diff --git a/.eslintrc.js b/.eslintrc.js index 7608bcb40a0b9..9cc7985b8bce2 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1316,7 +1316,7 @@ module.exports = { { files: [ - // platform-team owned code + // core-team owned code 'src/core/**', 'x-pack/plugins/features/**', 'x-pack/plugins/licensing/**', @@ -1325,6 +1325,14 @@ module.exports = { 'packages/kbn-config-schema', 'src/plugins/status_page/**', 'src/plugins/saved_objects_management/**', + 'packages/kbn-analytics/**', + 'packages/kbn-telemetry-tools/**', + 'src/plugins/kibana_usage_collection/**', + 'src/plugins/usage_collection/**', + 'src/plugins/telemetry/**', + 'src/plugins/telemetry_collection_manager/**', + 'src/plugins/telemetry_management_section/**', + 'x-pack/plugins/telemetry_collection_xpack/**', ], rules: { '@typescript-eslint/prefer-ts-expect-error': 'error', diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 307b449d50b61..30de890d6967a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -240,6 +240,7 @@ x-pack/plugins/telemetry_collection_xpack/schema/ @elastic/kibana-core @elastic/ # Security /src/core/server/csp/ @elastic/kibana-security @elastic/kibana-core /src/plugins/security_oss/ @elastic/kibana-security +/src/plugins/spaces_oss/ @elastic/kibana-security /test/security_functional/ @elastic/kibana-security /x-pack/plugins/spaces/ @elastic/kibana-security /x-pack/plugins/encrypted_saved_objects/ @elastic/kibana-security diff --git a/dev_docs/building_blocks.mdx b/dev_docs/building_blocks.mdx new file mode 100644 index 0000000000000..0cf9ab442b4bd --- /dev/null +++ b/dev_docs/building_blocks.mdx @@ -0,0 +1,138 @@ +--- +id: kibBuildingBlocks +slug: /kibana-dev-docs/building-blocks +title: Building blocks +summary: Consider these building blocks when developing your plugin. +date: 2021-02-24 +tags: ['kibana','onboarding', 'dev', 'architecture'] +--- + +When building a plugin in Kibana, there are a handful of architectural "building blocks" you can use. Some of these building blocks are "higher-level", +and some are "lower-level". High-level building blocks come +with many built-in capabilities, require less maintenance, and evolve new feature sets over time with little to no + impact on consumers. When developers use high-level building blocks, new features are exposed consistently, across all of Kibana, at the same time. + On the downside, they are not as flexible as our low-level building blocks. + + Low-level building blocks + provide greater flexibility, but require more code to stitch them together into a meaningful UX. This results in higher maintenance cost for consumers and greater UI/UX variability + across Kibana. + + For example, if an application is using and + , + their application would automatically support runtime fields. If the app is instead using the + lower-level , additional work would be required. + +Armed with this knowledge, you can choose what works best for your use case! + +# Application building blocks + +## UI components + +The following high-level building blocks can be rendered directly into your application UI. + +### Query Bar + +The provides a high-level Query Bar component that comes with support for Lucene, KQL, Saved Queries, +and . + +If you would like to expose the ability to search and filter on Elasticsearch data, the Query Bar provided by the + + is your go-to building block. + +**Github labels**: `Team:AppServices`, `Feature:QueryBar` + +### Dashboard Embeddable + +Add a Dashboard Embeddable directly inside your application to provide users with a set of visualizations and graphs that work seamlessly +with the . Every feature that is added to a registered + +(Lens, Maps, Saved Searches and more) will be available automatically, as well as any + that are + added to the Embeddable context menu panel (for example, drilldowns, custom panel time ranges, and "share to" features). + +The Dashboard Embeddable is one of the highest-level UI components you can add to your application. + +**Github labels**: `Team:Presentation`, `Feature:Dashboard` + +### Lens Embeddable + +Check out the Lens Embeddable if you wish to show users visualizations based on Elasticsearch data without worrying about query building and chart rendering. It's built on top of the + , and integrates with + + and . Using the same configuration, it's also possible to link to + a prefilled Lens editor, allowing the user to drill deeper and explore their data. + +**Github labels**: `Team:KibanaApp`, `Feature:Lens` + +### Map Embeddable + +Check out the Map Embeddable if you wish to embed a map in your application. + +**Github labels**: `Team:Geo` + +## Searching + +### Index Patterns + + are a high-level, space-aware abstraction layer that sits +above Data Streams and Elasticsearch indices. Index Patterns provide users the +ability to define and customize the data they wish to search and filter on, on a per-space basis. For example, users can specify a set of indices, +and they can customize the field list with runtime fields, formatting options and custom labels. + +Index Patterns are used in many other high-level building blocks so we highly recommend you consider this building block for your search needs. + +**Github labels**: `Team:AppServices`, `Feature:Index Patterns` + +### Search Source + + is a high-level search service offered by the +. It requires an +, and abstracts away the raw ES DSL and search endpoint. Internally +it uses the ES . Use Search Source if you need to query data +from Elasticsearch, and you aren't already using one of the high-level UI Components that handles this internally. + +**Github labels**: `Team:AppServices`, `Feature:Search` + +### Search Strategies + +Search Strategies are a low-level building block that abstracts away search details, like what REST endpoint is being called. The ES Search Strategy +is a very lightweight abstraction layer that sits just above querying ES with the elasticsearch-js client. Other search stragies are offered for other +languages, like EQL and SQL. These are very low-level building blocks so expect a lot of glue work to make these work with the higher-level abstractions. + +**Github labels**: `Team:AppServices`, `Feature:Search` + +### Expressions + +Expressions are a low-level building block that can be used if you have advanced search needs that requiring piping results into additional functionality, like +joining and manipulating data. Lens and Canvas are built on top of Expressions. Most developers should be able to use + or + , rather than need to access the Expression language directly. + +**Github labels**: `Team:AppServices`, `Feature:ExpressionLanguage` + +## Saved Objects + + should be used if you need to persist application-level information. If you were building a TODO +application, each TODO item would be a `Saved Object`. Saved objects come pre-wired with support for bulk export/import, security features like space sharing and +space isolation, and tags. + +**Github labels**: `Team:Core`, `Feature:Saved Objects` + +# Integration building blocks + +Use the following building blocks to create an inter-connected, cross-application, holistic Kibana experience. These building blocks allow you to expose functionality + that promotes your own application into other applications, as well as help developers of other applications integrate into your app. + +## UI Actions & Triggers + +Integrate custom actions into other applications by registering UI Actions attached to existing triggers. For example, the Maps +application could register a UI Action called "View in Maps" to appear any time the user clicked a geo field to filter on. + +**Github labels**: `Team:AppServices`, `Feature:UIActions` + +## Embeddables + +Embeddables help you integrate your application with the Dashboard application. Register your custom UI Widget as an Embeddable and users will +be able to add it as a panel on a Dashboard. With a little extra work, it can also be exposed in Canvas workpads. + +**Github labels**: `Team:AppServices`, `Feature:Embeddables` diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index 38b053ea12752..a2068b5b53b6d 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -224,7 +224,7 @@ which also contains the timelion APIs and backend, look at the vis_type_timelion |This plugins contains helpers to redirect legacy URLs. It can be used to forward old URLs to their new counterparts. -|{kib-repo}blob/{branch}/src/plugins/usage_collection/README.md[usageCollection] +|{kib-repo}blob/{branch}/src/plugins/usage_collection/README.mdx[usageCollection] |The Usage Collection Service defines a set of APIs for other plugins to report the usage of their features. At the same time, it provides necessary the APIs for other services (i.e.: telemetry, monitoring, ...) to consume that usage data. diff --git a/docs/settings/alert-action-settings.asciidoc b/docs/settings/alert-action-settings.asciidoc index d6f5fb1baba8e..6813a77776b5b 100644 --- a/docs/settings/alert-action-settings.asciidoc +++ b/docs/settings/alert-action-settings.asciidoc @@ -40,6 +40,8 @@ You can configure the following settings in the `kibana.yml` file. [cols="2*<"] |=== +| `xpack.actions.enabled` + | Feature toggle that enables Actions in {kib}. Defaults to `true`. | `xpack.actions.allowedHosts` {ess-icon} | A list of hostnames that {kib} is allowed to connect to when built-in actions are triggered. It defaults to `[*]`, allowing any host, but keep in mind the potential for SSRF attacks when hosts are not explicitly added to the allowed hosts. An empty list `[]` can be used to block built-in actions from making any external connections. + @@ -51,6 +53,24 @@ You can configure the following settings in the `kibana.yml` file. + Disabled action types will not appear as an option when creating new connectors, but existing connectors and actions of that type will remain in {kib} and will not function. +| `xpack.actions.preconfigured` + | Specifies preconfigured action IDs and configs. Defaults to {}. + +| `xpack.actions.proxyUrl` {ess-icon} + | Specifies the proxy URL to use, if using a proxy for actions. By default, no proxy is used. + +| `xpack.actions.proxyHeaders` {ess-icon} + | Specifies HTTP headers for the proxy, if using a proxy for actions. Defaults to {}. + +a|`xpack.actions.` +`proxyRejectUnauthorizedCertificates` {ess-icon} + | Set to `false` to bypass certificate validation for the proxy, if using a proxy for actions. Defaults to `true`. + +| `xpack.actions.rejectUnauthorized` {ess-icon} + | Set to `false` to bypass certificate validation for actions. Defaults to `true`. + + + + As an alternative to setting both `xpack.actions.proxyRejectUnauthorizedCertificates` and `xpack.actions.rejectUnauthorized`, you can point the OS level environment variable `NODE_EXTRA_CA_CERTS` to a file that contains the root CAs needed to trust certificates. + |=== [float] diff --git a/docs/user/alerting/action-types/jira.asciidoc b/docs/user/alerting/action-types/jira.asciidoc index 0740cf7838b15..d37f565c1739b 100644 --- a/docs/user/alerting/action-types/jira.asciidoc +++ b/docs/user/alerting/action-types/jira.asciidoc @@ -65,44 +65,13 @@ API token (or password):: Jira API authentication token (or password) for HTTP Jira actions have the following configuration properties: -Subaction:: The subaction to perform: `pushToService`, `getIncident`, `issueTypes`, `fieldsByIssueType`, `issues`, `issue`, or `getFields`. -Subaction params:: The parameters of the subaction. - -==== `pushToService` subaction configuration - -Incident:: A Jira incident has the following properties: -* `summary` - The title of the issue. -* `description` - A description of the issue. -* `externalId` - The ID of the issue in Jira. If present, the issue is updated. Otherwise, a new issue is created. -* `issueType` - The ID of the issue type in Jira. -* `priority` - The priority level in Jira. Example: `Medium`. -* `labels` - An array of labels. Labels cannot contain spaces. -* `parent` - The parent issue ID or key. Only for subtask issue types. -Comments:: A comment in the form of `{ commentId: string, version: string, comment: string }`. - -==== `getIncident` subaction configuration - -External ID:: The ID of the issue in Jira. - -==== `issueTypes` subaction configuration - -The `issueTypes` subaction has no parameters. Provide an empty object `{}`. - -==== `fieldsByIssueType` subaction configuration - -ID:: The ID of the issue in Jira. - -==== `issues` subaction configuration - -Title:: The title to search for. - -==== `issue` subaction configuration - -ID:: The ID of the issue in Jira. - -==== `getFields` subaction configuration - -The `getFields` subaction has no parameters. Provide an empty object `{}`. +Issue type:: The type of the issue. +Priority:: The priority of the incident. +Labels:: The labels for the incident. +Title:: A title for the issue, used for searching the contents of the knowledge base. +Description:: The details about the incident. +Parent:: The ID or key of the parent issue. Only for `Subtask` issue types. +Additional comments:: Additional information for the client, such as how to troubleshoot the issue. [[configuring-jira]] ==== Configuring and testing Jira diff --git a/docs/user/alerting/action-types/pre-configured-connectors.asciidoc b/docs/user/alerting/action-types/pre-configured-connectors.asciidoc index 722607ac05f87..a748a06398ef3 100644 --- a/docs/user/alerting/action-types/pre-configured-connectors.asciidoc +++ b/docs/user/alerting/action-types/pre-configured-connectors.asciidoc @@ -95,7 +95,7 @@ This example shows a preconfigured action type with one out-of-the box connector name: 'Server log #xyz' ``` -<1> `enabledActionTypes` excludes the preconfigured action type to prevent creating and deleting connectors. +<1> `enabledActionTypes` prevents the preconfigured action type from creating and deleting connectors. For more details, check <>. <2> `preconfigured` is the setting for defining the list of available connectors for the preconfigured action type. [[managing-pre-configured-action-types]] diff --git a/docs/user/alerting/action-types/resilient.asciidoc b/docs/user/alerting/action-types/resilient.asciidoc index dfa95e2deec00..feca42a542a2f 100644 --- a/docs/user/alerting/action-types/resilient.asciidoc +++ b/docs/user/alerting/action-types/resilient.asciidoc @@ -65,30 +65,11 @@ API key secret:: The authentication key secret for HTTP Basic authentication. IBM Resilient actions have the following configuration properties: -Subaction:: The subaction to perform: `pushToService`, `getFields`, `incidentTypes`, or `severity`. -Subaction params:: The parameters of the subaction. - -==== `pushToService` subaction configuration - -Incident:: The IBM resilient incident has the following properties: -* `name` - A name for the issue, used for searching the contents of the knowledge base. -* `description` - The details about the incident. -* `externalId` - The ID of the incident in IBM Resilient. If present, the incident is updated. Otherwise, a new incident is created. -* `incidentTypes` - An array with the IDs of IBM Resilient incident types. -* `severityCode` - The IBM Resilient ID of the severity code. -Comments:: A comment in the form of `{ commentId: string, version: string, comment: string }`. - -===== `getFields` subaction configuration - -The `getFields` subaction has not parameters. Provide an empty object `{}`. - -===== `incidentTypes` subaction configuration - -The `incidentTypes` subaction has no parameters. Provide an empty object `{}`. - -===== `severity` subaction configuration - -The `severity` subaction has no parameters. Provide an empty object `{}`. +Incident types:: The type of the incident. +Severity code:: The severity of the incident. +Name:: A name for the issue, used for searching the contents of the knowledge base. +Description:: The details about the incident. +Additional comments:: Additional information for the client, such as how to troubleshoot the issue. [[configuring-resilient]] ==== Configuring and testing IBM Resilient diff --git a/docs/user/alerting/action-types/servicenow.asciidoc b/docs/user/alerting/action-types/servicenow.asciidoc index d1ee1b9357737..4a11a2e28712a 100644 --- a/docs/user/alerting/action-types/servicenow.asciidoc +++ b/docs/user/alerting/action-types/servicenow.asciidoc @@ -60,33 +60,12 @@ Password:: Password for HTTP Basic authentication. ServiceNow actions have the following configuration properties: -Subaction:: The subaction to perform: `pushToService`, `getFields`, `getIncident`, or `getChoices`. -Subaction params:: The parameters of the subaction. - -==== `pushToService` subaction configuration - -Incident:: The ServiceNow incident has the following properties: -* `short_description` - A short description for the incident, used for searching the contents of the knowledge base. -* `description` - The details about the incident. -* `externalId` - The ID of the incident in ServiceNow. If present, the incident is updated. Otherwise, a new incident is created. -* `severity` - The severity of the incident. -* `urgency` - The extent to which the incident resolution can delay. -* `impact` - The effect an incident has on business. Can be measured by the number of affected users or by how critical it is to the business in question. -* `category` - The name of the category in ServiceNow. -* `subcategory` - The name of the subcategory in ServiceNow. -Comments:: A comment in the form of `{ commentId: string, version: string, comment: string }`. - -===== `getFields` subaction configuration - -The `getFields` subaction has no parameters. Provide an empty object `{}`. - -===== `getIncident` subaction configuration - -External ID:: The ID of the incident in ServiceNow. - -===== `getChoices` subaction configuration - -Fields:: An array of fields. Example: `[priority, category, impact]`. +Urgency:: The extent to which the incident resolution can delay. +Severity:: The severity of the incident. +Impact:: The effect an incident has on business. Can be measured by the number of affected users or by how critical it is to the business in question. +Short description:: A short description for the incident, used for searching the contents of the knowledge base. +Description:: The details about the incident. +Additional comments:: Additional information for the client, such as how to troubleshoot the issue. [[configuring-servicenow]] ==== Configuring and testing ServiceNow diff --git a/docs/user/alerting/alert-types.asciidoc b/docs/user/alerting/alert-types.asciidoc index 5983804c5c862..5afce8fa6cd93 100644 --- a/docs/user/alerting/alert-types.asciidoc +++ b/docs/user/alerting/alert-types.asciidoc @@ -28,7 +28,7 @@ For domain-specific alerts, refer to the documentation for that app. * {observability-guide}/create-alerts.html[Observability alerts] * {security-guide}/prebuilt-rules.html[Security alerts] * <> -* <> +* {ml-docs}/ml-configuring-alerts.html[{ml-cap} alerts] [NOTE] ============================================== diff --git a/docs/user/alerting/alerting-getting-started.asciidoc b/docs/user/alerting/alerting-getting-started.asciidoc index 0a7c17576de3d..6c6e7e6305c81 100644 --- a/docs/user/alerting/alerting-getting-started.asciidoc +++ b/docs/user/alerting/alerting-getting-started.asciidoc @@ -5,7 +5,7 @@ -- -Alerting allows you to detect complex conditions within different {kib} apps and trigger actions when those conditions are met. Alerting is integrated with {observability-guide}/create-alerts.html[*Observability*], {security-guide}/prebuilt-rules.html[*Security*], <> and <>, can be centrally managed from the <> UI, and provides a set of built-in <> and <> (known as stack alerts) for you to use. +Alerting allows you to detect complex conditions within different {kib} apps and trigger actions when those conditions are met. Alerting is integrated with {observability-guide}/create-alerts.html[*Observability*], {security-guide}/prebuilt-rules.html[*Security*], <> and {ml-docs}/ml-configuring-alerts.html[*{ml-app}*], can be centrally managed from the <> UI, and provides a set of built-in <> and <> (known as stack alerts) for you to use. image::images/alerting-overview.png[Alerts and actions UI] @@ -157,7 +157,7 @@ Pre-packaged *alert types* simplify setup, hide the details complex domain-speci If you are using an *on-premises* Elastic Stack deployment: -* In the kibana.yml configuration file, add the <> setting. +* In the kibana.yml configuration file, add the <> setting. * For emails to have a footer with a link back to {kib}, set the <> configuration setting. If you are using an *on-premises* Elastic Stack deployment with <>: diff --git a/docs/user/alerting/alerting-production-considerations.asciidoc b/docs/user/alerting/alerting-production-considerations.asciidoc index 0442b760669cc..58b4a263459b3 100644 --- a/docs/user/alerting/alerting-production-considerations.asciidoc +++ b/docs/user/alerting/alerting-production-considerations.asciidoc @@ -2,9 +2,9 @@ [[alerting-production-considerations]] == Production considerations -{kib} alerting run both alert checks and actions as persistent background tasks managed by the Kibana Task Manager. This has two major benefits: +{kib} alerting runs both alert checks and actions as persistent background tasks managed by the Kibana Task Manager. This has two major benefits: -* *Persistence*: all task state and scheduling is stored in {es}, so if {kib} is restarted, alerts and actions will pick up where they left off. Task definitions for alerts and actions are stored in the index specified by `xpack.task_manager.index` (defaults to `.kibana_task_manager`). It is important to have at least 1 replica of this index for production deployments, since if you lose this index all scheduled alerts and actions are also lost. +* *Persistence*: all task state and scheduling is stored in {es}, so if you restart {kib}, alerts and actions will pick up where they left off. Task definitions for alerts and actions are stored in the index specified by <>. The default is `.kibana_task_manager`. You must have at least one replica of this index for production deployments. If you lose this index, all scheduled alerts and actions are lost. * *Scaling*: multiple {kib} instances can read from and update the same task queue in {es}, allowing the alerting and action load to be distributed across instances. In cases where a {kib} instance no longer has capacity to run alert checks or actions, capacity can be increased by adding additional {kib} instances. [float] @@ -12,7 +12,7 @@ {kib} background tasks are managed by: -* Polling an {es} task index for overdue tasks at 3 second intervals. This interval can be changed using the `xpack.task_manager.poll_interval` setting. +* Polling an {es} task index for overdue tasks at 3 second intervals. You can change this interval using the <> setting. * Tasks are then claiming them by updating them in the {es} index, using optimistic concurrency control to prevent conflicts. Each {kib} instance can run a maximum of 10 concurrent tasks, so a maximum of 10 tasks are claimed each interval. * Tasks are run on the {kib} server. * In the case of alerts which are recurring background checks, upon completion the task is scheduled again according to the <>. @@ -32,4 +32,4 @@ For details on the settings that can influence the performance and throughput of [float] === Deployment considerations -{es} and {kib} instances use the system clock to determine the current time. To ensure schedules are triggered when expected, you should synchronize the clocks of all nodes in the cluster using a time service such as http://www.ntp.org/[Network Time Protocol]. \ No newline at end of file +{es} and {kib} instances use the system clock to determine the current time. To ensure schedules are triggered when expected, you should synchronize the clocks of all nodes in the cluster using a time service such as http://www.ntp.org/[Network Time Protocol]. diff --git a/docs/user/alerting/defining-alerts.asciidoc b/docs/user/alerting/defining-alerts.asciidoc index 77a4e5cc41ef2..8c8e25cea407a 100644 --- a/docs/user/alerting/defining-alerts.asciidoc +++ b/docs/user/alerting/defining-alerts.asciidoc @@ -2,7 +2,7 @@ [[defining-alerts]] == Defining alerts -{kib} alerts can be created in a variety of apps including <>, <>, <>, <> and from <> UI. While alerting details may differ from app to app, they share a common interface for defining and configuring alerts that this section describes in more detail. +{kib} alerts can be created in a variety of apps including <>, <>, <>, <>, <> and from <> UI. While alerting details may differ from app to app, they share a common interface for defining and configuring alerts that this section describes in more detail. [float] === Alert flyout @@ -101,29 +101,9 @@ image::images/alert-flyout-add-action.png[You can add multiple actions on an ale [NOTE] ============================================== -Actions are not required on alerts. In some cases you may want to run an alert without actions first to understand its behavior, and configure actions later. +Actions are not required on alerts. You can run an alert without actions to understand its behavior, and then <> later. ============================================== -[float] -[[actions-configuration]] -=== Global actions configuration -Some actions configuration options apply to all actions. -If you are using an *on-prem* Elastic Stack deployment, you can set these in the kibana.yml file. -If you are using a cloud deployment, you can set these via the console. - -Here's a list of the available global configuration options and an explanation of what each one does: - -* `xpack.actions.enabled`: Feature toggle that enables Actions in {kib}. Default: `true` -* `xpack.actions.allowedHosts`: Specifies an array of host names which actions such as email, Slack, PagerDuty, and webhook can connect to. An element of * indicates any host can be connected to. An empty array indicates no hosts can be connected to. Default: [ {asterisk} ] -* `xpack.actions.enabledActionTypes`: Specifies an array of action types that are enabled. An {asterisk} indicates all action types registered are enabled. The action types that {kib} provides are `.email`, `.index`, `.jira`, `.pagerduty`, `.resilient`, `.server-log`, `.servicenow`, `.servicenow-sir`, `.slack`, `.teams`, and `.webhook`. Default: [ {asterisk} ] -* `xpack.actions.preconfigured`: Specifies preconfigured action IDs and configs. Default: {} -* `xpack.actions.proxyUrl`: Specifies the proxy URL to use, if using a proxy for actions. -* `xpack.actions.proxyHeader`: Specifies HTTP headers for proxy, if using a proxy for actions. -* `xpack.actions.proxyRejectUnauthorizedCertificates`: Set to `false` to bypass certificate validation for proxy, if using a proxy for actions. -* `xpack.actions.rejectUnauthorized`: Set to `false` to bypass certificate validation for actions. - -*NOTE:* As an alternative to both `xpack.actions.proxyRejectUnauthorizedCertificates` and `xpack.actions.rejectUnauthorized`, the OS level environment variable `NODE_EXTRA_CA_CERTS` can be set to point to a file that contains the root CA(s) needed for certificates to be trusted. - [float] === Managing alerts diff --git a/src/core/CONVENTIONS.md b/src/core/CONVENTIONS.md index 56da185d023a9..6a519d44de0d9 100644 --- a/src/core/CONVENTIONS.md +++ b/src/core/CONVENTIONS.md @@ -285,7 +285,7 @@ export class Plugin { #### Usage Collection -For creating and registering a Usage Collector. Collectors should be defined in a separate directory `server/collectors/`. You can read more about usage collectors on `src/plugins/usage_collection/README.md`. +For creating and registering a Usage Collector. Collectors should be defined in a separate directory `server/collectors/`. You can read more about usage collectors on `src/plugins/usage_collection/README.mdx`. ```ts // server/collectors/register.ts diff --git a/src/core/public/core_app/status/lib/load_status.ts b/src/core/public/core_app/status/lib/load_status.ts index d8d2bd3fec517..3c31da4c5397f 100644 --- a/src/core/public/core_app/status/lib/load_status.ts +++ b/src/core/public/core_app/status/lib/load_status.ts @@ -57,7 +57,7 @@ function formatMetrics({ metrics }: StatusResponse): Metric[] { defaultMessage: 'Load', }), value: [metrics.os.load['1m'], metrics.os.load['5m'], metrics.os.load['15m']], - type: 'time', + type: 'float', }, { name: i18n.translate('core.statusPage.metricsTiles.columns.resTimeAvgHeader', { diff --git a/src/core/server/saved_objects/service/lib/repository.ts b/src/core/server/saved_objects/service/lib/repository.ts index 78c3cdcb91e02..7a54cdb8488d8 100644 --- a/src/core/server/saved_objects/service/lib/repository.ts +++ b/src/core/server/saved_objects/service/lib/repository.ts @@ -1640,7 +1640,7 @@ export class SavedObjectsRepository { * * When using incrementCounter for collecting usage data, you need to ensure * that usage collection happens on a best-effort basis and doesn't - * negatively affect your plugin or users. See https://github.com/elastic/kibana/blob/master/src/plugins/usage_collection/README.md#tracking-interactions-with-incrementcounter) + * negatively affect your plugin or users. See https://github.com/elastic/kibana/blob/master/src/plugins/usage_collection/README.mdx#tracking-interactions-with-incrementcounter) * * @example * ```ts diff --git a/src/dev/bazel_workspace_status.js b/src/dev/bazel_workspace_status.js index fe60f9176d243..3c3ef1574cd8e 100644 --- a/src/dev/bazel_workspace_status.js +++ b/src/dev/bazel_workspace_status.js @@ -43,25 +43,23 @@ // Commit SHA const commitSHACmdResult = await runCmd('git', ['rev-parse', 'HEAD']); - if (commitSHACmdResult.exitCode !== 0) { - process.exit(1); - } - console.log(`COMMIT_SHA ${commitSHACmdResult.stdout}`); + if (commitSHACmdResult.exitCode === 0) { + console.log(`COMMIT_SHA ${commitSHACmdResult.stdout}`); - // Git branch - const gitBranchCmdResult = await runCmd('git', ['rev-parse', '--abbrev-ref', 'HEAD']); - if (gitBranchCmdResult.exitCode !== 0) { - process.exit(1); - } - console.log(`GIT_BRANCH ${gitBranchCmdResult.stdout}`); + // Branch + const gitBranchCmdResult = await runCmd('git', ['rev-parse', '--abbrev-ref', 'HEAD']); + if (gitBranchCmdResult.exitCode === 0) { + console.log(`GIT_BRANCH ${gitBranchCmdResult.stdout}`); + } - // Tree status - const treeStatusCmdResult = await runCmd('git', ['diff-index', '--quiet', 'HEAD', '--']); - const treeStatusVarStr = 'GIT_TREE_STATUS'; - if (treeStatusCmdResult.exitCode === 0) { - console.log(`${treeStatusVarStr} Clean`); - } else { - console.log(`${treeStatusVarStr} Modified`); + // Tree status + const treeStatusCmdResult = await runCmd('git', ['diff-index', '--quiet', 'HEAD', '--']); + const treeStatusVarStr = 'GIT_TREE_STATUS'; + if (treeStatusCmdResult.exitCode === 0) { + console.log(`${treeStatusVarStr} Clean`); + } else { + console.log(`${treeStatusVarStr} Modified`); + } } // Host @@ -72,9 +70,8 @@ return !cpu.model.includes('Intel') || index % 2 === 1; }).length; - if (hostCmdResult.exitCode !== 0) { - process.exit(1); + if (hostCmdResult.exitCode === 0) { + console.log(`HOST ${hostStr}-${coresStr}`); } - console.log(`HOST ${hostStr}-${coresStr}`); } })(); diff --git a/src/plugins/discover/public/application/components/create_discover_grid_directive.tsx b/src/plugins/discover/public/application/components/create_discover_grid_directive.tsx index a6c36c199f852..0d17fcbba9c23 100644 --- a/src/plugins/discover/public/application/components/create_discover_grid_directive.tsx +++ b/src/plugins/discover/public/application/components/create_discover_grid_directive.tsx @@ -6,19 +6,27 @@ * Side Public License, v 1. */ -import * as React from 'react'; +import React, { useState } from 'react'; import { I18nProvider } from '@kbn/i18n/react'; import { DiscoverGrid, DiscoverGridProps } from './discover_grid/discover_grid'; import { getServices } from '../../kibana_services'; +import { ElasticSearchHit } from '../doc_views/doc_views_types'; export const DataGridMemoized = React.memo((props: DiscoverGridProps) => ( )); export function DiscoverGridEmbeddable(props: DiscoverGridProps) { + const [expandedDoc, setExpandedDoc] = useState(undefined); + return ( - + ); } diff --git a/src/plugins/discover/public/application/components/top_nav/open_search_panel.tsx b/src/plugins/discover/public/application/components/top_nav/open_search_panel.tsx index 8c5f44b97f4b3..f6881d1856566 100644 --- a/src/plugins/discover/public/application/components/top_nav/open_search_panel.tsx +++ b/src/plugins/discover/public/application/components/top_nav/open_search_panel.tsx @@ -59,7 +59,7 @@ export function OpenSearchPanel(props: OpenSearchPanelProps) { savedObjectMetaData={[ { type: SEARCH_OBJECT_TYPE, - getIconForSavedObject: () => 'search', + getIconForSavedObject: () => 'discoverApp', name: i18n.translate('discover.savedSearch.savedObjectName', { defaultMessage: 'Saved search', }), diff --git a/src/plugins/discover/public/application/embeddable/search_embeddable_factory.ts b/src/plugins/discover/public/application/embeddable/search_embeddable_factory.ts index 043869f99bb35..77da138d118dd 100644 --- a/src/plugins/discover/public/application/embeddable/search_embeddable_factory.ts +++ b/src/plugins/discover/public/application/embeddable/search_embeddable_factory.ts @@ -36,7 +36,7 @@ export class SearchEmbeddableFactory defaultMessage: 'Saved search', }), type: 'search', - getIconForSavedObject: () => 'search', + getIconForSavedObject: () => 'discoverApp', }; constructor( diff --git a/src/plugins/es_ui_shared/__packages_do_not_import__/errors/es_error_parser.ts b/src/plugins/es_ui_shared/__packages_do_not_import__/errors/es_error_parser.ts index 61a8882317f9f..fc400e4a87b3a 100644 --- a/src/plugins/es_ui_shared/__packages_do_not_import__/errors/es_error_parser.ts +++ b/src/plugins/es_ui_shared/__packages_do_not_import__/errors/es_error_parser.ts @@ -11,14 +11,14 @@ interface ParsedError { cause: string[]; } -const getCause = (obj: any = {}, causes: string[] = []): string[] => { +export const getEsCause = (obj: any = {}, causes: string[] = []): string[] => { const updated = [...causes]; if (obj.caused_by) { updated.push(obj.caused_by.reason); // Recursively find all the "caused by" reasons - return getCause(obj.caused_by, updated); + return getEsCause(obj.caused_by, updated); } return updated.filter(Boolean); @@ -27,7 +27,7 @@ const getCause = (obj: any = {}, causes: string[] = []): string[] => { export const parseEsError = (err: string): ParsedError => { try { const { error } = JSON.parse(err); - const cause = getCause(error); + const cause = getEsCause(error); return { message: error.reason, cause, diff --git a/src/plugins/es_ui_shared/__packages_do_not_import__/errors/handle_es_error.ts b/src/plugins/es_ui_shared/__packages_do_not_import__/errors/handle_es_error.ts index 4a45cff0b9604..a98a74375638d 100644 --- a/src/plugins/es_ui_shared/__packages_do_not_import__/errors/handle_es_error.ts +++ b/src/plugins/es_ui_shared/__packages_do_not_import__/errors/handle_es_error.ts @@ -9,6 +9,7 @@ import { ApiError } from '@elastic/elasticsearch'; import { ResponseError } from '@elastic/elasticsearch/lib/errors'; import { IKibanaResponse, KibanaResponseFactory } from 'kibana/server'; +import { getEsCause } from './es_error_parser'; interface EsErrorHandlerParams { error: ApiError; @@ -34,7 +35,15 @@ export const handleEsError = ({ const { statusCode, body } = error as ResponseError; return response.customError({ statusCode, - body: { message: body.error?.reason }, + body: { + message: body.error?.reason, + attributes: { + // The full original ES error object + error: body.error, + // We assume that this is an ES error object with a nested caused by chain if we can see the "caused_by" field at the top-level + causes: body.error?.caused_by ? getEsCause(body.error) : undefined, + }, + }, }); } // Case: default diff --git a/src/plugins/kibana_usage_collection/server/collectors/kibana/get_saved_object_counts.test.ts b/src/plugins/kibana_usage_collection/server/collectors/kibana/get_saved_object_counts.test.ts index dcc3af949878e..15cbecde386f7 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/kibana/get_saved_object_counts.test.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/kibana/get_saved_object_counts.test.ts @@ -12,7 +12,7 @@ import { getSavedObjectsCounts } from './get_saved_object_counts'; export function mockGetSavedObjectsCounts(params: any) { const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; esClient.search.mockResolvedValue( - // @ts-ignore we only care about the response body + // @ts-expect-error we only care about the response body { body: { ...params }, } diff --git a/src/plugins/security_oss/.eslintrc.json b/src/plugins/security_oss/.eslintrc.json new file mode 100644 index 0000000000000..2b63a9259d220 --- /dev/null +++ b/src/plugins/security_oss/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "rules": { + "@typescript-eslint/consistent-type-imports": 1 + } +} diff --git a/src/plugins/security_oss/public/app_state/app_state_service.test.ts b/src/plugins/security_oss/public/app_state/app_state_service.test.ts index 7f2af2e895836..ec491e0faac2f 100644 --- a/src/plugins/security_oss/public/app_state/app_state_service.test.ts +++ b/src/plugins/security_oss/public/app_state/app_state_service.test.ts @@ -6,7 +6,8 @@ * Side Public License, v 1. */ -import { coreMock } from '../../../../core/public/mocks'; +import { coreMock } from 'src/core/public/mocks'; + import { AppStateService } from './app_state_service'; describe('AppStateService', () => { diff --git a/src/plugins/security_oss/public/app_state/app_state_service.ts b/src/plugins/security_oss/public/app_state/app_state_service.ts index 1fe9984c7d1da..8f6e9c0f08e77 100644 --- a/src/plugins/security_oss/public/app_state/app_state_service.ts +++ b/src/plugins/security_oss/public/app_state/app_state_service.ts @@ -6,8 +6,9 @@ * Side Public License, v 1. */ -import { CoreStart } from 'kibana/public'; -import { AppState } from '../../common'; +import type { CoreStart } from 'src/core/public'; + +import type { AppState } from '../../common'; const DEFAULT_APP_STATE = Object.freeze({ insecureClusterAlert: { displayAlert: false }, diff --git a/src/plugins/security_oss/public/index.ts b/src/plugins/security_oss/public/index.ts index bddf107758fde..0f67c6ed5442b 100644 --- a/src/plugins/security_oss/public/index.ts +++ b/src/plugins/security_oss/public/index.ts @@ -6,10 +6,11 @@ * Side Public License, v 1. */ -import { PluginInitializerContext } from 'kibana/public'; +import type { PluginInitializerContext } from 'src/core/public'; import { SecurityOssPlugin } from './plugin'; export { SecurityOssPluginSetup, SecurityOssPluginStart } from './plugin'; + export const plugin = (initializerContext: PluginInitializerContext) => new SecurityOssPlugin(initializerContext); diff --git a/src/plugins/security_oss/public/insecure_cluster_service/components/default_alert.tsx b/src/plugins/security_oss/public/insecure_cluster_service/components/default_alert.tsx index 5431d95b78296..288d49457a64f 100644 --- a/src/plugins/security_oss/public/insecure_cluster_service/components/default_alert.tsx +++ b/src/plugins/security_oss/public/insecure_cluster_service/components/default_alert.tsx @@ -14,12 +14,13 @@ import { EuiSpacer, EuiText, } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { I18nProvider, FormattedMessage } from '@kbn/i18n/react'; -import { MountPoint } from 'kibana/public'; import React, { useState } from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage, I18nProvider } from '@kbn/i18n/react'; +import type { MountPoint } from 'src/core/public'; + export const defaultAlertTitle = i18n.translate('security.checkup.insecureClusterTitle', { defaultMessage: 'Your data is not secure', }); diff --git a/src/plugins/security_oss/public/insecure_cluster_service/insecure_cluster_service.mock.tsx b/src/plugins/security_oss/public/insecure_cluster_service/insecure_cluster_service.mock.tsx index c0f81ba276989..accf597aafa0b 100644 --- a/src/plugins/security_oss/public/insecure_cluster_service/insecure_cluster_service.mock.tsx +++ b/src/plugins/security_oss/public/insecure_cluster_service/insecure_cluster_service.mock.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { +import type { InsecureClusterServiceSetup, InsecureClusterServiceStart, } from './insecure_cluster_service'; diff --git a/src/plugins/security_oss/public/insecure_cluster_service/insecure_cluster_service.test.tsx b/src/plugins/security_oss/public/insecure_cluster_service/insecure_cluster_service.test.tsx index ef6ae18613f15..45240527d91ef 100644 --- a/src/plugins/security_oss/public/insecure_cluster_service/insecure_cluster_service.test.tsx +++ b/src/plugins/security_oss/public/insecure_cluster_service/insecure_cluster_service.test.tsx @@ -7,7 +7,9 @@ */ import { nextTick } from '@kbn/test/jest'; -import { coreMock } from '../../../../core/public/mocks'; + +import { coreMock } from 'src/core/public/mocks'; + import { mockAppStateService } from '../app_state/app_state_service.mock'; import type { ConfigType } from '../config'; import { InsecureClusterService } from './insecure_cluster_service'; diff --git a/src/plugins/security_oss/public/insecure_cluster_service/insecure_cluster_service.tsx b/src/plugins/security_oss/public/insecure_cluster_service/insecure_cluster_service.tsx index e8caa41391f27..6ad84b80eaf70 100644 --- a/src/plugins/security_oss/public/insecure_cluster_service/insecure_cluster_service.tsx +++ b/src/plugins/security_oss/public/insecure_cluster_service/insecure_cluster_service.tsx @@ -6,10 +6,11 @@ * Side Public License, v 1. */ -import { CoreSetup, CoreStart, MountPoint, Toast } from 'kibana/public'; - import { BehaviorSubject, combineLatest, from } from 'rxjs'; import { distinctUntilChanged, map } from 'rxjs/operators'; + +import type { CoreSetup, CoreStart, MountPoint, Toast } from 'src/core/public'; + import type { ConfigType } from '../config'; import type { AppStateServiceStart } from '../app_state'; import { defaultAlertText, defaultAlertTitle } from './components'; diff --git a/src/plugins/security_oss/public/plugin.mock.ts b/src/plugins/security_oss/public/plugin.mock.ts index f8b855803443d..324e0cdfd8524 100644 --- a/src/plugins/security_oss/public/plugin.mock.ts +++ b/src/plugins/security_oss/public/plugin.mock.ts @@ -7,9 +7,10 @@ */ import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; -import { InsecureClusterServiceStart } from './insecure_cluster_service'; + +import type { InsecureClusterServiceStart } from './insecure_cluster_service'; import { mockInsecureClusterService } from './insecure_cluster_service/insecure_cluster_service.mock'; -import { SecurityOssPluginSetup, SecurityOssPluginStart } from './plugin'; +import type { SecurityOssPluginSetup, SecurityOssPluginStart } from './plugin'; export const mockSecurityOssPlugin = { createSetup: () => { diff --git a/src/plugins/security_oss/public/plugin.ts b/src/plugins/security_oss/public/plugin.ts index 7b99e22de70f0..0104950f22366 100644 --- a/src/plugins/security_oss/public/plugin.ts +++ b/src/plugins/security_oss/public/plugin.ts @@ -13,13 +13,14 @@ import type { Plugin, PluginInitializerContext, } from 'src/core/public'; + +import { AppStateService } from './app_state'; import type { ConfigType } from './config'; -import { - InsecureClusterService, +import type { InsecureClusterServiceSetup, InsecureClusterServiceStart, } from './insecure_cluster_service'; -import { AppStateService } from './app_state'; +import { InsecureClusterService } from './insecure_cluster_service'; export interface SecurityOssPluginSetup { insecureCluster: InsecureClusterServiceSetup; diff --git a/src/plugins/security_oss/server/check_cluster_data.test.ts b/src/plugins/security_oss/server/check_cluster_data.test.ts index 21232d60ab293..0670eb3116b07 100644 --- a/src/plugins/security_oss/server/check_cluster_data.test.ts +++ b/src/plugins/security_oss/server/check_cluster_data.test.ts @@ -6,7 +6,8 @@ * Side Public License, v 1. */ -import { elasticsearchServiceMock, loggingSystemMock } from '../../../core/server/mocks'; +import { elasticsearchServiceMock, loggingSystemMock } from 'src/core/server/mocks'; + import { createClusterDataCheck } from './check_cluster_data'; describe('checkClusterForUserData', () => { diff --git a/src/plugins/security_oss/server/check_cluster_data.ts b/src/plugins/security_oss/server/check_cluster_data.ts index 99bedb84c8c38..c8c30196b485c 100644 --- a/src/plugins/security_oss/server/check_cluster_data.ts +++ b/src/plugins/security_oss/server/check_cluster_data.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { ElasticsearchClient, Logger } from 'kibana/server'; +import type { ElasticsearchClient, Logger } from 'src/core/server'; export const createClusterDataCheck = () => { let clusterHasUserData = false; diff --git a/src/plugins/security_oss/server/config.ts b/src/plugins/security_oss/server/config.ts index 0d650859c18f8..4be4bf96c2d82 100644 --- a/src/plugins/security_oss/server/config.ts +++ b/src/plugins/security_oss/server/config.ts @@ -6,7 +6,8 @@ * Side Public License, v 1. */ -import { schema, TypeOf } from '@kbn/config-schema'; +import type { TypeOf } from '@kbn/config-schema'; +import { schema } from '@kbn/config-schema'; export type ConfigType = TypeOf; diff --git a/src/plugins/security_oss/server/index.ts b/src/plugins/security_oss/server/index.ts index e69b2554aa6e4..42736302b5d26 100644 --- a/src/plugins/security_oss/server/index.ts +++ b/src/plugins/security_oss/server/index.ts @@ -6,9 +6,9 @@ * Side Public License, v 1. */ -import { TypeOf } from '@kbn/config-schema'; +import type { TypeOf } from '@kbn/config-schema'; +import type { PluginConfigDescriptor, PluginInitializerContext } from 'src/core/server'; -import { PluginConfigDescriptor, PluginInitializerContext } from 'kibana/server'; import { ConfigSchema } from './config'; import { SecurityOssPlugin } from './plugin'; diff --git a/src/plugins/security_oss/server/plugin.test.ts b/src/plugins/security_oss/server/plugin.test.ts index 7aaf259f3edfa..5858fabd6a706 100644 --- a/src/plugins/security_oss/server/plugin.test.ts +++ b/src/plugins/security_oss/server/plugin.test.ts @@ -6,7 +6,8 @@ * Side Public License, v 1. */ -import { coreMock } from '../../../core/server/mocks'; +import { coreMock } from 'src/core/server/mocks'; + import { SecurityOssPlugin } from './plugin'; describe('SecurityOss Plugin', () => { diff --git a/src/plugins/security_oss/server/plugin.ts b/src/plugins/security_oss/server/plugin.ts index 4fc157ef44339..6adea272ed490 100644 --- a/src/plugins/security_oss/server/plugin.ts +++ b/src/plugins/security_oss/server/plugin.ts @@ -6,6 +6,9 @@ * Side Public License, v 1. */ +import type { Observable } from 'rxjs'; +import { BehaviorSubject } from 'rxjs'; + import type { Capabilities, CoreSetup, @@ -13,11 +16,11 @@ import type { Logger, Plugin, PluginInitializerContext, -} from 'kibana/server'; -import { BehaviorSubject, Observable } from 'rxjs'; +} from 'src/core/server'; + import { createClusterDataCheck } from './check_cluster_data'; -import { ConfigType } from './config'; -import { setupAppStateRoute, setupAnonymousAccessCapabilitiesRoute } from './routes'; +import type { ConfigType } from './config'; +import { setupAnonymousAccessCapabilitiesRoute, setupAppStateRoute } from './routes'; export interface SecurityOssPluginSetup { /** diff --git a/src/plugins/security_oss/server/routes/anonymous_access_capabilities.ts b/src/plugins/security_oss/server/routes/anonymous_access_capabilities.ts index c9c4cd4ad903c..80273b41063ad 100644 --- a/src/plugins/security_oss/server/routes/anonymous_access_capabilities.ts +++ b/src/plugins/security_oss/server/routes/anonymous_access_capabilities.ts @@ -6,7 +6,8 @@ * Side Public License, v 1. */ -import type { IRouter } from 'kibana/server'; +import type { IRouter } from 'src/core/server'; + import type { AnonymousAccessService } from '../plugin'; interface Deps { diff --git a/src/plugins/security_oss/server/routes/app_state.ts b/src/plugins/security_oss/server/routes/app_state.ts index 7d6890cc46344..6ecac362559d1 100644 --- a/src/plugins/security_oss/server/routes/app_state.ts +++ b/src/plugins/security_oss/server/routes/app_state.ts @@ -6,10 +6,13 @@ * Side Public License, v 1. */ -import type { IRouter, Logger } from 'kibana/server'; -import { combineLatest, Observable } from 'rxjs'; +import type { Observable } from 'rxjs'; +import { combineLatest } from 'rxjs'; + +import type { IRouter, Logger } from 'src/core/server'; + import type { AppState } from '../../common'; -import { createClusterDataCheck } from '../check_cluster_data'; +import type { createClusterDataCheck } from '../check_cluster_data'; import type { ConfigType } from '../config'; import type { AnonymousAccessService } from '../plugin'; diff --git a/src/plugins/security_oss/server/routes/integration_tests/anonymous_access_capabilities.test.ts b/src/plugins/security_oss/server/routes/integration_tests/anonymous_access_capabilities.test.ts index ee0ef8eaa830a..0dba0433a3625 100644 --- a/src/plugins/security_oss/server/routes/integration_tests/anonymous_access_capabilities.test.ts +++ b/src/plugins/security_oss/server/routes/integration_tests/anonymous_access_capabilities.test.ts @@ -6,10 +6,12 @@ * Side Public License, v 1. */ -import type { UnwrapPromise } from '@kbn/utility-types'; import supertest from 'supertest'; -import { setupServer } from '../../../../../core/server/test_utils'; -import { AnonymousAccessService } from '../../plugin'; + +import type { UnwrapPromise } from '@kbn/utility-types'; +import { setupServer } from 'src/core/server/test_utils'; + +import type { AnonymousAccessService } from '../../plugin'; import { setupAnonymousAccessCapabilitiesRoute } from '../anonymous_access_capabilities'; type SetupServerReturn = UnwrapPromise>; diff --git a/src/plugins/security_oss/server/routes/integration_tests/app_state.test.ts b/src/plugins/security_oss/server/routes/integration_tests/app_state.test.ts index cec0b94cffa5f..82e7098760e18 100644 --- a/src/plugins/security_oss/server/routes/integration_tests/app_state.test.ts +++ b/src/plugins/security_oss/server/routes/integration_tests/app_state.test.ts @@ -6,16 +6,18 @@ * Side Public License, v 1. */ -import { loggingSystemMock } from '../../../../../core/server/mocks'; -import { setupServer } from '../../../../../core/server/test_utils'; -import { AnonymousAccessService } from '../../plugin'; -import { setupAppStateRoute } from '../app_state'; -import { ConfigType } from '../../config'; import { BehaviorSubject, of } from 'rxjs'; -import { UnwrapPromise } from '@kbn/utility-types'; -import { createClusterDataCheck } from '../../check_cluster_data'; import supertest from 'supertest'; +import type { UnwrapPromise } from '@kbn/utility-types'; +import { loggingSystemMock } from 'src/core/server/mocks'; +import { setupServer } from 'src/core/server/test_utils'; + +import type { createClusterDataCheck } from '../../check_cluster_data'; +import type { ConfigType } from '../../config'; +import type { AnonymousAccessService } from '../../plugin'; +import { setupAppStateRoute } from '../app_state'; + type SetupServerReturn = UnwrapPromise>; const pluginId = Symbol('securityOss'); diff --git a/src/plugins/spaces_oss/.eslintrc.json b/src/plugins/spaces_oss/.eslintrc.json new file mode 100644 index 0000000000000..2b63a9259d220 --- /dev/null +++ b/src/plugins/spaces_oss/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "rules": { + "@typescript-eslint/consistent-type-imports": 1 + } +} diff --git a/src/plugins/spaces_oss/public/api.mock.ts b/src/plugins/spaces_oss/public/api.mock.ts index 1f0899ca1df60..84b22459a96e2 100644 --- a/src/plugins/spaces_oss/public/api.mock.ts +++ b/src/plugins/spaces_oss/public/api.mock.ts @@ -7,7 +7,8 @@ */ import { of } from 'rxjs'; -import { SpacesApi, SpacesApiUi, SpacesApiUiComponent } from './api'; + +import type { SpacesApi, SpacesApiUi, SpacesApiUiComponent } from './api'; const createApiMock = (): jest.Mocked => ({ activeSpace$: of(), diff --git a/src/plugins/spaces_oss/public/api.ts b/src/plugins/spaces_oss/public/api.ts index 3c10995b75003..1d33408d645ea 100644 --- a/src/plugins/spaces_oss/public/api.ts +++ b/src/plugins/spaces_oss/public/api.ts @@ -6,9 +6,10 @@ * Side Public License, v 1. */ -import { Observable } from 'rxjs'; +import type { Observable } from 'rxjs'; import type { ReactElement } from 'react'; -import { Space } from '../common'; + +import type { Space } from '../common'; /** * @public diff --git a/src/plugins/spaces_oss/public/mocks/index.ts b/src/plugins/spaces_oss/public/mocks/index.ts index c0ee76436f1f5..8061faa00b089 100644 --- a/src/plugins/spaces_oss/public/mocks/index.ts +++ b/src/plugins/spaces_oss/public/mocks/index.ts @@ -7,7 +7,8 @@ */ import { spacesApiMock } from '../api.mock'; -import { SpacesOssPluginSetup, SpacesOssPluginStart } from '..'; + +import type { SpacesOssPluginSetup, SpacesOssPluginStart } from '../'; const createSetupContract = (): jest.Mocked => ({ registerSpacesApi: jest.fn(), diff --git a/src/plugins/spaces_oss/public/plugin.ts b/src/plugins/spaces_oss/public/plugin.ts index e6823284d44ba..52a8fd0d570d2 100644 --- a/src/plugins/spaces_oss/public/plugin.ts +++ b/src/plugins/spaces_oss/public/plugin.ts @@ -6,9 +6,10 @@ * Side Public License, v 1. */ -import { Plugin } from 'src/core/public'; -import { SpacesOssPluginSetup, SpacesOssPluginStart } from './types'; -import { SpacesApi } from './api'; +import type { Plugin } from 'src/core/public'; + +import type { SpacesOssPluginSetup, SpacesOssPluginStart } from './types'; +import type { SpacesApi } from './api'; export class SpacesOssPlugin implements Plugin { private api?: SpacesApi; diff --git a/src/plugins/spaces_oss/public/types.ts b/src/plugins/spaces_oss/public/types.ts index 831aaa2c45943..22501d3abd832 100644 --- a/src/plugins/spaces_oss/public/types.ts +++ b/src/plugins/spaces_oss/public/types.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { SpacesApi } from './api'; +import type { SpacesApi } from './api'; export interface SpacesAvailableStartContract extends SpacesApi { isSpacesAvailable: true; diff --git a/src/plugins/telemetry/README.md b/src/plugins/telemetry/README.md index 0a05facfbbe0f..df0070effe754 100644 --- a/src/plugins/telemetry/README.md +++ b/src/plugins/telemetry/README.md @@ -6,7 +6,7 @@ Telemetry allows Kibana features to have usage tracked in the wild. The general 2. Sending a payload of usage data up to Elastic's telemetry cluster. 3. Viewing usage data in the Kibana instance of the telemetry cluster (Viewing). -This plugin is responsible for sending usage data to the telemetry cluster. For collecting usage data, use the [`usageCollection` plugin](../usage_collection/README.md) +This plugin is responsible for sending usage data to the telemetry cluster. For collecting usage data, use the [`usageCollection` plugin](../usage_collection/README.mdx) ## Telemetry Plugin public API diff --git a/src/plugins/telemetry/public/services/telemetry_sender.test.ts b/src/plugins/telemetry/public/services/telemetry_sender.test.ts index 805b53379c815..82dbdb49f38f5 100644 --- a/src/plugins/telemetry/public/services/telemetry_sender.test.ts +++ b/src/plugins/telemetry/public/services/telemetry_sender.test.ts @@ -126,9 +126,7 @@ describe('TelemetrySender', () => { originalFetch = window.fetch; }); - // @ts-ignore beforeEach(() => (window.fetch = mockFetch = jest.fn())); - // @ts-ignore afterAll(() => (window.fetch = originalFetch)); it('does not send if already sending', async () => { @@ -250,9 +248,7 @@ describe('TelemetrySender', () => { originalSetInterval = window.setInterval; }); - // @ts-ignore beforeEach(() => (window.setInterval = mockSetInterval = jest.fn())); - // @ts-ignore afterAll(() => (window.setInterval = originalSetInterval)); it('calls sendIfDue every 60000 ms', () => { diff --git a/src/plugins/telemetry/public/services/telemetry_service.test.ts b/src/plugins/telemetry/public/services/telemetry_service.test.ts index 465daf1e66048..c06352208651a 100644 --- a/src/plugins/telemetry/public/services/telemetry_service.test.ts +++ b/src/plugins/telemetry/public/services/telemetry_service.test.ts @@ -211,9 +211,7 @@ describe('TelemetryService', () => { originalFetch = window.fetch; }); - // @ts-ignore beforeEach(() => (window.fetch = mockFetch = jest.fn())); - // @ts-ignore afterAll(() => (window.fetch = originalFetch)); it('reports opt-in status to telemetry url', async () => { diff --git a/src/plugins/telemetry/server/fetcher.ts b/src/plugins/telemetry/server/fetcher.ts index 76dfa398ec5e4..5db1b62cb3e26 100644 --- a/src/plugins/telemetry/server/fetcher.ts +++ b/src/plugins/telemetry/server/fetcher.ts @@ -8,7 +8,6 @@ import { Observable, Subscription, timer } from 'rxjs'; import { take } from 'rxjs/operators'; -// @ts-ignore import fetch from 'node-fetch'; import { TelemetryCollectionManagerPluginStart, diff --git a/src/plugins/telemetry/server/routes/telemetry_opt_in_stats.test.ts b/src/plugins/telemetry/server/routes/telemetry_opt_in_stats.test.ts index deb8e10280065..6660a36e76199 100644 --- a/src/plugins/telemetry/server/routes/telemetry_opt_in_stats.test.ts +++ b/src/plugins/telemetry/server/routes/telemetry_opt_in_stats.test.ts @@ -7,7 +7,6 @@ */ jest.mock('node-fetch'); -// @ts-ignore import fetch from 'node-fetch'; import { sendTelemetryOptInStatus } from './telemetry_opt_in_stats'; import { StatsGetterConfig } from 'src/plugins/telemetry_collection_manager/server'; diff --git a/src/plugins/telemetry/server/telemetry_collection/get_cluster_info.test.ts b/src/plugins/telemetry/server/telemetry_collection/get_cluster_info.test.ts index 2fc6fd355d7ac..9e70e31925226 100644 --- a/src/plugins/telemetry/server/telemetry_collection/get_cluster_info.test.ts +++ b/src/plugins/telemetry/server/telemetry_collection/get_cluster_info.test.ts @@ -11,14 +11,12 @@ import { getClusterInfo } from './get_cluster_info'; export function mockGetClusterInfo(clusterInfo: any) { const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; - esClient.info - // @ts-ignore we only care about the response body - .mockResolvedValue( - // @ts-ignore we only care about the response body - { - body: { ...clusterInfo }, - } - ); + esClient.info.mockResolvedValue( + // @ts-expect-error we only care about the response body + { + body: { ...clusterInfo }, + } + ); return esClient; } diff --git a/src/plugins/telemetry/server/telemetry_collection/get_cluster_stats.test.ts b/src/plugins/telemetry/server/telemetry_collection/get_cluster_stats.test.ts index 40325ba854ea2..a2c22fbbb0a78 100644 --- a/src/plugins/telemetry/server/telemetry_collection/get_cluster_stats.test.ts +++ b/src/plugins/telemetry/server/telemetry_collection/get_cluster_stats.test.ts @@ -21,7 +21,7 @@ describe('get_cluster_stats', () => { const response = Promise.resolve({ body: { cluster_uuid: '1234' } }); const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; esClient.cluster.stats.mockImplementationOnce( - // @ts-ignore the method only cares about the response body + // @ts-expect-error the method only cares about the response body async (_params = { timeout: TIMEOUT }) => { return response; } diff --git a/src/plugins/telemetry/server/telemetry_collection/get_data_telemetry/get_data_telemetry.test.ts b/src/plugins/telemetry/server/telemetry_collection/get_data_telemetry/get_data_telemetry.test.ts index 986b4c45849ca..c892f27905e0d 100644 --- a/src/plugins/telemetry/server/telemetry_collection/get_data_telemetry/get_data_telemetry.test.ts +++ b/src/plugins/telemetry/server/telemetry_collection/get_data_telemetry/get_data_telemetry.test.ts @@ -265,7 +265,7 @@ function mockEsClient( indexStats: any = {} ) { const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; - // @ts-ignore + // @ts-expect-error esClient.indices.getMapping.mockImplementationOnce(async () => { const body = Object.fromEntries( indicesMappings.map((index) => [ @@ -294,7 +294,7 @@ function mockEsClient( ); return { body }; }); - // @ts-ignore + // @ts-expect-error esClient.indices.stats.mockImplementationOnce(async () => { return { body: indexStats }; }); diff --git a/src/plugins/telemetry/server/telemetry_collection/get_local_stats.test.ts b/src/plugins/telemetry/server/telemetry_collection/get_local_stats.test.ts index 7a6e7f2cf56ea..45db15bbdedb0 100644 --- a/src/plugins/telemetry/server/telemetry_collection/get_local_stats.test.ts +++ b/src/plugins/telemetry/server/telemetry_collection/get_local_stats.test.ts @@ -24,19 +24,17 @@ function mockUsageCollection(kibanaUsage = {}) { // set up successful call mocks for info, cluster stats, nodes usage and data telemetry function mockGetLocalStats(clusterInfo: any, clusterStats: any) { const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; - esClient.info - // @ts-ignore we only care about the response body - .mockResolvedValue( - // @ts-ignore we only care about the response body - { - body: { ...clusterInfo }, - } - ); + esClient.info.mockResolvedValue( + // @ts-expect-error we only care about the response body + { + body: { ...clusterInfo }, + } + ); esClient.cluster.stats - // @ts-ignore we only care about the response body + // @ts-expect-error we only care about the response body .mockResolvedValue({ body: { ...clusterStats } }); esClient.nodes.usage.mockResolvedValue( - // @ts-ignore we only care about the response body + // @ts-expect-error we only care about the response body { body: { cluster_name: 'testCluster', @@ -64,9 +62,9 @@ function mockGetLocalStats(clusterInfo: any, clusterStats: any) { }, } ); - // @ts-ignore we only care about the response body + // @ts-expect-error we only care about the response body esClient.indices.getMapping.mockResolvedValue({ body: { mappings: {} } }); - // @ts-ignore we only care about the response body + // @ts-expect-error we only care about the response body esClient.indices.stats.mockResolvedValue({ body: { indices: {} } }); return esClient; } diff --git a/src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.test.ts b/src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.test.ts index 145ad89e7d462..9192afd3376d5 100644 --- a/src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.test.ts +++ b/src/plugins/telemetry/server/telemetry_collection/get_nodes_usage.test.ts @@ -40,7 +40,7 @@ describe('get_nodes_usage', () => { const response = Promise.resolve({ body: mockedNodesFetchResponse }); const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; esClient.nodes.usage.mockImplementationOnce( - // @ts-ignore + // @ts-expect-error async (_params = { timeout: TIMEOUT }) => { return response; } diff --git a/src/plugins/usage_collection/README.md b/src/plugins/usage_collection/README.mdx similarity index 97% rename from src/plugins/usage_collection/README.md rename to src/plugins/usage_collection/README.mdx index 735c4697737d2..07ead377bf396 100644 --- a/src/plugins/usage_collection/README.md +++ b/src/plugins/usage_collection/README.mdx @@ -1,3 +1,12 @@ +--- +id: kibUsageCollectionPlugin +slug: /kibana-dev-docs/services/usage-collection-plugin +title: Usage collection service +summary: The Usage Collection Service defines a set of APIs for other plugins to report the usage of their features. +date: 2021-02-24 +tags: ['kibana','dev', 'contributor', 'api docs'] +--- + # Kibana Usage Collection Service The Usage Collection Service defines a set of APIs for other plugins to report the usage of their features. At the same time, it provides necessary the APIs for other services (i.e.: telemetry, monitoring, ...) to consume that usage data. @@ -43,7 +52,7 @@ import { Plugin, CoreStart } from '../../../core/public'; export class MyPlugin implements Plugin { public start( - core: CoreStart, + core: CoreStart, { usageCollection }: { usageCollection?: UsageCollectionSetup } ) { // Call the following method as many times as you want to report an increase in the count for this event @@ -109,9 +118,9 @@ In many cases, plugins need to report the custom usage of a feature. In this cas ##### Creating and Registering Usage Collector -1. To create the usage collector, the API `usageCollection.makeUsageCollector` expects: - - `type`: the key under which to nest all the usage reported by the `fetch` method. - - `schema`: field to define the expected output of the `fetch` method. +1. To create the usage collector, the API `usageCollection.makeUsageCollector` expects: + - `type`: the key under which to nest all the usage reported by the `fetch` method. + - `schema`: field to define the expected output of the `fetch` method. - `isReady`: async method (that returns true or false) for letting the usage collection consumers know if they need to wait for any asynchronous action (initialization of clients or other services) before calling the `fetch` method. - `fetch`: async method for returning the usage collector's data. @@ -161,7 +170,7 @@ In many cases, plugins need to report the custom usage of a feature. In this cas }, }, isReady: () => isCollectorFetchReady, // Method to return `true`/`false` or Promise(`true`/`false`) to confirm if the collector is ready for the `fetch` method to be called. - + fetch: async (collectorFetchContext: CollectorFetchContext) => { // query ES or saved objects and get some data @@ -181,13 +190,13 @@ In many cases, plugins need to report the custom usage of a feature. In this cas } ``` -Some background: +Some background: - `MY_USAGE_TYPE` can be any string. It usually matches the plugin name. As a safety mechanism, we double check there are no duplicates at the moment of registering the collector. - `isReady` (added in v7.2.0 and v6.8.4) is a way for a usage collector to announce that some async process must finish first before it can return data in the `fetch` method (e.g. a client needs to ne initialized, or the task manager needs to run a task first). If any collector reports that it is not ready when we call its `fetch` method, we reset a flag to try again and, after a set amount of time, collect data from those collectors that are ready and skip any that are not. This means that if a collector returns `true` for `isReady` and it actually isn't ready to return data, there won't be telemetry data from that collector in that telemetry report (usually once per day). You should consider what it means if your collector doesn't return data in the first few documents when Kibana starts or, if we should wait for any other reason (e.g. the task manager needs to run your task first). If you need to tell telemetry collection to wait, you should implement this function with custom logic. If your `fetch` method can run without the need of any previous dependencies, then you can return true for `isReady` as shown in the example below. -- The `fetch` method needs to support multiple contexts in which it is called. For example, when a user requests the example of what we collect in the **Kibana>Advanced Settings>Usage data** section, the clients provided in the context of the function (`CollectorFetchContext`) are scoped to that user's privileges. The reason is to avoid exposing via telemetry any data that user should not have access to (i.e.: if the user does not have access to certain indices, they shouldn't be allowed to see the number of documents that exists in it). In this case, the `fetch` method receives the clients `esClient` and `soClient` scoped to the user who performed the HTTP API request. Alternatively, when requesting the usage data to be reported to the Remote Telemetry Service, the clients are scoped to the internal Kibana user (`kibana_system`). Please, mind it might have lower-level access than the default super-admin `elastic` test user. +- The `fetch` method needs to support multiple contexts in which it is called. For example, when a user requests the example of what we collect in the **Kibana>Advanced Settings>Usage data** section, the clients provided in the context of the function (`CollectorFetchContext`) are scoped to that user's privileges. The reason is to avoid exposing via telemetry any data that user should not have access to (i.e.: if the user does not have access to certain indices, they shouldn't be allowed to see the number of documents that exists in it). In this case, the `fetch` method receives the clients `esClient` and `soClient` scoped to the user who performed the HTTP API request. Alternatively, when requesting the usage data to be reported to the Remote Telemetry Service, the clients are scoped to the internal Kibana user (`kibana_system`). Please, mind it might have lower-level access than the default super-admin `elastic` test user. In some scenarios, your collector might need to maintain its own client. An example of that is the `monitoring` plugin, that maintains a connection to the Remote Monitoring Cluster to push its monitoring data. If that's the case, your plugin can opt-in to receive the additional `kibanaRequest` parameter by adding `extendFetchContext.kibanaRequest: true` to the collector's config: it will be appended to the context of the `fetch` method only if the request needs to be scoped to a user other than Kibana Internal, so beware that your collector will need to work for both scenarios (especially for the scenario when `kibanaRequest` is missing). Note: there will be many cases where you won't need to use the `esClient` or `soClient` function that gets passed in to your `fetch` method at all. Your feature might have an accumulating value in server memory, or read something from the OS. @@ -241,15 +250,15 @@ export const myCollector = makeUsageCollector({ }, some_array: { type: 'array', - items: { type: 'keyword' } + items: { type: 'keyword' } }, some_array_of_obj: { type: 'array', - items: { + items: { total: { type: 'long', }, - }, + }, }, }, }); @@ -263,7 +272,7 @@ use your plugin or specific features. For tracking user interactions the method which can be used to increment one or more counter fields in a document. Examples of interactions include tracking: - the number of API calls - - the number of times users installed and uninstalled the sample datasets + - the number of times users installed and uninstalled the sample datasets When using `incrementCounter` for collecting usage data, you need to ensure that usage collection happens on a best-effort basis and doesn't @@ -341,7 +350,7 @@ export class DashboardPlugin implements Plugin { counter ], {refresh: false}) .catch((e) => (this.isDevEnvironement ? this.logger.error(e) : e)); - + return response.ok(); } ); diff --git a/src/plugins/visualize/public/plugin.ts b/src/plugins/visualize/public/plugin.ts index 300afd69c84cc..4b369e8be86ee 100644 --- a/src/plugins/visualize/public/plugin.ts +++ b/src/plugins/visualize/public/plugin.ts @@ -116,10 +116,7 @@ export class VisualizePlugin ], getHistory: () => this.currentHistory!, onBeforeNavLinkSaved: (urlToSave: string) => { - if ( - !urlToSave.includes(`${VisualizeConstants.EDIT_PATH}/`) && - this.isLinkedToOriginatingApp?.() - ) { + if (this.isLinkedToOriginatingApp?.()) { return core.http.basePath.prepend(VisualizeConstants.VISUALIZE_BASE_PATH); } return urlToSave; diff --git a/test/functional/apps/dashboard/create_and_add_embeddables.ts b/test/functional/apps/dashboard/create_and_add_embeddables.ts index c26b375a37b8f..f4ee4e9904768 100644 --- a/test/functional/apps/dashboard/create_and_add_embeddables.ts +++ b/test/functional/apps/dashboard/create_and_add_embeddables.ts @@ -69,10 +69,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.dashboard.waitForRenderComplete(); }); - it('saves the saved visualization url to the app link', async () => { + it('saves the listing page instead of the visualization to the app link', async () => { await PageObjects.header.clickVisualize(true); const currentUrl = await browser.getCurrentUrl(); - expect(currentUrl).to.contain(VisualizeConstants.EDIT_PATH); + expect(currentUrl).not.to.contain(VisualizeConstants.EDIT_PATH); }); after(async () => { diff --git a/test/functional/apps/dashboard/edit_visualizations.js b/test/functional/apps/dashboard/edit_visualizations.js index a918c017bd88f..d5df97881a1d3 100644 --- a/test/functional/apps/dashboard/edit_visualizations.js +++ b/test/functional/apps/dashboard/edit_visualizations.js @@ -109,6 +109,24 @@ export default function ({ getService, getPageObjects }) { expect(await testSubjects.exists('visualizationLandingPage')).to.be(true); }); + it('visualize app menu navigates to the visualize listing page if the last opened visualization was linked to dashboard', async () => { + await PageObjects.common.navigateToApp('dashboard'); + await PageObjects.dashboard.gotoDashboardLandingPage(); + await PageObjects.dashboard.clickNewDashboard(); + + // Create markdown by reference. + await createMarkdownVis('by reference'); + + // Edit then save and return + await editMarkdownVis(); + await PageObjects.visualize.saveVisualizationAndReturn(); + + await PageObjects.header.waitUntilLoadingHasFinished(); + await appsMenu.clickLink('Visualize Library'); + await PageObjects.common.clickConfirmOnModal(); + expect(await testSubjects.exists('visualizationLandingPage')).to.be(true); + }); + describe('by value', () => { it('save and return button returns to dashboard after editing visualization with changes saved', async () => { await PageObjects.common.navigateToApp('dashboard'); diff --git a/test/functional/apps/dashboard/embeddable_data_grid.ts b/test/functional/apps/dashboard/embeddable_data_grid.ts index 54fa9f08c5763..00a75baae4be7 100644 --- a/test/functional/apps/dashboard/embeddable_data_grid.ts +++ b/test/functional/apps/dashboard/embeddable_data_grid.ts @@ -16,6 +16,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const kibanaServer = getService('kibanaServer'); const find = getService('find'); const PageObjects = getPageObjects(['common', 'dashboard', 'header', 'timePicker', 'discover']); + const retry = getService('retry'); + const dataGrid = getService('dataGrid'); describe('dashboard embeddable data grid', () => { before(async () => { @@ -31,22 +33,30 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.dashboard.gotoDashboardLandingPage(); await PageObjects.dashboard.clickNewDashboard(); await PageObjects.timePicker.setDefaultDataRange(); + await dashboardAddPanel.addSavedSearch('Rendering-Test:-saved-search'); }); - describe('saved search filters', function () { - it('are added when a cell filter is clicked', async function () { - await dashboardAddPanel.addSavedSearch('Rendering-Test:-saved-search'); - await find.clickByCssSelector(`[role="gridcell"]:nth-child(3)`); - // needs a short delay between becoming visible & being clickable - await PageObjects.common.sleep(250); - await find.clickByCssSelector(`[data-test-subj="filterOutButton"]`); - await PageObjects.header.waitUntilLoadingHasFinished(); - await find.clickByCssSelector(`[role="gridcell"]:nth-child(3)`); - await PageObjects.common.sleep(250); - await find.clickByCssSelector(`[data-test-subj="filterForButton"]`); - const filterCount = await filterBar.getFilterCount(); - expect(filterCount).to.equal(2); + it('should expand the detail row when the toggle arrow is clicked', async function () { + await retry.try(async function () { + await dataGrid.clickRowToggle({ isAnchorRow: false, rowIndex: 0 }); + const detailsEl = await dataGrid.getDetailsRows(); + const defaultMessageEl = await detailsEl[0].findByTestSubject('docTableRowDetailsTitle'); + expect(defaultMessageEl).to.be.ok(); + await dataGrid.closeFlyout(); }); }); + + it('are added when a cell filter is clicked', async function () { + await find.clickByCssSelector(`[role="gridcell"]:nth-child(3)`); + // needs a short delay between becoming visible & being clickable + await PageObjects.common.sleep(250); + await find.clickByCssSelector(`[data-test-subj="filterOutButton"]`); + await PageObjects.header.waitUntilLoadingHasFinished(); + await find.clickByCssSelector(`[role="gridcell"]:nth-child(3)`); + await PageObjects.common.sleep(250); + await find.clickByCssSelector(`[data-test-subj="filterForButton"]`); + const filterCount = await filterBar.getFilterCount(); + expect(filterCount).to.equal(2); + }); }); } diff --git a/x-pack/plugins/actions/README.md b/x-pack/plugins/actions/README.md index 78094f4c0eb0b..f1be1ec12b79c 100644 --- a/x-pack/plugins/actions/README.md +++ b/x-pack/plugins/actions/README.md @@ -33,42 +33,14 @@ Table of Contents - [actionsClient.execute(options)](#actionsclientexecuteoptions) - [Example](#example-2) - [Built-in Action Types](#built-in-action-types) - - [Server log](#server-log) - - [`config`](#config) - - [`secrets`](#secrets) - - [`params`](#params) - - [Email](#email) - - [`config`](#config-1) - - [`secrets`](#secrets-1) - - [`params`](#params-1) - - [Slack](#slack) - - [`config`](#config-2) - - [`secrets`](#secrets-2) - - [`params`](#params-2) - - [Index](#index) - - [`config`](#config-3) - - [`secrets`](#secrets-3) - - [`params`](#params-3) - - [Webhook](#webhook) - - [`config`](#config-4) - - [`secrets`](#secrets-4) - - [`params`](#params-4) - - [PagerDuty](#pagerduty) - - [`config`](#config-5) - - [`secrets`](#secrets-5) - - [`params`](#params-5) - [ServiceNow](#servicenow) - - [`config`](#config-6) - - [`secrets`](#secrets-6) - - [`params`](#params-6) + - [`params`](#params) - [`subActionParams (pushToService)`](#subactionparams-pushtoservice) - [`subActionParams (getFields)`](#subactionparams-getfields) - [`subActionParams (getIncident)`](#subactionparams-getincident) - [`subActionParams (getChoices)`](#subactionparams-getchoices) - [Jira](#jira) - - [`config`](#config-7) - - [`secrets`](#secrets-7) - - [`params`](#params-7) + - [`params`](#params-1) - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-1) - [`subActionParams (getIncident)`](#subactionparams-getincident-1) - [`subActionParams (issueTypes)`](#subactionparams-issuetypes) @@ -77,9 +49,7 @@ Table of Contents - [`subActionParams (issue)`](#subactionparams-issue) - [`subActionParams (getFields)`](#subactionparams-getfields-1) - [IBM Resilient](#ibm-resilient) - - [`config`](#config-8) - - [`secrets`](#secrets-8) - - [`params`](#params-8) + - [`params`](#params-2) - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-2) - [`subActionParams (getFields)`](#subactionparams-getfields-2) - [`subActionParams (incidentTypes)`](#subactionparams-incidenttypes) @@ -272,6 +242,160 @@ const result = await actionsClient.execute({ Kibana ships with a set of built-in action types. See [Actions and connector types Documentation](https://www.elastic.co/guide/en/kibana/master/action-types.html). +In addition to the documented configurations, several built in action type offer additional `params` configurations. + +## ServiceNow + +The [ServiceNow user documentation `params`](https://www.elastic.co/guide/en/kibana/master/servicenow-action-type.html) lists configuration properties for the `pushToService` subaction. In addition, several other subaction types are available. +### `params` + +| Property | Description | Type | +| --------------- | -------------------------------------------------------------------------------------------------- | ------ | +| subAction | The subaction to perform. It can be `pushToService`, `getFields`, `getIncident`, and `getChoices`. | string | +| subActionParams | The parameters of the subaction. | object | + +#### `subActionParams (pushToService)` + +| Property | Description | Type | +| -------- | ------------------------------------------------------------------------------------------------------------- | --------------------- | +| incident | The ServiceNow incident. | object | +| comments | The comments of the case. A comment is of the form `{ commentId: string, version: string, comment: string }`. | object[] _(optional)_ | + +The following table describes the properties of the `incident` object. + +| Property | Description | Type | +| ----------------- | ------------------------------------------------------------------------------------------------------------------------- | ------------------- | +| short_description | The title of the incident. | string | +| description | The description of the incident. | string _(optional)_ | +| externalId | The ID of the incident in ServiceNow. If present, the incident is updated. Otherwise, a new incident is created. | string _(optional)_ | +| severity | The severity in ServiceNow. | string _(optional)_ | +| urgency | The urgency in ServiceNow. | string _(optional)_ | +| impact | The impact in ServiceNow. | string _(optional)_ | +| category | The category in ServiceNow. | string _(optional)_ | +| subcategory | The subcategory in ServiceNow. | string _(optional)_ | + +#### `subActionParams (getFields)` + +No parameters for the `getFields` subaction. Provide an empty object `{}`. + +#### `subActionParams (getIncident)` + +| Property | Description | Type | +| ---------- | ------------------------------------- | ------ | +| externalId | The ID of the incident in ServiceNow. | string | + + +#### `subActionParams (getChoices)` + +| Property | Description | Type | +| -------- | ------------------------------------------------------------ | -------- | +| fields | An array of fields. Example: `[priority, category, impact]`. | string[] | + +--- + +## Jira + +The [Jira user documentation `params`](https://www.elastic.co/guide/en/kibana/master/jira-action-type.html) lists configuration properties for the `pushToService` subaction. In addition, several other subaction types are available. +### `params` + +| Property | Description | Type | +| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ------ | +| subAction | The subaction to perform. It can be `pushToService`, `getIncident`, `issueTypes`, `fieldsByIssueType`, `issues`, `issue`, and `getFields`. | string | +| subActionParams | The parameters of the subaction. | object | + +#### `subActionParams (pushToService)` + +| Property | Description | Type | +| -------- | ------------------------------------------------------------------------------------------------------------- | --------------------- | +| incident | The Jira incident. | object | +| comments | The comments of the case. A comment is of the form `{ commentId: string, version: string, comment: string }`. | object[] _(optional)_ | + +The following table describes the properties of the `incident` object. + +| Property | Description | Type | +| ----------- | ---------------------------------------------------------------------------------------------------------------- | --------------------- | +| summary | The title of the issue. | string | +| description | The description of the issue. | string _(optional)_ | +| externalId | The ID of the issue in Jira. If present, the incident is updated. Otherwise, a new incident is created. | string _(optional)_ | +| issueType | The ID of the issue type in Jira. | string _(optional)_ | +| priority | The name of the priority in Jira. Example: `Medium`. | string _(optional)_ | +| labels | An array of labels. Labels cannot contain spaces. | string[] _(optional)_ | +| parent | The ID or key of the parent issue. Only for `Sub-task` issue types. | string _(optional)_ | + +#### `subActionParams (getIncident)` + +| Property | Description | Type | +| ---------- | --------------------------- | ------ | +| externalId | The ID of the issue in Jira. | string | + +#### `subActionParams (issueTypes)` + +No parameters for the `issueTypes` subaction. Provide an empty object `{}`. + +#### `subActionParams (fieldsByIssueType)` + +| Property | Description | Type | +| -------- | -------------------------------- | ------ | +| id | The ID of the issue type in Jira. | string | + +#### `subActionParams (issues)` + +| Property | Description | Type | +| -------- | ----------------------- | ------ | +| title | The title to search for. | string | + +#### `subActionParams (issue)` + +| Property | Description | Type | +| -------- | --------------------------- | ------ | +| id | The ID of the issue in Jira. | string | + +#### `subActionParams (getFields)` + +No parameters for the `getFields` subaction. Provide an empty object `{}`. + +--- +## IBM Resilient + +The [IBM Resilient user documentation `params`](https://www.elastic.co/guide/en/kibana/master/resilient-action-type.html) lists configuration properties for the `pushToService` subaction. In addition, several other subaction types are available. + +### `params` + +| Property | Description | Type | +| --------------- | -------------------------------------------------------------------------------------------------- | ------ | +| subAction | The subaction to perform. It can be `pushToService`, `getFields`, `incidentTypes`, and `severity. | string | +| subActionParams | The parameters of the subaction. | object | + +#### `subActionParams (pushToService)` + +| Property | Description | Type | +| -------- | ------------------------------------------------------------------------------------------------------------- | --------------------- | +| incident | The IBM Resilient incident. | object | +| comments | The comments of the case. A comment is of the form `{ commentId: string, version: string, comment: string }`. | object[] _(optional)_ | + +The following table describes the properties of the `incident` object. + +| Property | Description | Type | +| ------------- | ---------------------------------------------------------------------------------------------------------------------------- | --------------------- | +| name | The title of the incident. | string _(optional)_ | +| description | The description of the incident. | string _(optional)_ | +| externalId | The ID of the incident in IBM Resilient. If present, the incident is updated. Otherwise, a new incident is created. | string _(optional)_ | +| incidentTypes | An array with the IDs of IBM Resilient incident types. | number[] _(optional)_ | +| severityCode | IBM Resilient ID of the severity code. | number _(optional)_ | + +#### `subActionParams (getFields)` + +No parameters for the `getFields` subaction. Provide an empty object `{}`. + +#### `subActionParams (incidentTypes)` + +No parameters for the `incidentTypes` subaction. Provide an empty object `{}`. + +#### `subActionParams (severity)` + +No parameters for the `severity` subaction. Provide an empty object `{}`. + +--- # Command Line Utility The [`kbn-action`](https://github.com/pmuellr/kbn-action) tool can be used to send HTTP requests to the Actions plugin. For instance, to create a Slack action from the `.slack` Action Type, use the following command: diff --git a/x-pack/plugins/apm/dev_docs/telemetry.md b/x-pack/plugins/apm/dev_docs/telemetry.md index 5999997537789..5462fbcc3b36c 100644 --- a/x-pack/plugins/apm/dev_docs/telemetry.md +++ b/x-pack/plugins/apm/dev_docs/telemetry.md @@ -14,7 +14,7 @@ Telemetry data is uploaded to the "xpack-phone-home" indices. Information that can be derived from a cluster's APM indices is queried and sent to the telemetry cluster using the -[Usage Collection plugin](../../../../src/plugins/usage_collection/README.md). +[Usage Collection plugin](../../../../src/plugins/usage_collection/README.mdx). During the APM server-side plugin's setup phase a [Saved Object](https://www.elastic.co/guide/en/kibana/master/managing-saved-objects.html) diff --git a/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/index.tsx b/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/index.tsx index 4b8d8ddc6f746..5fcd2914f2225 100644 --- a/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/index.tsx +++ b/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/index.tsx @@ -60,6 +60,45 @@ function getShortGroupId(errorGroupId?: string) { return errorGroupId.slice(0, 5); } +function ErrorGroupHeader({ + groupId, + isUnhandled, +}: { + groupId: string; + isUnhandled?: boolean; +}) { + return ( + <> + + + + +

+ {i18n.translate('xpack.apm.errorGroupDetails.errorGroupTitle', { + defaultMessage: 'Error group {errorGroupId}', + values: { + errorGroupId: getShortGroupId(groupId), + }, + })} +

+
+
+ {isUnhandled && ( + + + {i18n.translate('xpack.apm.errorGroupDetails.unhandledLabel', { + defaultMessage: 'Unhandled', + })} + + + )} +
+
+ + + ); +} + type ErrorGroupDetailsProps = RouteComponentProps<{ groupId: string; serviceName: string; @@ -101,7 +140,7 @@ export function ErrorGroupDetails({ location, match }: ErrorGroupDetailsProps) { useTrackPageview({ app: 'apm', path: 'error_group_details', delay: 15000 }); if (!errorGroupData || !errorDistributionData) { - return null; + return ; } // If there are 0 occurrences, show only distribution chart w. empty message @@ -114,32 +153,7 @@ export function ErrorGroupDetails({ location, match }: ErrorGroupDetailsProps) { return ( <> - - - - -

- {i18n.translate('xpack.apm.errorGroupDetails.errorGroupTitle', { - defaultMessage: 'Error group {errorGroupId}', - values: { - errorGroupId: getShortGroupId(groupId), - }, - })} -

-
-
- {isUnhandled && ( - - - {i18n.translate('xpack.apm.errorGroupDetails.unhandledLabel', { - defaultMessage: 'Unhandled', - })} - - - )} -
-
- + diff --git a/x-pack/plugins/apm/public/components/app/error_group_overview/index.tsx b/x-pack/plugins/apm/public/components/app/error_group_overview/index.tsx index 49e1cc44f9255..96657bcfb4734 100644 --- a/x-pack/plugins/apm/public/components/app/error_group_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/error_group_overview/index.tsx @@ -68,7 +68,7 @@ export function ErrorGroupOverview({ serviceName }: ErrorGroupOverviewProps) { useTrackPageview({ app: 'apm', path: 'error_group_overview', delay: 15000 }); if (!errorDistributionData || !errorGroupListData) { - return null; + return ; } return ( diff --git a/x-pack/plugins/beats_management/public/bootstrap.tsx b/x-pack/plugins/beats_management/public/bootstrap.tsx index 4a4d3a893286b..b5bdd39fa0817 100644 --- a/x-pack/plugins/beats_management/public/bootstrap.tsx +++ b/x-pack/plugins/beats_management/public/bootstrap.tsx @@ -18,10 +18,13 @@ import { BeatsManagementConfigType } from '../common'; import { MANAGEMENT_SECTION } from '../common/constants'; async function startApp(libs: FrontendLibs, core: CoreSetup) { - const [startServices] = await Promise.all([ - core.getStartServices(), - libs.framework.waitUntilFrameworkReady(), - ]); + const startServices = await core.getStartServices(); + + if (startServices[0].http.anonymousPaths.isAnonymous(window.location.pathname)) { + return; + } + // Can't run until the `start` lifecycle, so we wait for start services to resolve above before calling this. + await libs.framework.waitUntilFrameworkReady(); const capabilities = startServices[0].application.capabilities; const hasBeatsCapability = capabilities.management.ingest?.[MANAGEMENT_SECTION] ?? false; diff --git a/x-pack/plugins/canvas/PLUGINS.mdx b/x-pack/plugins/canvas/PLUGINS.mdx new file mode 100644 index 0000000000000..0f93948d663a0 --- /dev/null +++ b/x-pack/plugins/canvas/PLUGINS.mdx @@ -0,0 +1,239 @@ +--- +id: canvasPlugins +slug: /playground/kibana/canvas-plugins +title: Develop Canvas plugins +summary: Introduction to +date: 2021-02-18 +tags: ['kibana', 'canvas', 'plugins'] +related: [] +--- + +To develop your own Canvas plugins, you simply create a Kibana plugin, and register your customizations with Canvas. + +The following is a step-by-step guide to adding your own custom random number Canvas plugin. + +## Generating a Kibana plugin + +```bash +# in the kibana directory +# Rename canvas_example to whatever you want your plugin to be named +node scripts/generate_plugin.js canvas_example +``` + +This will prompt you for some input. Generally, you can answer as follows: + +``` +❯ node scripts/generate_plugin.js canvas_example +? Would you like to create the plugin in a different folder? No +? Provide a short description An awesome Kibana plugin +? What Kibana version are you targeting? master +? Should an app component be generated? No +? Should a server API be generated? No +? Should translation files be generated? No +? Would you like to use a custom eslint file? No +``` + +Once this has completed, go to your plugin directory: + +```bash +cd plugins/canvas_example +``` + +Open that folder in your code editor of choice: `code .` + +### Creating a Canvas element and function +Open your plugin's `kibana.json` file. Make sure that `ui` has a value of true, and that `'canvas'` is included in `requiredPlugins`. It should look something like this. + +```json +{ + "id": "canvasExample", + "version": "7.8.0", + "server": false, + "ui": true, + "requiredPlugins": ["canvas"], + "optionalPlugins": [] +} +``` + +In your plugin folder, create a new folder `public` and an `index.ts` file within it. + +This `index.ts` will need export a Kibana Plugin. You can use this as a starting point for your plugin. + +```typescript +import { Plugin, CoreSetup, CoreStart } from '../../../src/core/public'; +import { CanvasSetup } from '../../../x-pack/plugins/canvas/public'; + +interface CanvasExampleSetupPlugins { + canvas: CanvasSetup; +} + +interface CanvasExampleStartPlugins {} + +class CanvasExamplePlugin + implements Plugin { + setup(core: CoreSetup, plugins: CanvasExampleSetupPlugins) {} + + start(core: CoreStart) {} +} + +export const plugin = () => new CanvasExamplePlugin(); +``` + + +Now that the Kibana plugin boilerplate is out of the way, you can start adding functionality to Canvas. + +Let's start by adding a new function. + +In your `index.ts` add a new function definition: + +```typescript +const canvasFunctions = [ + () => ({ + name: 'random', + help: 'Make a random number between 1 and 100', + args: {}, + fn() { + return Math.floor(Math.random() * 100) + 1; + } + }), +]; +``` + +Then, in the `setup` method of your plugin, you can add this new function definition to Canvas: + +```typescript +setup(core: CoreSetup, plugins: CanvasExampleSetupPlugins) { + plugins.canvas.addFunctions(canvasFunctions); +} +``` + +Now, let's add a new Element type. In your `index.ts` add a new element definition: + +```typescript +const elements = [ + () => ({ + name: 'randomNumber', + displayName: 'Random Number', + help: 'A random number between 1 and 100', + image: 'https://images.contentstack.io/v3/assets/bltefdd0b53724fa2ce/bltb59c89a07c05b937/5c583a6602ac90e80ba0ab8f/icon-white-circle-elastic-stack.svg', + expression: 'random | metric "Random Number"', + }), +]; +``` + +And then, in the `setup` method of the plugin, add this new element definition to Canvas, just like you did with the function: + +```typescript +setup(core: CoreSetup, plugins: CanvasExampleSetupPlugins) { + plugins.canvas.addFunctions(canvasFunctions); + plugins.canvas.addElements(elements); +} +``` + +Now, your 'Random Number' element will show up in the list of other Canvas elements. + +### Trying out your new plugin + +In the terminal, in your plugin's directory, run: + +```bash +# In plugins/canvas_example +yarn start +``` + +- Pull up Kibana in your browser: `http://localhost:5601` +- Go to canvas, and click: "Create workpad" +- Click: "Add element" +- Click: "Other" +- Click: "Random Number" + +### Adding a server-side function + +> Server side functions may be deprecated in a later version of Kibana + +Now, let's add a function which runs on the server. + +In your plugin's `kibana.json` file, set `server` to true, and add `"expressions"` as a requiredPlugin. + +```typescript +{ + "id": "canvasExample", + "version": "8.0.0", + "server": false, + "ui": true, + "requiredPlugins": ["canvas", "expressions"], + "optionalPlugins": [] +} +``` + +Now, much like we made the client plugin, we'll make a server plugin. + +Start by making the `server` directory and an `index.ts` file with a shell for your server plugin: + +```typescript +import { Plugin, CoreSetup, CoreStart } from '../../../src/core/server'; +import { ExpressionsServerSetup } from '../../../src/plugins/expressions/server'; + +interface CanvasExamplePluginsSetup { + expressions: ExpressionsServerSetup; +} + +class CanvasExamplePlugin implements Plugin { + setup(core: CoreSetup, plugins: CanvasExamplePluginsSetup) {} + + start(core: CoreStart) {} +} + +export const plugin = () => new CanvasExamplePlugin(); +``` + +Now, we'll create a simple function definition that we will register on the server: + +```typescript +const serverFunctions = [ + () => ({ + name: 'serverTime', + help: 'Get the server time in milliseconds', + args: {}, + fn() { + return Date.now(); + }, + }), +]; +``` + +And then in our setup method, register it with the Expressions plugin: + +```typescript +setup(core: CoreSetup, plugins: CanvasExamplePluginsSetup) { + serverFunctions.forEach((f) => plugins.expressions.registerFunction(f)); +} +``` + +Now, let's try out our new server function. + +- Refresh your browser. +- In the same Canvas workpad: + - Add another Random Number element as before + - Click that element to select it + - Click "Expression editor" + - Modify the expression to look like this: `serverTime | metric "Server Time in ms"` + - Click "Run" + +You should now see one random number and one "Server Time in ms" value. + +> More information about building Kibana Plugins can be found in [src/core](https://github.com/elastic/kibana/blob/master/src/core/README.md) + +### My Canvas Plugin stopped working + +If your Kibana Server is crashing on startup with a message like + +> **FATAL** Error: Unmet requirement "canvas" for plugin "your_plugin_name" + +or + +> **FATAL** Error: Unmet requirement "interpreter" for plugin "your_plugin_name" + +then your plugin was likely created to work on a previous version of Kibana. Starting with version 7.8, the plugin system was redesigned and caused breaking changes to these earlier plugins. + +The good news is that all of your existing Canvas extension code can be reused, it just needs to be in an updated Kibana plugin. Follow the [instructions](#generating-a-kibana-plugin) for creating a new Canvas Kibana plugin, and then add in your existing functions and elements. diff --git a/x-pack/plugins/canvas/README.md b/x-pack/plugins/canvas/README.md index f77585b5b062c..754a4dc29d007 100644 --- a/x-pack/plugins/canvas/README.md +++ b/x-pack/plugins/canvas/README.md @@ -6,246 +6,6 @@ Canvas is included with X-Pack and requires a Basic license or better to use. -## Developing in Canvas - -To develop your own Canvas plugins, you simply create a Kibana plugin, and register your customizations with Canvas. - -The following is a step-by-step guide to adding your own custom random number Canvas plugin. - -### Generating a Kibana plugin - -```bash -# in the kibana directory -# Rename canvas_example to whatever you want your plugin to be named -node scripts/generate_plugin.js canvas_example -``` - -This will prompt you for some input. Generally, you can answer as follows: - -``` -❯ node scripts/generate_plugin.js canvas_example -? Would you like to create the plugin in a different folder? No -? Provide a short description An awesome Kibana plugin -? What Kibana version are you targeting? master -? Should an app component be generated? No -? Should a server API be generated? No -? Should translation files be generated? No -? Would you like to use a custom eslint file? No -``` - -Once this has completed, go to your plugin directory: - -```bash -cd plugins/canvas_example -``` - -Open that folder in your code editor of choice: `code .` - -#### Creating a Canvas element and function -Open your plugin's `kibana.json` file. Make sure that `ui` has a value of true, and that `'canvas'` is included in `requiredPlugins`. It should look something like this. - -```json -{ - "id": "canvasExample", - "version": "7.8.0", - "server": false, - "ui": true, - "requiredPlugins": ["canvas"], - "optionalPlugins": [] -} -``` - -In your plugin folder, create a new folder `public` and an `index.ts` file within it. - -This `index.ts` will need export a Kibana Plugin. You can use this as a starting point for your plugin. - -```typescript -import { Plugin, CoreSetup, CoreStart } from '../../../src/core/public'; -import { CanvasSetup } from '../../../x-pack/plugins/canvas/public'; - -interface CanvasExampleSetupPlugins { - canvas: CanvasSetup; -} - -interface CanvasExampleStartPlugins {} - -class CanvasExamplePlugin - implements Plugin { - setup(core: CoreSetup, plugins: CanvasExampleSetupPlugins) {} - - start(core: CoreStart) {} -} - -export const plugin = () => new CanvasExamplePlugin(); -``` - - -Now that the Kibana plugin boilerplate is out of the way, you can start adding functionality to Canvas. - -Let's start by adding a new function. - -In your `index.ts` add a new function definition: - -```typescript -const canvasFunctions = [ - () => ({ - name: 'random', - help: 'Make a random number between 1 and 100', - args: {}, - fn() { - return Math.floor(Math.random() * 100) + 1; - } - }), -]; -``` - -Then, in the `setup` method of your plugin, you can add this new function definition to Canvas: - -```typescript -setup(core: CoreSetup, plugins: CanvasExampleSetupPlugins) { - plugins.canvas.addFunctions(canvasFunctions); -} -``` - -Now, let's add a new Element type. In your `index.ts` add a new element definition: - -```typescript -const elements = [ - () => ({ - name: 'randomNumber', - displayName: 'Random Number', - help: 'A random number between 1 and 100', - image: 'https://images.contentstack.io/v3/assets/bltefdd0b53724fa2ce/bltb59c89a07c05b937/5c583a6602ac90e80ba0ab8f/icon-white-circle-elastic-stack.svg', - expression: 'random | metric "Random Number"', - }), -]; -``` - -And then, in the `setup` method of the plugin, add this new element definition to Canvas, just like you did with the function: - -```typescript -setup(core: CoreSetup, plugins: CanvasExampleSetupPlugins) { - plugins.canvas.addFunctions(canvasFunctions); - plugins.canvas.addElements(elements); -} -``` - -Now, your 'Random Number' element will show up in the list of other Canvas elements. - -#### Trying out your new plugin - -In the terminal, in your plugin's directory, run: - -```bash -# In plugins/canvas_example -yarn start -``` - -- Pull up Kibana in your browser: `http://localhost:5601` -- Go to canvas, and click: "Create workpad" -- Click: "Add element" -- Click: "Other" -- Click: "Random Number" - -#### Adding a server-side function - -> Server side functions may be deprecated in a later version of Kibana - -Now, let's add a function which runs on the server. - -In your plugin's `kibana.json` file, set `server` to true, and add `"expressions"` as a requiredPlugin. - -```typescript -{ - "id": "canvasExample", - "version": "8.0.0", - "server": false, - "ui": true, - "requiredPlugins": ["canvas", "expressions"], - "optionalPlugins": [] -} -``` - -Now, much like we made the client plugin, we'll make a server plugin. - -Start by making the `server` directory and an `index.ts` file with a shell for your server plugin: - -```typescript -import { Plugin, CoreSetup, CoreStart } from '../../../src/core/server'; -import { ExpressionsServerSetup } from '../../../src/plugins/expressions/server'; - -interface CanvasExamplePluginsSetup { - expressions: ExpressionsServerSetup; -} - -class CanvasExamplePlugin implements Plugin { - setup(core: CoreSetup, plugins: CanvasExamplePluginsSetup) {} - - start(core: CoreStart) {} -} - -export const plugin = () => new CanvasExamplePlugin(); -``` - -Now, we'll create a simple function definition that we will register on the server: - -```typescript -const serverFunctions = [ - () => ({ - name: 'serverTime', - help: 'Get the server time in milliseconds', - args: {}, - fn() { - return Date.now(); - }, - }), -]; -``` - -And then in our setup method, register it with the Expressions plugin: - -```typescript -setup(core: CoreSetup, plugins: CanvasExamplePluginsSetup) { - serverFunctions.forEach((f) => plugins.expressions.registerFunction(f)); -} -``` - -Now, let's try out our new server function. - -- Refresh your browser. -- In the same Canvas workpad: - - Add another Random Number element as before - - Click that element to select it - - Click "Expression editor" - - Modify the expression to look like this: `serverTime | metric "Server Time in ms"` - - Click "Run" - -You should now see one random number and one "Server Time in ms" value. - -> More information about building Kibana Plugins can be found in [src/core](https://github.com/elastic/kibana/blob/master/src/core/README.md) - -#### My Canvas Plugin stopped working - -If your Kibana Server is crashing on startup with a message like - -> **FATAL** Error: Unmet requirement "canvas" for plugin "your_plugin_name" - -or - -> **FATAL** Error: Unmet requirement "interpreter" for plugin "your_plugin_name" - -then your plugin was likely created to work on a previous version of Kibana. Starting with version 7.8, the plugin system was redesigned and caused breaking changes to these earlier plugins. - -The good news is that all of your existing Canvas extension code can be reused, it just needs to be in an updated Kibana plugin. Follow the [instructions](#generating-a-kibana-plugin) for creating a new Canvas Kibana plugin, and then add in your existing functions and elements. - -## Scripts - -There are several scripts available once you are in that path as well. - -- `node scripts/lint` - local linter setup, can also be used with the `--fix` flag for automatic fixes. -- `node scripts/test` - local test runner, does not require a real Kibana instance. Runs all the same unit tests the normal runner does, just limited to Canvas, and *waaaaaay* faster (currently 12 seconds or less). -- `node scripts/test_dev` - Same as above, but watches for changes and only runs tests for the given scope (browser, server, or common). - ## Feature Questions **Why are there no tooltips** diff --git a/x-pack/plugins/canvas/shareable_runtime/README.md b/x-pack/plugins/canvas/shareable_runtime/README.mdx similarity index 88% rename from x-pack/plugins/canvas/shareable_runtime/README.md rename to x-pack/plugins/canvas/shareable_runtime/README.mdx index 3839e7c4ecb3f..8f1c9e06ca788 100644 --- a/x-pack/plugins/canvas/shareable_runtime/README.md +++ b/x-pack/plugins/canvas/shareable_runtime/README.mdx @@ -1,35 +1,12 @@ -# Canvas Shareable Workpads - -- [Introduction](#introduction) -- [Quick Start](#quick-start) -- [Using the Runtime](#using-the-runtime) - - [Assumptions](#assumptions) - - [Restrictions](#restrictions) - - [JS](#js) - - [HTML](#html) - - [Options](#options) -- [Testing](#testing) - - [Download a ZIP from Canvas](#download-a-zip-from-canvas) - - [Test the Runtime Directly from Webpack](#test-the-runtime-directly-from-webpack) - - [Run the Canvas Storybook](#run-the-canvas-storybook) - - [Run the Jest Tests](#run-the-jest-tests) - - [Gathering Test Coverage](#gathering-test-coverage) -- [Building](#building) - - [Build Options](#build-options) -- [Development](#development) - - [Prerequisite](#prerequisite) - - [Webpack Dev Server](#webpack-dev-server) - - [Gathering Statistics](#gathering-statistics) -- [Architecture](#architecture) - - [The Build](#the-build) - - [Supported Expressions](#supported-expressions) - - [Expression Interpreter](#expression-interpreter) - - [Build Size](#build-size) - - [The App](#the-app) - - [App State](#app-state) - - [CSS](#css) - -## Introduction +--- +id: canvasShareableWorkpads +slug: /playground/kibana/canvas-shareable-workpads +title: Share a Canvas Workpad on a Website +summary: How to share a static snapshot of a workpad on an external website. +date: 2021-02-18 +tags: ['kibana', 'canvas', 'share'] +related: [] +--- The Canvas Shareable Runtime is designed to render Shareable Canvas Workpads outside of Kibana in a different website or application. It uses the intermediate, "transient" state of a workpad, which is a JSON-blob state after element expressions are initially evaluated against their data sources, but before the elements are rendered to the screen. This "transient" state, therefore, has no dependency or access to ES/Kibana data, making it lightweight and portable. @@ -228,11 +205,7 @@ The `index.html` file contains a call to the `CanvasShareable` runtime. Currentl ``` -There are three workpads available, in `test/workpads`: - -- `hello.json` - A simple 'Hello, Canvas' workpad. -- `austin.json` - A workpad from an Elastic{ON} talk in Austin, TX. -- `test.json` - A couple of pages with customized CSS animations and charts. +There are three test workpads available, in `test/workpads`. ### Gathering Statistics diff --git a/x-pack/plugins/case/server/routes/api/cases/find_cases.ts b/x-pack/plugins/case/server/routes/api/cases/find_cases.ts index d04f01eb73537..bc6907f52b9eb 100644 --- a/x-pack/plugins/case/server/routes/api/cases/find_cases.ts +++ b/x-pack/plugins/case/server/routes/api/cases/find_cases.ts @@ -37,7 +37,6 @@ export function initFindCasesApi({ caseService, router, logger }: RouteDeps) { CasesFindRequestRt.decode(request.query), fold(throwErrors(Boom.badRequest), identity) ); - const queryArgs = { tags: queryParams.tags, reporters: queryParams.reporters, @@ -47,7 +46,6 @@ export function initFindCasesApi({ caseService, router, logger }: RouteDeps) { }; const caseQueries = constructQueryOptions(queryArgs); - const cases = await caseService.findCasesGroupedByID({ client, caseOptions: { ...queryParams, ...caseQueries.case }, diff --git a/x-pack/plugins/case/server/routes/api/cases/helpers.ts b/x-pack/plugins/case/server/routes/api/cases/helpers.ts index a1a7f4f9da8f5..8659ab02d6d53 100644 --- a/x-pack/plugins/case/server/routes/api/cases/helpers.ts +++ b/x-pack/plugins/case/server/routes/api/cases/helpers.ts @@ -28,7 +28,7 @@ export const addStatusFilter = ({ appendFilter, type = CASE_SAVED_OBJECT, }: { - status: CaseStatuses | undefined; + status?: CaseStatuses; appendFilter?: string; type?: string; }) => { diff --git a/x-pack/plugins/cross_cluster_replication/public/plugin.ts b/x-pack/plugins/cross_cluster_replication/public/plugin.ts index 24c9d8dae379d..7998cdbdf750b 100644 --- a/x-pack/plugins/cross_cluster_replication/public/plugin.ts +++ b/x-pack/plugins/cross_cluster_replication/public/plugin.ts @@ -73,18 +73,21 @@ export class CrossClusterReplicationPlugin implements Plugin { // NOTE: We enable the plugin by default instead of disabling it by default because this // creates a race condition that causes functional tests to fail on CI (see #66781). - licensing.license$ - .pipe(first()) - .toPromise() - .then((license) => { + Promise.all([licensing.license$.pipe(first()).toPromise(), getStartServices()]).then( + ([license, startServices]) => { const licenseStatus = license.check(PLUGIN.ID, PLUGIN.minimumLicenseType); const isLicenseOk = licenseStatus.state === 'valid'; const config = this.initializerContext.config.get(); + const capabilities = startServices[0].application.capabilities; + // remoteClusters.isUiEnabled is driven by the xpack.remote_clusters.ui.enabled setting. // The CCR UI depends upon the Remote Clusters UI (e.g. by cross-linking to it), so if // the Remote Clusters UI is disabled we can't show the CCR UI. - const isCcrUiEnabled = config.ui.enabled && remoteClusters.isUiEnabled; + const isCcrUiEnabled = + capabilities.management.data?.[MANAGEMENT_ID] && + config.ui.enabled && + remoteClusters.isUiEnabled; if (isLicenseOk && isCcrUiEnabled) { if (indexManagement) { @@ -106,7 +109,8 @@ export class CrossClusterReplicationPlugin implements Plugin { } else { ccrApp.disable(); } - }); + } + ); } public start() {} diff --git a/x-pack/plugins/encrypted_saved_objects/.eslintrc.json b/x-pack/plugins/encrypted_saved_objects/.eslintrc.json new file mode 100644 index 0000000000000..2b63a9259d220 --- /dev/null +++ b/x-pack/plugins/encrypted_saved_objects/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "rules": { + "@typescript-eslint/consistent-type-imports": 1 + } +} diff --git a/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.test.ts b/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.test.ts index cf772ab9ae21f..695dafe77d3bc 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.test.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.test.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { EncryptedSavedObjectsAuditLogger } from './audit_logger'; import { mockAuthenticatedUser } from '../../../security/common/model/authenticated_user.mock'; +import { EncryptedSavedObjectsAuditLogger } from './audit_logger'; it('properly logs audit events', () => { const mockInternalAuditLogger = { log: jest.fn() }; diff --git a/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.ts b/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.ts index 9af696abf373e..e6290e4cc4dd8 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/audit/audit_logger.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { LegacyAuditLogger, AuthenticatedUser } from '../../../security/server'; -import { SavedObjectDescriptor, descriptorToArray } from '../crypto'; +import type { AuthenticatedUser, LegacyAuditLogger } from '../../../security/server'; +import type { SavedObjectDescriptor } from '../crypto'; +import { descriptorToArray } from '../crypto'; /** * Represents all audit events the plugin can log. diff --git a/x-pack/plugins/encrypted_saved_objects/server/audit/index.mock.ts b/x-pack/plugins/encrypted_saved_objects/server/audit/index.mock.ts index e7463ae57ef95..4b8f183e4928c 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/audit/index.mock.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/audit/index.mock.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { EncryptedSavedObjectsAuditLogger } from './audit_logger'; +import type { EncryptedSavedObjectsAuditLogger } from './audit_logger'; export const encryptedSavedObjectsAuditLoggerMock = { create() { diff --git a/x-pack/plugins/encrypted_saved_objects/server/config.ts b/x-pack/plugins/encrypted_saved_objects/server/config.ts index 2bcf0e9b69511..fc86336d44836 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/config.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/config.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { schema, TypeOf } from '@kbn/config-schema'; +import type { TypeOf } from '@kbn/config-schema'; +import { schema } from '@kbn/config-schema'; export type ConfigType = TypeOf; diff --git a/x-pack/plugins/encrypted_saved_objects/server/create_migration.test.ts b/x-pack/plugins/encrypted_saved_objects/server/create_migration.test.ts index 4df51af8b16b0..548340fbb6463 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/create_migration.test.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/create_migration.test.ts @@ -5,10 +5,11 @@ * 2.0. */ -import { SavedObjectUnsanitizedDoc } from 'kibana/server'; +import type { SavedObjectUnsanitizedDoc } from 'src/core/server'; import { migrationMocks } from 'src/core/server/mocks'; -import { encryptedSavedObjectsServiceMock } from './crypto/index.mock'; + import { getCreateMigration } from './create_migration'; +import { encryptedSavedObjectsServiceMock } from './crypto/index.mock'; afterEach(() => { jest.clearAllMocks(); diff --git a/x-pack/plugins/encrypted_saved_objects/server/create_migration.ts b/x-pack/plugins/encrypted_saved_objects/server/create_migration.ts index cf5357c40fa20..beace2b17fe08 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/create_migration.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/create_migration.ts @@ -5,12 +5,13 @@ * 2.0. */ -import { - SavedObjectUnsanitizedDoc, - SavedObjectMigrationFn, +import type { SavedObjectMigrationContext, + SavedObjectMigrationFn, + SavedObjectUnsanitizedDoc, } from 'src/core/server'; -import { EncryptedSavedObjectTypeRegistration, EncryptedSavedObjectsService } from './crypto'; + +import type { EncryptedSavedObjectsService, EncryptedSavedObjectTypeRegistration } from './crypto'; import { normalizeNamespace } from './saved_objects'; type SavedObjectOptionalMigrationFn = ( diff --git a/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_object_type_definition.test.ts b/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_object_type_definition.test.ts index 0e06fcc2f6a67..a8d6327cb4230 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_object_type_definition.test.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_object_type_definition.test.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { EncryptedSavedObjectTypeRegistration } from './encrypted_saved_objects_service'; import { EncryptedSavedObjectAttributesDefinition } from './encrypted_saved_object_type_definition'; +import type { EncryptedSavedObjectTypeRegistration } from './encrypted_saved_objects_service'; it('correctly determines attribute properties', () => { const attributes = ['attr#1', 'attr#2', 'attr#3', 'attr#4']; diff --git a/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_object_type_definition.ts b/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_object_type_definition.ts index b2b6bd16c12cd..561cb2b6b3f5b 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_object_type_definition.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_object_type_definition.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { EncryptedSavedObjectTypeRegistration } from './encrypted_saved_objects_service'; +import type { EncryptedSavedObjectTypeRegistration } from './encrypted_saved_objects_service'; /** * Represents the definition of the attributes of the specific saved object that are supposed to be diff --git a/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.mocks.ts b/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.mocks.ts index d2a16ebef9ef6..d7ff27ced38c6 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.mocks.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.mocks.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { +import type { EncryptedSavedObjectsService, EncryptedSavedObjectTypeRegistration, SavedObjectDescriptor, diff --git a/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.test.ts b/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.test.ts index 7bc08d0e7b30f..5ac6467e8d78b 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.test.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.test.ts @@ -5,16 +5,17 @@ * 2.0. */ -import nodeCrypto, { Crypto } from '@elastic/node-crypto'; +import type { Crypto } from '@elastic/node-crypto'; +import nodeCrypto from '@elastic/node-crypto'; + +import { loggingSystemMock } from 'src/core/server/mocks'; import { mockAuthenticatedUser } from '../../../security/common/model/authenticated_user.mock'; -import { EncryptedSavedObjectsAuditLogger } from '../audit'; +import type { EncryptedSavedObjectsAuditLogger } from '../audit'; +import { encryptedSavedObjectsAuditLoggerMock } from '../audit/index.mock'; import { EncryptedSavedObjectsService } from './encrypted_saved_objects_service'; import { EncryptionError } from './encryption_error'; -import { loggingSystemMock } from 'src/core/server/mocks'; -import { encryptedSavedObjectsAuditLoggerMock } from '../audit/index.mock'; - function createNodeCryptMock(encryptionKey: string) { const crypto = nodeCrypto({ encryptionKey }); const nodeCryptoMock: jest.Mocked = { diff --git a/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.ts b/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.ts index 17757c9d8b2ba..652a2c8b6870e 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/crypto/encrypted_saved_objects_service.ts @@ -5,14 +5,16 @@ * 2.0. */ -import { Crypto, EncryptOutput } from '@elastic/node-crypto'; -import typeDetect from 'type-detect'; +import type { Crypto, EncryptOutput } from '@elastic/node-crypto'; import stringify from 'json-stable-stringify'; -import { Logger } from 'src/core/server'; -import { AuthenticatedUser } from '../../../security/common/model'; -import { EncryptedSavedObjectsAuditLogger } from '../audit'; -import { EncryptionError, EncryptionErrorOperation } from './encryption_error'; +import typeDetect from 'type-detect'; + +import type { Logger } from 'src/core/server'; + +import type { AuthenticatedUser } from '../../../security/common/model'; +import type { EncryptedSavedObjectsAuditLogger } from '../audit'; import { EncryptedSavedObjectAttributesDefinition } from './encrypted_saved_object_type_definition'; +import { EncryptionError, EncryptionErrorOperation } from './encryption_error'; /** * Describes the attributes to encrypt. By default, attribute values won't be exposed to end-users diff --git a/x-pack/plugins/encrypted_saved_objects/server/crypto/encryption_key_rotation_service.mocks.ts b/x-pack/plugins/encrypted_saved_objects/server/crypto/encryption_key_rotation_service.mocks.ts index 71dc7fabef612..a69154c0e7be3 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/crypto/encryption_key_rotation_service.mocks.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/crypto/encryption_key_rotation_service.mocks.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { EncryptionKeyRotationService } from './encryption_key_rotation_service'; +import type { EncryptionKeyRotationService } from './encryption_key_rotation_service'; function createEncryptionKeyRotationServiceMock() { return ({ rotate: jest.fn() } as unknown) as jest.Mocked; diff --git a/x-pack/plugins/encrypted_saved_objects/server/crypto/encryption_key_rotation_service.test.ts b/x-pack/plugins/encrypted_saved_objects/server/crypto/encryption_key_rotation_service.test.ts index 800b2b381e121..3f343f4a0e15b 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/crypto/encryption_key_rotation_service.test.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/crypto/encryption_key_rotation_service.test.ts @@ -5,22 +5,22 @@ * 2.0. */ -import { +import type { SavedObject, SavedObjectsClientContract, SavedObjectsServiceStart, -} from '../../../../../src/core/server'; -import { EncryptionError, EncryptionErrorOperation } from './encryption_error'; -import { EncryptionKeyRotationService } from './encryption_key_rotation_service'; -import { EncryptedSavedObjectsService } from './encrypted_saved_objects_service'; - +} from 'src/core/server'; import { coreMock, httpServerMock, loggingSystemMock, savedObjectsClientMock, savedObjectsTypeRegistryMock, -} from '../../../../../src/core/server/mocks'; +} from 'src/core/server/mocks'; + +import type { EncryptedSavedObjectsService } from './encrypted_saved_objects_service'; +import { EncryptionError, EncryptionErrorOperation } from './encryption_error'; +import { EncryptionKeyRotationService } from './encryption_key_rotation_service'; import { encryptedSavedObjectsServiceMock } from './index.mock'; function getMockSavedObject(savedObject?: Partial>) { diff --git a/x-pack/plugins/encrypted_saved_objects/server/crypto/encryption_key_rotation_service.ts b/x-pack/plugins/encrypted_saved_objects/server/crypto/encryption_key_rotation_service.ts index 73d304afa15c2..1a6d1173d1652 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/crypto/encryption_key_rotation_service.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/crypto/encryption_key_rotation_service.ts @@ -6,7 +6,7 @@ */ import type { PublicMethodsOf } from '@kbn/utility-types'; -import { +import type { ISavedObjectTypeRegistry, KibanaRequest, Logger, @@ -14,9 +14,10 @@ import { SavedObjectsBulkUpdateObject, StartServicesAccessor, } from 'src/core/server'; -import { AuthenticatedUser, SecurityPluginSetup } from '../../../security/server'; + +import type { AuthenticatedUser, SecurityPluginSetup } from '../../../security/server'; import { getDescriptorNamespace } from '../saved_objects/get_descriptor_namespace'; -import { EncryptedSavedObjectsService } from './encrypted_saved_objects_service'; +import type { EncryptedSavedObjectsService } from './encrypted_saved_objects_service'; import { EncryptionError } from './encryption_error'; interface EncryptionKeyRotationServiceOptions { diff --git a/x-pack/plugins/encrypted_saved_objects/server/index.ts b/x-pack/plugins/encrypted_saved_objects/server/index.ts index 53b020e5b8241..95337b8c92913 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/index.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/index.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { PluginInitializerContext } from 'src/core/server'; +import type { PluginInitializerContext } from 'src/core/server'; + import { ConfigSchema } from './config'; import { EncryptedSavedObjectsPlugin } from './plugin'; diff --git a/x-pack/plugins/encrypted_saved_objects/server/mocks.ts b/x-pack/plugins/encrypted_saved_objects/server/mocks.ts index edb55513aabf5..5f80e5bab310f 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/mocks.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/mocks.ts @@ -5,8 +5,11 @@ * 2.0. */ -import { EncryptedSavedObjectsPluginSetup, EncryptedSavedObjectsPluginStart } from './plugin'; -import { EncryptedSavedObjectsClient, EncryptedSavedObjectsClientOptions } from './saved_objects'; +import type { EncryptedSavedObjectsPluginSetup, EncryptedSavedObjectsPluginStart } from './plugin'; +import type { + EncryptedSavedObjectsClient, + EncryptedSavedObjectsClientOptions, +} from './saved_objects'; function createEncryptedSavedObjectsSetupMock( { canEncrypt }: { canEncrypt: boolean } = { canEncrypt: false } diff --git a/x-pack/plugins/encrypted_saved_objects/server/plugin.test.ts b/x-pack/plugins/encrypted_saved_objects/server/plugin.test.ts index e71332b1c5aa7..9d345c5e0af0f 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/plugin.test.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/plugin.test.ts @@ -5,11 +5,11 @@ * 2.0. */ -import { EncryptedSavedObjectsPlugin } from './plugin'; -import { ConfigSchema } from './config'; - import { coreMock } from 'src/core/server/mocks'; + import { securityMock } from '../../security/server/mocks'; +import { ConfigSchema } from './config'; +import { EncryptedSavedObjectsPlugin } from './plugin'; describe('EncryptedSavedObjects Plugin', () => { describe('setup()', () => { diff --git a/x-pack/plugins/encrypted_saved_objects/server/plugin.ts b/x-pack/plugins/encrypted_saved_objects/server/plugin.ts index c99d6bd32287d..fa1b6415d206e 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/plugin.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/plugin.ts @@ -6,19 +6,23 @@ */ import nodeCrypto from '@elastic/node-crypto'; -import type { Logger, PluginInitializerContext, CoreSetup, Plugin } from 'src/core/server'; + +import type { CoreSetup, Logger, Plugin, PluginInitializerContext } from 'src/core/server'; + import type { SecurityPluginSetup } from '../../security/server'; +import { EncryptedSavedObjectsAuditLogger } from './audit'; import type { ConfigType } from './config'; +import type { CreateEncryptedSavedObjectsMigrationFn } from './create_migration'; +import { getCreateMigration } from './create_migration'; +import type { EncryptedSavedObjectTypeRegistration } from './crypto'; import { EncryptedSavedObjectsService, - EncryptedSavedObjectTypeRegistration, EncryptionError, EncryptionKeyRotationService, } from './crypto'; -import { EncryptedSavedObjectsAuditLogger } from './audit'; -import { setupSavedObjects, ClientInstanciator } from './saved_objects'; -import { getCreateMigration, CreateEncryptedSavedObjectsMigrationFn } from './create_migration'; import { defineRoutes } from './routes'; +import type { ClientInstanciator } from './saved_objects'; +import { setupSavedObjects } from './saved_objects'; export interface PluginsSetup { security?: SecurityPluginSetup; diff --git a/x-pack/plugins/encrypted_saved_objects/server/routes/index.mock.ts b/x-pack/plugins/encrypted_saved_objects/server/routes/index.mock.ts index 32ac1617f4a7e..9c8add9da3ad3 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/routes/index.mock.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/routes/index.mock.ts @@ -5,9 +5,10 @@ * 2.0. */ -import { ConfigSchema, ConfigType } from '../config'; +import { httpServiceMock, loggingSystemMock } from 'src/core/server/mocks'; -import { httpServiceMock, loggingSystemMock } from '../../../../../src/core/server/mocks'; +import type { ConfigType } from '../config'; +import { ConfigSchema } from '../config'; import { encryptionKeyRotationServiceMock } from '../crypto/index.mock'; export const routeDefinitionParamsMock = { diff --git a/x-pack/plugins/encrypted_saved_objects/server/routes/index.ts b/x-pack/plugins/encrypted_saved_objects/server/routes/index.ts index 6cab988257ea6..680ad0be015c0 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/routes/index.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/routes/index.ts @@ -6,10 +6,10 @@ */ import type { PublicMethodsOf } from '@kbn/utility-types'; -import { IRouter, Logger } from '../../../../../src/core/server'; -import { ConfigType } from '../config'; -import { EncryptionKeyRotationService } from '../crypto'; +import type { IRouter, Logger } from 'src/core/server'; +import type { ConfigType } from '../config'; +import type { EncryptionKeyRotationService } from '../crypto'; import { defineKeyRotationRoutes } from './key_rotation'; /** diff --git a/x-pack/plugins/encrypted_saved_objects/server/routes/key_rotation.test.ts b/x-pack/plugins/encrypted_saved_objects/server/routes/key_rotation.test.ts index 0fca4b36597b2..138d111cb8f9d 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/routes/key_rotation.test.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/routes/key_rotation.test.ts @@ -6,18 +6,13 @@ */ import { Type } from '@kbn/config-schema'; -import { - IRouter, - kibanaResponseFactory, - RequestHandler, - RequestHandlerContext, - RouteConfig, -} from '../../../../../src/core/server'; -import { defineKeyRotationRoutes } from './key_rotation'; +import type { IRouter, RequestHandler, RequestHandlerContext, RouteConfig } from 'src/core/server'; +import { kibanaResponseFactory } from 'src/core/server'; +import { httpServerMock } from 'src/core/server/mocks'; -import { httpServerMock } from '../../../../../src/core/server/mocks'; +import type { EncryptionKeyRotationService } from '../crypto'; import { routeDefinitionParamsMock } from './index.mock'; -import { EncryptionKeyRotationService } from '../crypto'; +import { defineKeyRotationRoutes } from './key_rotation'; describe('Key rotation routes', () => { let router: jest.Mocked; diff --git a/x-pack/plugins/encrypted_saved_objects/server/routes/key_rotation.ts b/x-pack/plugins/encrypted_saved_objects/server/routes/key_rotation.ts index e2c63f4b6f066..2a8076d537eb4 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/routes/key_rotation.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/routes/key_rotation.ts @@ -6,7 +6,8 @@ */ import { schema } from '@kbn/config-schema'; -import { RouteDefinitionParams } from '.'; + +import type { RouteDefinitionParams } from './'; /** * The default maximum value of from + size for searches to .kibana index. Since we cannot use scroll diff --git a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.test.ts b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.test.ts index 474a283b5e3cb..76f5cb49c7f07 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.test.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.test.ts @@ -5,18 +5,19 @@ * 2.0. */ -import { EncryptionErrorOperation } from '../crypto/encryption_error'; -import { SavedObjectsClientContract } from 'src/core/server'; -import { EncryptedSavedObjectsService, EncryptionError } from '../crypto'; -import { EncryptedSavedObjectsClientWrapper } from './encrypted_saved_objects_client_wrapper'; - +import type { SavedObjectsClientContract } from 'src/core/server'; import { savedObjectsClientMock, savedObjectsTypeRegistryMock } from 'src/core/server/mocks'; + import { mockAuthenticatedUser } from '../../../security/common/model/authenticated_user.mock'; +import type { EncryptedSavedObjectsService } from '../crypto'; +import { EncryptionError } from '../crypto'; +import { EncryptionErrorOperation } from '../crypto/encryption_error'; import { encryptedSavedObjectsServiceMock } from '../crypto/index.mock'; +import { EncryptedSavedObjectsClientWrapper } from './encrypted_saved_objects_client_wrapper'; -jest.mock('../../../../../src/core/server/saved_objects/service/lib/utils', () => { +jest.mock('src/core/server/saved_objects/service/lib/utils', () => { const { SavedObjectsUtils } = jest.requireActual( - '../../../../../src/core/server/saved_objects/service/lib/utils' + 'src/core/server/saved_objects/service/lib/utils' ); return { SavedObjectsUtils: { diff --git a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.ts b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.ts index a602f3606e0a9..6b06f7e4e68e9 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/encrypted_saved_objects_client_wrapper.ts @@ -5,32 +5,33 @@ * 2.0. */ -import { +import type { + ISavedObjectTypeRegistry, SavedObject, + SavedObjectsAddToNamespacesOptions, SavedObjectsBaseOptions, SavedObjectsBulkCreateObject, SavedObjectsBulkGetObject, - SavedObjectsBulkUpdateObject, SavedObjectsBulkResponse, + SavedObjectsBulkUpdateObject, SavedObjectsBulkUpdateResponse, SavedObjectsCheckConflictsObject, SavedObjectsClientContract, SavedObjectsClosePointInTimeOptions, SavedObjectsCreateOptions, + SavedObjectsDeleteFromNamespacesOptions, SavedObjectsFindOptions, SavedObjectsFindResponse, SavedObjectsOpenPointInTimeOptions, - SavedObjectsUpdateOptions, - SavedObjectsUpdateResponse, - SavedObjectsAddToNamespacesOptions, - SavedObjectsDeleteFromNamespacesOptions, SavedObjectsRemoveReferencesToOptions, - ISavedObjectTypeRegistry, SavedObjectsRemoveReferencesToResponse, - SavedObjectsUtils, -} from '../../../../../src/core/server'; -import { AuthenticatedUser } from '../../../security/common/model'; -import { EncryptedSavedObjectsService } from '../crypto'; + SavedObjectsUpdateOptions, + SavedObjectsUpdateResponse, +} from 'src/core/server'; + +import { SavedObjectsUtils } from '../../../../../src/core/server'; +import type { AuthenticatedUser } from '../../../security/common/model'; +import type { EncryptedSavedObjectsService } from '../crypto'; import { getDescriptorNamespace } from './get_descriptor_namespace'; interface EncryptedSavedObjectsClientOptions { diff --git a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/get_descriptor_namespace.test.ts b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/get_descriptor_namespace.test.ts index 2899f044cdb9a..bb4ae1f59f02f 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/get_descriptor_namespace.test.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/get_descriptor_namespace.test.ts @@ -6,6 +6,7 @@ */ import { savedObjectsTypeRegistryMock } from 'src/core/server/mocks'; + import { getDescriptorNamespace } from './get_descriptor_namespace'; describe('getDescriptorNamespace', () => { diff --git a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/get_descriptor_namespace.ts b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/get_descriptor_namespace.ts index 0f737995e8d2a..4e01c516dc3af 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/get_descriptor_namespace.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/get_descriptor_namespace.ts @@ -5,7 +5,9 @@ * 2.0. */ -import { ISavedObjectTypeRegistry, SavedObjectsUtils } from '../../../../../src/core/server'; +import type { ISavedObjectTypeRegistry } from 'src/core/server'; + +import { SavedObjectsUtils } from '../../../../../src/core/server'; export const getDescriptorNamespace = ( typeRegistry: ISavedObjectTypeRegistry, diff --git a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.test.ts b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.test.ts index 2c29bb2bb8a9d..972292670d05f 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.test.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.test.ts @@ -5,24 +5,25 @@ * 2.0. */ -import { ClientInstanciator, setupSavedObjects } from '.'; - +import type { + ISavedObjectsRepository, + ISavedObjectTypeRegistry, + SavedObject, +} from 'src/core/server'; import { coreMock, httpServerMock, savedObjectsClientMock, savedObjectsRepositoryMock, savedObjectsTypeRegistryMock, -} from '../../../../../src/core/server/mocks'; +} from 'src/core/server/mocks'; + import { securityMock } from '../../../security/server/mocks'; +import type { EncryptedSavedObjectsService } from '../crypto'; import { encryptedSavedObjectsServiceMock } from '../crypto/index.mock'; +import type { ClientInstanciator } from './'; +import { setupSavedObjects } from './'; import { EncryptedSavedObjectsClientWrapper } from './encrypted_saved_objects_client_wrapper'; -import { - ISavedObjectsRepository, - ISavedObjectTypeRegistry, - SavedObject, -} from '../../../../../src/core/server'; -import { EncryptedSavedObjectsService } from '../crypto'; describe('#setupSavedObjects', () => { let setupContract: ClientInstanciator; diff --git a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts index 9e7c1f6592290..1268113eb19bb 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/saved_objects/index.ts @@ -6,16 +6,17 @@ */ import type { PublicMethodsOf } from '@kbn/utility-types'; -import { - StartServicesAccessor, +import type { + ISavedObjectsRepository, + ISavedObjectTypeRegistry, SavedObject, SavedObjectsBaseOptions, SavedObjectsServiceSetup, - ISavedObjectsRepository, - ISavedObjectTypeRegistry, + StartServicesAccessor, } from 'src/core/server'; -import { SecurityPluginSetup } from '../../../security/server'; -import { EncryptedSavedObjectsService } from '../crypto'; + +import type { SecurityPluginSetup } from '../../../security/server'; +import type { EncryptedSavedObjectsService } from '../crypto'; import { EncryptedSavedObjectsClientWrapper } from './encrypted_saved_objects_client_wrapper'; import { getDescriptorNamespace, normalizeNamespace } from './get_descriptor_namespace'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/constants.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/constants.ts index 401d4ccd6d117..e0e36afa8e0c4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/constants.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/constants.ts @@ -22,3 +22,25 @@ export const CREATE_AN_ENGINE_BUTTON_LABEL = i18n.translate( defaultMessage: 'Create an engine', } ); + +export const CREATE_A_META_ENGINE_BUTTON_LABEL = i18n.translate( + 'xpack.enterpriseSearch.appSearch.engines.createAMetaEngineButton.ButtonLabel', + { + defaultMessage: 'Create a meta engine', + } +); + +export const META_ENGINE_EMPTY_PROMPT_TITLE = i18n.translate( + 'xpack.enterpriseSearch.appSearch.engines.metaEngines.emptyPrompTitle', + { + defaultMessage: 'No meta engines yet', + } +); + +export const META_ENGINE_EMPTY_PROMPT_DESCRIPTION = i18n.translate( + 'xpack.enterpriseSearch.appSearch.engines.metaEngines.emptyPromptDescription', + { + defaultMessage: + 'Meta engines allow you to combine multiple engines into one searchable engine.', + } +); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.test.tsx index c25f27c81ff48..5a3f730940760 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.test.tsx @@ -12,6 +12,8 @@ import React from 'react'; import { shallow, ShallowWrapper } from 'enzyme'; +import { EuiEmptyPrompt } from '@elastic/eui'; + import { LoadingState, EmptyState } from './components'; import { EnginesTable } from './engines_table'; @@ -19,7 +21,6 @@ import { EnginesOverview } from './'; describe('EnginesOverview', () => { const values = { - hasPlatinumLicense: false, dataLoading: false, engines: [], enginesMeta: { @@ -39,6 +40,7 @@ describe('EnginesOverview', () => { }, }, metaEnginesLoading: false, + hasPlatinumLicense: false, }; const actions = { loadEngines: jest.fn(), @@ -73,7 +75,7 @@ describe('EnginesOverview', () => { const valuesWithEngines = { ...values, dataLoading: false, - engines: ['dummy-engine'], + engines: ['test-engine'], enginesMeta: { page: { current: 1, @@ -84,6 +86,7 @@ describe('EnginesOverview', () => { }; beforeEach(() => { + jest.clearAllMocks(); setMockValues(valuesWithEngines); }); @@ -102,18 +105,47 @@ describe('EnginesOverview', () => { ).toEqual('/engine_creation'); }); - describe('when on a platinum license', () => { - it('renders a 2nd meta engines table & makes a 2nd meta engines API call', async () => { + describe('when user has a platinum license', () => { + let wrapper: ShallowWrapper; + + beforeEach(() => { setMockValues({ ...valuesWithEngines, hasPlatinumLicense: true, - metaEngines: ['dummy-meta-engine'], }); - const wrapper = shallow(); + wrapper = shallow(); + }); + it('renders a 2nd meta engines table ', async () => { expect(wrapper.find(EnginesTable)).toHaveLength(2); + }); + + it('makes a 2nd meta engines call', () => { expect(actions.loadMetaEngines).toHaveBeenCalled(); }); + + it('renders a create engine button which takes users to the create meta engine page', () => { + expect( + wrapper.find('[data-test-subj="appSearchEnginesMetaEngineCreationButton"]').prop('to') + ).toEqual('/meta_engine_creation'); + }); + + it('contains an EuiEmptyPrompt that takes users to the create meta when metaEngines is empty', () => { + setMockValues({ + ...valuesWithEngines, + hasPlatinumLicense: true, + metaEngines: [], + }); + wrapper = shallow(); + const metaEnginesTable = wrapper.find(EnginesTable).last().dive(); + const emptyPrompt = metaEnginesTable.dive().find(EuiEmptyPrompt).dive(); + + expect( + emptyPrompt + .find('[data-test-subj="appSearchMetaEnginesEmptyStateCreationButton"]') + .prop('to') + ).toEqual('/meta_engine_creation'); + }); }); describe('pagination', () => { @@ -150,7 +182,7 @@ describe('EnginesOverview', () => { setMockValues({ ...valuesWithEngines, hasPlatinumLicense: true, - metaEngines: ['dummy-meta-engine'], + metaEngines: ['test-meta-engine'], }); const wrapper = shallow(); const pageEvent = { page: { index: 0 } }; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx index a26fe87365536..4cfa5d9078162 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_overview.tsx @@ -16,6 +16,7 @@ import { EuiPageContentBody, EuiTitle, EuiSpacer, + EuiEmptyPrompt, } from '@elastic/eui'; import { FlashMessages } from '../../../shared/flash_messages'; @@ -24,12 +25,19 @@ import { LicensingLogic } from '../../../shared/licensing'; import { EuiButtonTo } from '../../../shared/react_router_helpers'; import { convertMetaToPagination, handlePageChange } from '../../../shared/table_pagination'; import { SendAppSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; -import { ENGINE_CREATION_PATH } from '../../routes'; +import { ENGINE_CREATION_PATH, META_ENGINE_CREATION_PATH } from '../../routes'; import { EngineIcon } from './assets/engine_icon'; import { MetaEngineIcon } from './assets/meta_engine_icon'; import { EnginesOverviewHeader, LoadingState, EmptyState } from './components'; -import { CREATE_AN_ENGINE_BUTTON_LABEL, ENGINES_TITLE, META_ENGINES_TITLE } from './constants'; +import { + CREATE_AN_ENGINE_BUTTON_LABEL, + CREATE_A_META_ENGINE_BUTTON_LABEL, + ENGINES_TITLE, + META_ENGINE_EMPTY_PROMPT_DESCRIPTION, + META_ENGINE_EMPTY_PROMPT_TITLE, + META_ENGINES_TITLE, +} from './constants'; import { EnginesLogic } from './engines_logic'; import { EnginesTable } from './engines_table'; @@ -37,6 +45,7 @@ import './engines_overview.scss'; export const EnginesOverview: React.FC = () => { const { hasPlatinumLicense } = useValues(LicensingLogic); + const { dataLoading, engines, @@ -46,6 +55,7 @@ export const EnginesOverview: React.FC = () => { metaEnginesMeta, metaEnginesLoading, } = useValues(EnginesLogic); + const { loadEngines, loadMetaEngines, onEnginesPagination, onMetaEnginesPagination } = useActions( EnginesLogic ); @@ -100,15 +110,27 @@ export const EnginesOverview: React.FC = () => { /> - {metaEngines.length > 0 && ( + {hasPlatinumLicense && ( <> - -

- {META_ENGINES_TITLE} -

-
+ + +

+ {META_ENGINES_TITLE} +

+
+
+ + + {CREATE_A_META_ENGINE_BUTTON_LABEL} + +
{ ...convertMetaToPagination(metaEnginesMeta), hidePerPageOptions: true, }} + noItemsMessage={ + {META_ENGINE_EMPTY_PROMPT_TITLE}} + body={

{META_ENGINE_EMPTY_PROMPT_DESCRIPTION}

} + actions={ + + {CREATE_A_META_ENGINE_BUTTON_LABEL} + + } + /> + } onChange={handlePageChange(onMetaEnginesPagination)} />
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.test.tsx index f8ad9bc6b2bc3..51c65e1478d13 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.test.tsx @@ -88,6 +88,13 @@ describe('EnginesTable', () => { }); }); + describe('noItemsMessage', () => { + it('passes the noItemsMessage prop', () => { + const wrapper = mountWithIntl(); + expect(wrapper.find(EuiBasicTable).prop('noItemsMessage')).toEqual('No items.'); + }); + }); + describe('language field', () => { it('renders language when available', () => { const wrapper = mountWithIntl( diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.tsx index fe61ba8cbcc43..f542d12318244 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/engines_table.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React from 'react'; +import React, { ReactNode } from 'react'; import { useActions } from 'kea'; @@ -24,6 +24,7 @@ import { EngineDetails } from '../engine/types'; interface EnginesTableProps { items: EngineDetails[]; loading: boolean; + noItemsMessage?: ReactNode; pagination: { pageIndex: number; pageSize: number; @@ -36,6 +37,7 @@ interface EnginesTableProps { export const EnginesTable: React.FC = ({ items, loading, + noItemsMessage, pagination, onChange, }) => { @@ -148,6 +150,7 @@ export const EnginesTable: React.FC = ({ loading={loading} pagination={pagination} onChange={onChange} + noItemsMessage={noItemsMessage} /> ); }; 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 new file mode 100644 index 0000000000000..aff5942d497a8 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/constants.tsx @@ -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 React from 'react'; + +import { EuiLink } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { DOCS_PREFIX } from '../../routes'; + +export const DEFAULT_LANGUAGE = 'Universal'; + +export const META_ENGINE_CREATION_TITLE = i18n.translate( + 'xpack.enterpriseSearch.appSearch.metaEngineCreation.title', + { + defaultMessage: 'Create a meta engine', + } +); + +export const META_ENGINE_CREATION_FORM_TITLE = i18n.translate( + 'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.title', + { + defaultMessage: 'Name your meta engine', + } +); + +export const META_ENGINE_CREATION_FORM_SUBMIT_BUTTON_LABEL = i18n.translate( + 'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.submitButton.buttonLabel', + { + defaultMessage: 'Create meta engine', + } +); + +export const META_ENGINE_CREATION_FORM_META_ENGINE_DESCRIPTION = i18n.translate( + 'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.metaEngineDescription', + { + defaultMessage: + 'Meta engines allow you to combine multiple engines into one searchable engine.', + } +); + +export const META_ENGINE_CREATION_FORM_DOCUMENTATION_LINK = i18n.translate( + 'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.documentationLink', + { + defaultMessage: 'Read the documentation', + } +); + +export const META_ENGINE_CREATION_FORM_DOCUMENTATION_DESCRIPTION = ( + + {META_ENGINE_CREATION_FORM_DOCUMENTATION_LINK} + + ), + }} + /> +); + +export const META_ENGINE_CREATION_FORM_ENGINE_NAME_LABEL = i18n.translate( + 'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.engineName.label', + { + defaultMessage: 'Meta engine name', + } +); + +export const ALLOWED_CHARS_NOTE = i18n.translate( + 'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.engineName.allowedCharactersHelpText', + { + defaultMessage: 'Meta engine names can only contain lowercase letters, numbers, and hyphens', + } +); + +export const SANITIZED_NAME_NOTE = i18n.translate( + 'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.engineName.sanitizedNameHelpText', + { + defaultMessage: 'Your meta engine will be named', + } +); + +export const META_ENGINE_CREATION_FORM_ENGINE_NAME_PLACEHOLDER = i18n.translate( + 'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.engineName.placeholder', + { + defaultMessage: 'i.e., my-meta-engine', + } +); + +export const META_ENGINE_CREATION_FORM_ENGINE_SOURCE_ENGINES_LABEL = i18n.translate( + 'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.sourceEngines.label', + { + defaultMessage: 'Add source engines to this meta engine', + } +); + +export const META_ENGINE_CREATION_FORM_MAX_SOURCE_ENGINES_WARNING_TITLE = ( + maxEnginesPerMetaEngine: number +) => + i18n.translate( + 'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.sourceEngines.maxSourceEnginesWarningTitle', + { + defaultMessage: 'Meta engines have a limit of {maxEnginesPerMetaEngine} source engines', + values: { maxEnginesPerMetaEngine }, + } + ); + +export const META_ENGINE_CREATION_SUCCESS_MESSAGE = i18n.translate( + 'xpack.enterpriseSearch.appSearch.metaEngineCreation.successMessage', + { + defaultMessage: 'Successfully created meta engine.', + } +); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/index.ts new file mode 100644 index 0000000000000..2d33322a84fc6 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/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 { MetaEngineCreation } from './meta_engine_creation'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation.test.tsx new file mode 100644 index 0000000000000..51ccc7b83b1fc --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation.test.tsx @@ -0,0 +1,187 @@ +/* + * 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 '../../../__mocks__/shallow_useeffect.mock'; +import { setMockActions, setMockValues } from '../../../__mocks__'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { EuiCallOut } from '@elastic/eui'; + +import { MetaEngineCreation } from './'; + +const DEFAULT_VALUES = { + // MetaEngineLogic + name: 'test-meta-engine', + rawName: 'test-meta-engine', + indexedEngineNames: [], + selectedIndexedEngineNames: ['one'], + // AppLogic + configuredLimits: { engine: { maxEnginesPerMetaEngine: 10 } }, +}; + +const MOCK_ACTIONS = { + setRawName: jest.fn(), + setSelectedIndexedEngineNames: jest.fn(), + fetchIndexedEngineNames: jest.fn(), + submitEngine: jest.fn(), +}; + +describe('MetaEngineCreation', () => { + beforeEach(() => { + jest.clearAllMocks(); + setMockValues(DEFAULT_VALUES); + setMockActions(MOCK_ACTIONS); + }); + + it('renders and calls fetchIndexedEngineNames', () => { + const wrapper = shallow(); + expect(wrapper.find('[data-test-subj="MetaEngineCreation"]')).toHaveLength(1); + expect(MOCK_ACTIONS.fetchIndexedEngineNames).toHaveBeenCalledTimes(1); + }); + + describe('MetaEngineCreationNameInput', () => { + it('uses rawName as its value', () => { + const wrapper = shallow(); + expect( + wrapper + .find('[data-test-subj="MetaEngineCreationNameInput"]') + .render() + .find('input') // as far as I can tell I can't include this input in the .find() two lines above + .attr('value') + ).toEqual('test-meta-engine'); + }); + + it('EngineCreationForm calls submitEngine on form submit', () => { + const wrapper = shallow(); + const simulatedEvent = { + preventDefault: jest.fn(), + }; + wrapper.find('[data-test-subj="MetaEngineCreationForm"]').simulate('submit', simulatedEvent); + + expect(MOCK_ACTIONS.submitEngine).toHaveBeenCalledTimes(1); + }); + + it('MetaEngineCreationNameInput calls setRawName on change', () => { + const wrapper = shallow(); + const simulatedEvent = { + currentTarget: { value: 'new-raw-name' }, + }; + wrapper + .find('[data-test-subj="MetaEngineCreationNameInput"]') + .simulate('change', simulatedEvent); + expect(MOCK_ACTIONS.setRawName).toHaveBeenCalledWith('new-raw-name'); + }); + }); + + describe('EngineCreationNameFormRow', () => { + it('renders sanitized name helptext when the raw name is being sanitized', () => { + setMockValues({ + ...DEFAULT_VALUES, + name: 'name-with-special-characters', + rawName: 'Name__With#$&*%Special--Characters', + }); + + const wrapper = shallow(); + const formRow = wrapper.find('[data-test-subj="MetaEngineCreationNameFormRow"]').dive(); + + expect(formRow.contains('Your meta engine will be named')).toBeTruthy(); + }); + + it('renders allowed character helptext when rawName and sanitizedName match', () => { + setMockValues({ + ...DEFAULT_VALUES, + name: 'name-without-special-characters', + rawName: 'name-without-special-characters', + }); + + const wrapper = shallow(); + const formRow = wrapper.find('[data-test-subj="MetaEngineCreationNameFormRow"]').dive(); + + expect( + formRow.contains( + 'Meta engine names can only contain lowercase letters, numbers, and hyphens' + ) + ).toBeTruthy(); + }); + }); + + it('MetaEngineCreationSourceEnginesInput calls calls setSelectedIndexedEngines on change', () => { + const wrapper = shallow(); + + wrapper + .find('[data-test-subj="MetaEngineCreationSourceEnginesInput"]') + .simulate('change', [{ label: 'foo', value: 'foo' }]); + + expect(MOCK_ACTIONS.setSelectedIndexedEngineNames).toHaveBeenCalledWith(['foo']); + }); + + it('renders a warning callout when user has selected too many engines', () => { + setMockValues({ + ...DEFAULT_VALUES, + ...{ + selectedIndexedEngineNames: ['one', 'two', 'three'], + configuredLimits: { engine: { maxEnginesPerMetaEngine: 2 } }, + }, + }); + const wrapper = shallow(); + + expect(wrapper.find(EuiCallOut).prop('title')).toContain('Meta engines have a limit of'); + }); + + describe('NewMetaEngineSubmitButton', () => { + it('is enabled for a valid submission', () => { + const wrapper = shallow(); + const submitButton = wrapper.find('[data-test-subj="NewMetaEngineSubmitButton"]'); + + expect(submitButton.prop('disabled')).toEqual(false); + }); + + it('is disabled when name is empty', () => { + setMockValues({ + ...DEFAULT_VALUES, + ...{ + name: '', + rawName: '', + }, + }); + const wrapper = shallow(); + const submitButton = wrapper.find('[data-test-subj="NewMetaEngineSubmitButton"]'); + + expect(submitButton.prop('disabled')).toEqual(true); + }); + + it('is disabled when user has selected no engines', () => { + setMockValues({ + ...DEFAULT_VALUES, + ...{ + selectedIndexedEngineNames: [], + }, + }); + const wrapper = shallow(); + const submitButton = wrapper.find('[data-test-subj="NewMetaEngineSubmitButton"]'); + + expect(submitButton.prop('disabled')).toEqual(true); + }); + + it('is disabled when user has selected too many engines', () => { + setMockValues({ + ...DEFAULT_VALUES, + ...{ + selectedIndexedEngineNames: ['one', 'two', 'three'], + configuredLimits: { engine: { maxEnginesPerMetaEngine: 2 } }, + }, + }); + const wrapper = shallow(); + const submitButton = wrapper.find('[data-test-subj="NewMetaEngineSubmitButton"]'); + + expect(submitButton.prop('disabled')).toEqual(true); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation.tsx new file mode 100644 index 0000000000000..3757bbb533e57 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation.tsx @@ -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 React, { useEffect } from 'react'; + +import { useActions, useValues } from 'kea'; + +import { + EuiCallOut, + EuiComboBox, + EuiComboBoxOptionOption, + EuiForm, + EuiFlexGroup, + EuiFormRow, + EuiFlexItem, + EuiFieldText, + EuiPageContent, + EuiPageHeader, + EuiPageHeaderSection, + EuiSpacer, + EuiText, + EuiTitle, + EuiButton, +} from '@elastic/eui'; + +import { FlashMessages } from '../../../shared/flash_messages'; +import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; +import { AppLogic } from '../../app_logic'; + +import { + ALLOWED_CHARS_NOTE, + META_ENGINE_CREATION_FORM_DOCUMENTATION_DESCRIPTION, + META_ENGINE_CREATION_FORM_ENGINE_NAME_LABEL, + META_ENGINE_CREATION_FORM_ENGINE_NAME_PLACEHOLDER, + META_ENGINE_CREATION_FORM_ENGINE_SOURCE_ENGINES_LABEL, + META_ENGINE_CREATION_FORM_MAX_SOURCE_ENGINES_WARNING_TITLE, + META_ENGINE_CREATION_FORM_META_ENGINE_DESCRIPTION, + META_ENGINE_CREATION_FORM_SUBMIT_BUTTON_LABEL, + META_ENGINE_CREATION_FORM_TITLE, + META_ENGINE_CREATION_TITLE, + SANITIZED_NAME_NOTE, +} from './constants'; +import { MetaEngineCreationLogic } from './meta_engine_creation_logic'; + +const engineNameToComboBoxOption = (engineName: string): EuiComboBoxOptionOption => ({ + label: engineName, +}); + +const comboBoxOptionToEngineName = (option: EuiComboBoxOptionOption): string => + option.label; + +export const MetaEngineCreation: React.FC = () => { + const { + configuredLimits: { + engine: { maxEnginesPerMetaEngine } = { maxEnginesPerMetaEngine: Infinity }, + }, + } = useValues(AppLogic); + + const { + fetchIndexedEngineNames, + setRawName, + setSelectedIndexedEngineNames, + submitEngine, + } = useActions(MetaEngineCreationLogic); + + const { rawName, name, indexedEngineNames, selectedIndexedEngineNames } = useValues( + MetaEngineCreationLogic + ); + + useEffect(() => { + fetchIndexedEngineNames(); + }, []); + + return ( +
+ + + + +

{META_ENGINE_CREATION_TITLE}

+
+ {META_ENGINE_CREATION_FORM_META_ENGINE_DESCRIPTION} + {META_ENGINE_CREATION_FORM_DOCUMENTATION_DESCRIPTION} +
+
+ + + { + e.preventDefault(); + submitEngine(); + }} + > + + {META_ENGINE_CREATION_FORM_TITLE} + + + + + 0 && rawName !== name ? ( + <> + {SANITIZED_NAME_NOTE} {name} + + ) : ( + ALLOWED_CHARS_NOTE + ) + } + fullWidth + > + setRawName(event.currentTarget.value)} + fullWidth + data-test-subj="MetaEngineCreationNameInput" + placeholder={META_ENGINE_CREATION_FORM_ENGINE_NAME_PLACEHOLDER} + autoFocus + /> + + + + + + { + setSelectedIndexedEngineNames(options.map(comboBoxOptionToEngineName)); + }} + /> + + + {selectedIndexedEngineNames.length > maxEnginesPerMetaEngine && ( + + )} + + maxEnginesPerMetaEngine + } + type="submit" + data-test-subj="NewMetaEngineSubmitButton" + fill + color="secondary" + > + {META_ENGINE_CREATION_FORM_SUBMIT_BUTTON_LABEL} + + + +
+ ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation_logic.test.ts new file mode 100644 index 0000000000000..6ffe7034584a1 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation_logic.test.ts @@ -0,0 +1,175 @@ +/* + * 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 { + LogicMounter, + mockHttpValues, + mockFlashMessageHelpers, + mockKibanaValues, +} from '../../../__mocks__'; + +import { nextTick } from '@kbn/test/jest'; + +import { MetaEngineCreationLogic } from './meta_engine_creation_logic'; + +describe('MetaEngineCreationLogic', () => { + const { mount } = new LogicMounter(MetaEngineCreationLogic); + const { http } = mockHttpValues; + const { navigateToUrl } = mockKibanaValues; + const { setQueuedSuccessMessage, flashAPIErrors } = mockFlashMessageHelpers; + + const DEFAULT_VALUES = { + indexedEngineNames: [], + name: '', + rawName: '', + selectedIndexedEngineNames: [], + }; + + it('has expected default values', () => { + mount(); + expect(MetaEngineCreationLogic.values).toEqual(DEFAULT_VALUES); + }); + + describe('actions', () => { + describe('setRawName', () => { + beforeAll(() => { + jest.clearAllMocks(); + mount(); + MetaEngineCreationLogic.actions.setRawName('Name__With#$&*%Special--Characters'); + }); + + it('should set rawName to provided value', () => { + expect(MetaEngineCreationLogic.values.rawName).toEqual( + 'Name__With#$&*%Special--Characters' + ); + }); + + it('should set name to a sanitized value', () => { + expect(MetaEngineCreationLogic.values.name).toEqual('name-with-special-characters'); + }); + }); + + describe('setIndexedEngineNames', () => { + it('should set indexedEngineNames to provided value', () => { + mount(); + MetaEngineCreationLogic.actions.setIndexedEngineNames(['first', 'middle', 'last']); + expect(MetaEngineCreationLogic.values.indexedEngineNames).toEqual([ + 'first', + 'middle', + 'last', + ]); + }); + }); + + describe('setSelectedIndexedEngineNames', () => { + it('should set selectedIndexedEngineNames to provided value', () => { + mount(); + MetaEngineCreationLogic.actions.setSelectedIndexedEngineNames(['one', 'two', 'three']); + expect(MetaEngineCreationLogic.values.selectedIndexedEngineNames).toEqual([ + 'one', + 'two', + 'three', + ]); + }); + }); + }); + + describe('listeners', () => { + describe('fetchIndexedEngineNames', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('calls flashAPIErrors on API Error', async () => { + http.get.mockReturnValueOnce(Promise.reject()); + MetaEngineCreationLogic.actions.fetchIndexedEngineNames(); + await nextTick(); + expect(flashAPIErrors).toHaveBeenCalledTimes(1); + }); + + it('calls onEngineCreationSuccess on valid submission', async () => { + jest.spyOn(MetaEngineCreationLogic.actions, 'setIndexedEngineNames'); + http.get.mockReturnValueOnce( + Promise.resolve({ results: [{ name: 'foo' }], meta: { page: { total_pages: 1 } } }) + ); + MetaEngineCreationLogic.actions.fetchIndexedEngineNames(); + await nextTick(); + expect(MetaEngineCreationLogic.actions.setIndexedEngineNames).toHaveBeenCalledWith(['foo']); + }); + + it('if there are remaining pages it should call fetchIndexedEngineNames recursively with an incremented page', async () => { + jest.spyOn(MetaEngineCreationLogic.actions, 'fetchIndexedEngineNames'); + http.get.mockReturnValueOnce( + Promise.resolve({ results: [{ name: 'foo' }], meta: { page: { total_pages: 2 } } }) + ); + MetaEngineCreationLogic.actions.fetchIndexedEngineNames(); + await nextTick(); + expect(MetaEngineCreationLogic.actions.fetchIndexedEngineNames).toHaveBeenCalledWith(2); + }); + + it('if there are no remaining pages it should end without calling recursively', async () => { + jest.spyOn(MetaEngineCreationLogic.actions, 'fetchIndexedEngineNames'); + http.get.mockReturnValueOnce( + Promise.resolve({ results: [{ name: 'foo' }], meta: { page: { total_pages: 1 } } }) + ); + MetaEngineCreationLogic.actions.fetchIndexedEngineNames(); + await nextTick(); + expect(MetaEngineCreationLogic.actions.fetchIndexedEngineNames).toHaveBeenCalledTimes(1); // it's one time cause we called it two lines above + }); + }); + + describe('onEngineCreationSuccess', () => { + beforeAll(() => { + jest.clearAllMocks(); + mount({ language: 'English', rawName: 'test' }); + MetaEngineCreationLogic.actions.onEngineCreationSuccess(); + }); + + it('should set a success message', () => { + expect(setQueuedSuccessMessage).toHaveBeenCalledWith('Successfully created meta engine.'); + }); + + it('should navigate the user to the engine page', () => { + expect(navigateToUrl).toHaveBeenCalledWith('/engines/test'); + }); + }); + + describe('submitEngine', () => { + beforeAll(() => { + jest.clearAllMocks(); + mount({ rawName: 'test', selectedIndexedEngineNames: ['foo'] }); + }); + + it('POSTS to /api/app_search/engines', () => { + const body = JSON.stringify({ + name: 'test', + type: 'meta', + source_engines: ['foo'], + }); + MetaEngineCreationLogic.actions.submitEngine(); + expect(http.post).toHaveBeenCalledWith('/api/app_search/engines', { body }); + }); + + it('calls onEngineCreationSuccess on valid submission', async () => { + jest.spyOn(MetaEngineCreationLogic.actions, 'onEngineCreationSuccess'); + http.post.mockReturnValueOnce(Promise.resolve({})); + MetaEngineCreationLogic.actions.submitEngine(); + await nextTick(); + expect(MetaEngineCreationLogic.actions.onEngineCreationSuccess).toHaveBeenCalledTimes(1); + }); + + it('calls flashAPIErrors on API Error', async () => { + jest.spyOn(MetaEngineCreationLogic.actions, 'setIndexedEngineNames'); + http.post.mockReturnValueOnce(Promise.reject()); + MetaEngineCreationLogic.actions.submitEngine(); + await nextTick(); + expect(flashAPIErrors).toHaveBeenCalledTimes(1); + expect(MetaEngineCreationLogic.actions.setIndexedEngineNames).not.toHaveBeenCalled(); + }); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation_logic.ts new file mode 100644 index 0000000000000..d94eb82a49c0e --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation_logic.ts @@ -0,0 +1,127 @@ +/* + * 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 { generatePath } from 'react-router-dom'; + +import { kea, MakeLogicType } from 'kea'; + +import { Meta } from '../../../../../common/types'; +import { DEFAULT_META } from '../../../shared/constants'; +import { flashAPIErrors, setQueuedSuccessMessage } from '../../../shared/flash_messages'; +import { HttpLogic } from '../../../shared/http'; +import { KibanaLogic } from '../../../shared/kibana'; +import { ENGINE_PATH } from '../../routes'; +import { formatApiName } from '../../utils/format_api_name'; +import { EngineDetails } from '../engine/types'; + +import { META_ENGINE_CREATION_SUCCESS_MESSAGE } from './constants'; + +interface MetaEngineCreationValues { + indexedEngineNames: string[]; + name: string; + rawName: string; + selectedIndexedEngineNames: string[]; +} + +interface MetaEngineCreationActions { + fetchIndexedEngineNames(page?: number): { page: number }; + onEngineCreationSuccess(): void; + setIndexedEngineNames( + indexedEngineNames: MetaEngineCreationValues['indexedEngineNames'] + ): { indexedEngineNames: MetaEngineCreationValues['indexedEngineNames'] }; + setRawName(rawName: string): { rawName: string }; + setSelectedIndexedEngineNames( + selectedIndexedEngineNames: MetaEngineCreationValues['selectedIndexedEngineNames'] + ): { selectedIndexedEngineNames: MetaEngineCreationValues['selectedIndexedEngineNames'] }; + submitEngine(): void; +} + +export const MetaEngineCreationLogic = kea< + MakeLogicType +>({ + path: ['enterprise_search', 'app_search', 'meta_engine_creation_logic'], + actions: { + fetchIndexedEngineNames: (page = DEFAULT_META.page.current) => ({ page }), + onEngineCreationSuccess: true, + setIndexedEngineNames: (indexedEngineNames) => ({ indexedEngineNames }), + setRawName: (rawName) => ({ rawName }), + setSelectedIndexedEngineNames: (selectedIndexedEngineNames) => ({ selectedIndexedEngineNames }), + submitEngine: () => null, + }, + reducers: { + indexedEngineNames: [ + [], + { + setIndexedEngineNames: (_, { indexedEngineNames }) => indexedEngineNames, + }, + ], + rawName: [ + '', + { + setRawName: (_, { rawName }) => rawName, + }, + ], + selectedIndexedEngineNames: [ + [], + { + setSelectedIndexedEngineNames: (_, { selectedIndexedEngineNames }) => + selectedIndexedEngineNames, + }, + ], + }, + selectors: ({ selectors }) => ({ + name: [() => [selectors.rawName], (rawName: string) => formatApiName(rawName)], + }), + listeners: ({ values, actions }) => ({ + fetchIndexedEngineNames: async ({ page }) => { + const { http } = HttpLogic.values; + let response: { results: EngineDetails[]; meta: Meta } | undefined; + + try { + response = await http.get('/api/app_search/engines', { + query: { type: 'indexed', 'page[current]': page, 'page[size]': DEFAULT_META.page.size }, + }); + } catch (e) { + flashAPIErrors(e); + } + + if (response) { + const engineNames = response.results.map((result) => result.name); + actions.setIndexedEngineNames([...values.indexedEngineNames, ...engineNames]); + + if (page < response.meta.page.total_pages) { + actions.fetchIndexedEngineNames(page + 1); + } + } + }, + onEngineCreationSuccess: () => { + const { name } = values; + const { navigateToUrl } = KibanaLogic.values; + const enginePath = generatePath(ENGINE_PATH, { engineName: name }); + + setQueuedSuccessMessage(META_ENGINE_CREATION_SUCCESS_MESSAGE); + navigateToUrl(enginePath); + }, + submitEngine: async () => { + const { http } = HttpLogic.values; + const { name, selectedIndexedEngineNames } = values; + + const body = JSON.stringify({ + name, + type: 'meta', + source_engines: selectedIndexedEngineNames, + }); + + try { + await http.post('/api/app_search/engines', { body }); + actions.onEngineCreationSuccess(); + } catch (e) { + flashAPIErrors(e); + } + }, + }), +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx index 5150a4996eb84..a1c845a10a47c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx @@ -21,6 +21,7 @@ import { EngineRouter } from './components/engine'; import { EngineCreation } from './components/engine_creation'; import { EnginesOverview } from './components/engines'; import { ErrorConnecting } from './components/error_connecting'; +import { MetaEngineCreation } from './components/meta_engine_creation'; import { SetupGuide } from './components/setup_guide'; import { AppSearch, AppSearchUnconfigured, AppSearchConfigured, AppSearchNav } from './'; @@ -117,6 +118,22 @@ describe('AppSearchConfigured', () => { expect(wrapper.find(EngineCreation)).toHaveLength(0); }); }); + + describe('canManageMetaEngines', () => { + it('renders MetaEngineCreation when user canManageMetaEngines is true', () => { + setMockValues({ myRole: { canManageMetaEngines: true } }); + const wrapper = shallow(); + + expect(wrapper.find(MetaEngineCreation)).toHaveLength(1); + }); + + it('does not render MetaEngineCreation when user canManageMetaEngines is false', () => { + setMockValues({ myRole: { canManageMetaEngines: false } }); + const wrapper = shallow(); + + expect(wrapper.find(MetaEngineCreation)).toHaveLength(0); + }); + }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx index 40dfc1426e402..ec64cb2f10eb0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx @@ -25,6 +25,7 @@ import { EngineCreation } from './components/engine_creation'; import { EnginesOverview, ENGINES_TITLE } from './components/engines'; import { ErrorConnecting } from './components/error_connecting'; import { Library } from './components/library'; +import { MetaEngineCreation } from './components/meta_engine_creation'; import { ROLE_MAPPINGS_TITLE } from './components/role_mappings'; import { Settings, SETTINGS_TITLE } from './components/settings'; import { SetupGuide } from './components/setup_guide'; @@ -38,6 +39,7 @@ import { ENGINES_PATH, ENGINE_PATH, LIBRARY_PATH, + META_ENGINE_CREATION_PATH, } from './routes'; export const AppSearch: React.FC = (props) => { @@ -60,7 +62,7 @@ export const AppSearchConfigured: React.FC = (props) => { const { initializeAppData } = useActions(AppLogic); const { hasInitialized, - myRole: { canManageEngines }, + myRole: { canManageEngines, canManageMetaEngines }, } = useValues(AppLogic); const { errorConnecting, readOnlyMode } = useValues(HttpLogic); @@ -106,6 +108,11 @@ export const AppSearchConfigured: React.FC = (props) => { )} + {canManageMetaEngines && ( + + + + )} 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 6fe9be083405e..907a27c8660d2 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 @@ -40,6 +40,7 @@ export const ENGINE_REINDEX_JOB_PATH = `${ENGINE_PATH}/reindex-job/:activeReinde export const ENGINE_CRAWLER_PATH = `${ENGINE_PATH}/crawler`; // TODO: Crawler sub-pages +export const META_ENGINE_CREATION_PATH = '/meta_engine_creation'; export const META_ENGINE_SOURCE_ENGINES_PATH = `${ENGINE_PATH}/engines`; export const ENGINE_RELEVANCE_TUNING_PATH = `${ENGINE_PATH}/relevance_tuning`; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/setup_guide/setup_guide.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/setup_guide/setup_guide.tsx index c59742d7ccbea..c9dbe3882ba72 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/setup_guide/setup_guide.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/setup_guide/setup_guide.tsx @@ -12,6 +12,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { ENTERPRISE_SEARCH_PLUGIN } from '../../../../../common/constants'; +import { DOCS_PREFIX } from '../../../app_search/routes'; import { SetEnterpriseSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; import { SetupGuideLayout, SETUP_GUIDE_TITLE } from '../../../shared/setup_guide'; import { SendEnterpriseSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; @@ -22,8 +23,8 @@ export const SetupGuide: React.FC = () => ( diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/nav.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/nav.tsx index 16722c1554ddf..f2edc04a5661c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/nav.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/layout/nav.tsx @@ -10,7 +10,6 @@ import React from 'react'; import { EuiSpacer } from '@elastic/eui'; import { WORKPLACE_SEARCH_PLUGIN } from '../../../../../common/constants'; -import { getWorkplaceSearchUrl } from '../../../shared/enterprise_search_url'; import { SideNav, SideNavLink } from '../../../shared/layout'; import { NAV } from '../../constants'; import { @@ -43,9 +42,7 @@ export const WorkplaceSearchNav: React.FC = ({ {NAV.GROUPS} - - {NAV.ROLE_MAPPINGS} - + {NAV.ROLE_MAPPINGS} {NAV.SECURITY} {NAV.SETTINGS} diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx index 3cd1a3bd136b8..656c93053e22b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx @@ -26,6 +26,7 @@ import { SOURCES_PATH, PERSONAL_SOURCES_PATH, ORG_SETTINGS_PATH, + ROLE_MAPPINGS_PATH, SECURITY_PATH, } from './routes'; import { SourcesRouter } from './views/content_sources'; @@ -36,6 +37,7 @@ import { GroupsRouter } from './views/groups'; import { GroupSubNav } from './views/groups/components/group_sub_nav'; import { Overview } from './views/overview'; import { Overview as OverviewMVP } from './views/overview_mvp'; +import { RoleMappingsRouter } from './views/role_mappings'; import { Security } from './views/security'; import { SettingsRouter } from './views/settings'; import { SettingsSubNav } from './views/settings/components/settings_sub_nav'; @@ -111,6 +113,11 @@ export const WorkplaceSearchConfigured: React.FC = (props) => { + + } restrictWidth readOnlyMode={readOnlyMode}> + + + } restrictWidth readOnlyMode={readOnlyMode}> diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/routes.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/routes.ts index 462f89abd6143..50f6596a860c5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/routes.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/routes.ts @@ -133,3 +133,4 @@ export const getReindexJobRoute = ( isOrganization: boolean ) => getSourcesPath(generatePath(REINDEX_JOB_PATH, { sourceId, activeReindexJobId }), isOrganization); +export const getRoleMappingPath = (roleId: string) => generatePath(ROLE_MAPPING_PATH, { roleId }); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/types.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/types.ts index 44e0fd5b6f287..79fe6dc8c92cb 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/types.ts +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/types.ts @@ -22,6 +22,8 @@ export interface Meta { page: MetaPage; } +export type Role = 'admin' | 'user'; + export interface Group { id: string; name: string; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/constants.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/constants.ts new file mode 100644 index 0000000000000..5930f7862cd83 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/constants.ts @@ -0,0 +1,105 @@ +/* + * 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 DELETE_ROLE_MAPPING_MESSAGE = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.deleteRoleMappingButtonMessage', + { + defaultMessage: + 'Are you sure you want to permanently delete this mapping? This action is not reversible and some users might lose access.', + } +); + +export const DEFAULT_GROUP_NAME = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.defaultGroupName', + { + defaultMessage: 'Default', + } +); + +export const ADMIN_ROLE_TYPE_DESCRIPTION = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.adminRoleTypeDescription', + { + defaultMessage: + 'Admins have complete access to all organization-wide settings, including content source, group and user management functionality.', + } +); + +export const USER_ROLE_TYPE_DESCRIPTION = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.userRoleTypeDescription', + { + defaultMessage: + "Users' feature access is limited to search interfaces and personal settings management.", + } +); + +export const ROLE_SELECTOR_DISABLED_TEXT = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.roleSelectorDisabledText', + { + defaultMessage: + 'You need at least one admin role mapping before you can create a user role mapping.', + } +); + +export const GROUP_ASSIGNMENT_TITLE = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.groupAssignmentTitle', + { + defaultMessage: 'Group assignment', + } +); + +export const GROUP_ASSIGNMENT_INVALID_ERROR = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.groupAssignmentInvalidError', + { + defaultMessage: 'At least one assigned group is required.', + } +); + +export const GROUP_ASSIGNMENT_ALL_GROUPS_LABEL = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.groupAssignmentAllGroupsLabel', + { + defaultMessage: 'Include in all groups, including future groups', + } +); + +export const EMPTY_ROLE_MAPPINGS_TITLE = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.emptyRoleMappingsTitle', + { + defaultMessage: 'No role mappings yet', + } +); + +export const EMPTY_ROLE_MAPPINGS_BODY = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.emptyRoleMappingsBody', + { + defaultMessage: + 'New team members are assigned the admin role by default. An admin can access everything. Create a new role to override the default.', + } +); + +export const ROLE_MAPPINGS_TABLE_HEADER = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.roleMappingsTableHeader', + { + defaultMessage: 'Group Access', + } +); + +export const ROLE_MAPPINGS_TITLE = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.roleMappingsTitle', + { + defaultMessage: 'Users & roles', + } +); + +export const ROLE_MAPPINGS_DESCRIPTION = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.roleMappingsDescription', + { + defaultMessage: + 'Define role mappings for elasticsearch-native and elasticsearch-saml authentication.', + } +); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/index.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/index.ts new file mode 100644 index 0000000000000..ce4b1de6e399d --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/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 { RoleMappingsRouter } from './role_mappings_router'; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mapping.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mapping.test.tsx new file mode 100644 index 0000000000000..4742b741c9640 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mapping.test.tsx @@ -0,0 +1,121 @@ +/* + * 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 '../../../__mocks__/shallow_useeffect.mock'; +import { setMockActions, setMockValues } from '../../../__mocks__'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { EuiCheckbox } from '@elastic/eui'; + +import { Loading } from '../../../shared/loading'; +import { + AttributeSelector, + DeleteMappingCallout, + RoleSelector, +} from '../../../shared/role_mapping'; +import { wsRoleMapping } from '../../../shared/role_mapping/__mocks__/roles'; + +import { RoleMapping } from './role_mapping'; + +describe('RoleMapping', () => { + const initializeRoleMappings = jest.fn(); + const initializeRoleMapping = jest.fn(); + const handleSaveMapping = jest.fn(); + const handleGroupSelectionChange = jest.fn(); + const handleAllGroupsSelectionChange = jest.fn(); + const handleAttributeValueChange = jest.fn(); + const handleAttributeSelectorChange = jest.fn(); + const handleDeleteMapping = jest.fn(); + const handleRoleChange = jest.fn(); + const handleAuthProviderChange = jest.fn(); + const resetState = jest.fn(); + const groups = [ + { + name: 'Group 1', + id: 'g1', + }, + { + name: 'Group 2', + id: 'g2', + }, + ]; + const mockValues = { + attributes: [], + elasticsearchRoles: [], + dataLoading: false, + roleType: 'admin', + roleMappings: [wsRoleMapping], + attributeValue: '', + attributeName: 'username', + availableGroups: groups, + selectedGroups: new Set(), + includeInAllGroups: false, + availableAuthProviders: [], + multipleAuthProvidersConfig: true, + selectedAuthProviders: [], + }; + + beforeEach(() => { + setMockActions({ + initializeRoleMappings, + initializeRoleMapping, + handleSaveMapping, + handleGroupSelectionChange, + handleAllGroupsSelectionChange, + handleAttributeValueChange, + handleAttributeSelectorChange, + handleDeleteMapping, + handleRoleChange, + handleAuthProviderChange, + resetState, + }); + setMockValues(mockValues); + }); + + it('renders', () => { + const wrapper = shallow(); + + expect(wrapper.find(AttributeSelector)).toHaveLength(1); + expect(wrapper.find(RoleSelector)).toHaveLength(2); + }); + + it('returns Loading when loading', () => { + setMockValues({ ...mockValues, dataLoading: true }); + const wrapper = shallow(); + + expect(wrapper.find(Loading)).toHaveLength(1); + }); + + it('hides DeleteMappingCallout for new mapping', () => { + const wrapper = shallow(); + + expect(wrapper.find(DeleteMappingCallout)).toHaveLength(0); + }); + + it('handles group checkbox click', () => { + const wrapper = shallow(); + wrapper + .find(EuiCheckbox) + .first() + .simulate('change', { target: { checked: true } }); + + expect(handleGroupSelectionChange).toHaveBeenCalledWith(groups[0].id, true); + }); + + it('handles all groups checkbox click', () => { + const wrapper = shallow(); + wrapper + .find(EuiCheckbox) + .last() + .simulate('change', { target: { checked: true } }); + + expect(handleAllGroupsSelectionChange).toHaveBeenCalledWith(true); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mapping.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mapping.tsx new file mode 100644 index 0000000000000..b2911bbcc64c2 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mapping.tsx @@ -0,0 +1,216 @@ +/* + * 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 } from 'react'; + +import { useParams } from 'react-router-dom'; + +import { useActions, useValues } from 'kea'; + +import { + EuiButton, + EuiCheckbox, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiPanel, + EuiSpacer, + EuiTitle, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { FlashMessages } from '../../../shared/flash_messages'; +import { Loading } from '../../../shared/loading'; +import { + AttributeSelector, + DeleteMappingCallout, + RoleSelector, +} from '../../../shared/role_mapping'; +import { ROLE_LABEL } from '../../../shared/role_mapping/constants'; +import { ViewContentHeader } from '../../components/shared/view_content_header'; +import { Role } from '../../types'; + +import { + ADMIN_ROLE_TYPE_DESCRIPTION, + USER_ROLE_TYPE_DESCRIPTION, + ROLE_SELECTOR_DISABLED_TEXT, + GROUP_ASSIGNMENT_TITLE, + GROUP_ASSIGNMENT_INVALID_ERROR, + GROUP_ASSIGNMENT_ALL_GROUPS_LABEL, +} from './constants'; + +import { RoleMappingsLogic } from './role_mappings_logic'; + +interface RoleType { + type: Role; + description: string; +} + +const roleTypes = [ + { + type: 'admin', + description: ADMIN_ROLE_TYPE_DESCRIPTION, + }, + { + type: 'user', + description: USER_ROLE_TYPE_DESCRIPTION, + }, +] as RoleType[]; + +interface RoleMappingProps { + isNew?: boolean; +} + +export const RoleMapping: React.FC = ({ isNew }) => { + const { roleId } = useParams() as { roleId: string }; + const { + initializeRoleMappings, + initializeRoleMapping, + handleSaveMapping, + handleGroupSelectionChange, + handleAllGroupsSelectionChange, + handleAttributeValueChange, + handleAttributeSelectorChange, + handleDeleteMapping, + handleRoleChange, + handleAuthProviderChange, + resetState, + } = useActions(RoleMappingsLogic); + + const { + attributes, + elasticsearchRoles, + dataLoading, + roleType, + roleMappings, + attributeValue, + attributeName, + availableGroups, + selectedGroups, + includeInAllGroups, + availableAuthProviders, + multipleAuthProvidersConfig, + selectedAuthProviders, + } = useValues(RoleMappingsLogic); + + useEffect(() => { + initializeRoleMappings(); + initializeRoleMapping(roleId); + return resetState; + }, [roleId]); + + if (dataLoading) return ; + + const hasGroupAssignment = selectedGroups.size > 0 || includeInAllGroups; + + const SAVE_ROLE_MAPPING_LABEL = i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.roleMapping.saveRoleMappingButtonMessage', + { + defaultMessage: '{operation} role mapping', + values: { operation: isNew ? 'Save' : 'Update' }, + } + ); + + const saveRoleMappingButton = ( + + {SAVE_ROLE_MAPPING_LABEL} + + ); + + const hasAdminRoleMapping = roleMappings.some( + ({ roleType: roleMappingRoleType }: { roleType: string }) => + roleMappingRoleType === ('admin' as string) + ); + + return ( + <> + + +
+ + + + + + + +

{ROLE_LABEL}

+
+ + {roleTypes.map(({ type, description }) => ( + + ))} +
+
+ + + +

{GROUP_ASSIGNMENT_TITLE}

+
+ +
+ + <> + {availableGroups.map(({ id, name }) => ( + { + handleGroupSelectionChange(id, e.target.checked); + }} + label={name} + disabled={includeInAllGroups} + /> + ))} + + { + handleAllGroupsSelectionChange(e.target.checked); + }} + label={GROUP_ASSIGNMENT_ALL_GROUPS_LABEL} + /> + + +
+
+
+
+ + {!isNew && } +
+ + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings.test.tsx new file mode 100644 index 0000000000000..c6da903e20912 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings.test.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 '../../../__mocks__/shallow_useeffect.mock'; +import { setMockActions, setMockValues } from '../../../__mocks__'; + +import React from 'react'; + +import { shallow } from 'enzyme'; + +import { EuiEmptyPrompt } from '@elastic/eui'; + +import { Loading } from '../../../shared/loading'; +import { RoleMappingsTable } from '../../../shared/role_mapping'; +import { wsRoleMapping } from '../../../shared/role_mapping/__mocks__/roles'; + +import { RoleMappings } from './role_mappings'; + +describe('RoleMappings', () => { + const initializeRoleMappings = jest.fn(); + const mockValues = { + roleMappings: [wsRoleMapping], + dataLoading: false, + multipleAuthProvidersConfig: false, + }; + + beforeEach(() => { + setMockActions({ + initializeRoleMappings, + }); + setMockValues(mockValues); + }); + + it('renders', () => { + const wrapper = shallow(); + + expect(wrapper.find(RoleMappingsTable)).toHaveLength(1); + }); + + it('returns Loading when loading', () => { + setMockValues({ ...mockValues, dataLoading: true }); + const wrapper = shallow(); + + expect(wrapper.find(Loading)).toHaveLength(1); + }); + + it('renders empty state', () => { + setMockValues({ ...mockValues, roleMappings: [] }); + const wrapper = shallow(); + + expect(wrapper.find(EuiEmptyPrompt)).toHaveLength(1); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings.tsx new file mode 100644 index 0000000000000..e47b2646459df --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useEffect } from 'react'; + +import { useActions, useValues } from 'kea'; + +import { EuiEmptyPrompt } from '@elastic/eui'; + +import { FlashMessages } from '../../../shared/flash_messages'; +import { Loading } from '../../../shared/loading'; +import { AddRoleMappingButton, RoleMappingsTable } from '../../../shared/role_mapping'; +import { ViewContentHeader } from '../../components/shared/view_content_header'; +import { getRoleMappingPath, ROLE_MAPPING_NEW_PATH } from '../../routes'; + +import { + EMPTY_ROLE_MAPPINGS_TITLE, + EMPTY_ROLE_MAPPINGS_BODY, + ROLE_MAPPINGS_TABLE_HEADER, + ROLE_MAPPINGS_TITLE, + ROLE_MAPPINGS_DESCRIPTION, +} from './constants'; + +import { RoleMappingsLogic } from './role_mappings_logic'; + +export const RoleMappings: React.FC = () => { + const { initializeRoleMappings } = useActions(RoleMappingsLogic); + + const { roleMappings, dataLoading, multipleAuthProvidersConfig } = useValues(RoleMappingsLogic); + + useEffect(() => { + initializeRoleMappings(); + }, []); + + if (dataLoading) return ; + + const addMappingButton = ; + const emptyPrompt = ( + {EMPTY_ROLE_MAPPINGS_TITLE}} + body={

{EMPTY_ROLE_MAPPINGS_BODY}

} + actions={addMappingButton} + /> + ); + const roleMappingsTable = ( + + ); + + return ( + <> + +
+ + {roleMappings.length === 0 ? emptyPrompt : roleMappingsTable} +
+ + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_logic.test.ts new file mode 100644 index 0000000000000..a9526d9450993 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_logic.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 { mockFlashMessageHelpers, mockHttpValues, mockKibanaValues } from '../../../__mocks__'; +import { LogicMounter } from '../../../__mocks__/kea.mock'; + +import { groups } from '../../__mocks__/groups.mock'; + +import { nextTick } from '@kbn/test/jest'; + +import { wsRoleMapping } from '../../../shared/role_mapping/__mocks__/roles'; +import { ANY_AUTH_PROVIDER } from '../../../shared/role_mapping/constants'; + +import { RoleMappingsLogic } from './role_mappings_logic'; + +describe('RoleMappingsLogic', () => { + const { http } = mockHttpValues; + const { navigateToUrl } = mockKibanaValues; + const { clearFlashMessages, flashAPIErrors } = mockFlashMessageHelpers; + const { mount } = new LogicMounter(RoleMappingsLogic); + const defaultValues = { + attributes: [], + availableAuthProviders: [], + elasticsearchRoles: [], + roleMapping: null, + roleMappings: [], + roleType: 'admin', + attributeValue: '', + attributeName: 'username', + dataLoading: true, + multipleAuthProvidersConfig: false, + availableGroups: [], + selectedGroups: new Set(), + includeInAllGroups: false, + selectedAuthProviders: [ANY_AUTH_PROVIDER], + }; + const roleGroup = { + id: '123', + name: 'Role Group', + }; + const defaultGroup = { + id: '124', + name: 'Default', + }; + + const mappingsServerProps = { multipleAuthProvidersConfig: true, roleMappings: [wsRoleMapping] }; + const mappingServerProps = { + attributes: [], + authProviders: [], + availableGroups: [roleGroup, defaultGroup], + elasticsearchRoles: [], + multipleAuthProvidersConfig: false, + roleMapping: wsRoleMapping, + }; + + beforeEach(() => { + jest.clearAllMocks(); + mount(); + }); + + it('has expected default values', () => { + expect(RoleMappingsLogic.values).toEqual(defaultValues); + }); + + describe('actions', () => { + it('setRoleMappingsData', () => { + RoleMappingsLogic.actions.setRoleMappingsData(mappingsServerProps); + + expect(RoleMappingsLogic.values.roleMappings).toEqual([wsRoleMapping]); + expect(RoleMappingsLogic.values.dataLoading).toEqual(false); + expect(RoleMappingsLogic.values.multipleAuthProvidersConfig).toEqual(true); + }); + + describe('setRoleMappingData', () => { + it('sets data correctly', () => { + RoleMappingsLogic.actions.setRoleMappingData(mappingServerProps); + + expect(RoleMappingsLogic.values.roleMapping).toEqual(wsRoleMapping); + expect(RoleMappingsLogic.values.dataLoading).toEqual(false); + expect(RoleMappingsLogic.values.attributes).toEqual(mappingServerProps.attributes); + expect(RoleMappingsLogic.values.availableGroups).toEqual( + mappingServerProps.availableGroups + ); + expect(RoleMappingsLogic.values.includeInAllGroups).toEqual(true); + expect(RoleMappingsLogic.values.elasticsearchRoles).toEqual( + mappingServerProps.elasticsearchRoles + ); + expect(RoleMappingsLogic.values.selectedGroups).toEqual( + new Set([wsRoleMapping.groups[0].id]) + ); + }); + + it('sets default group with new role mapping', () => { + RoleMappingsLogic.actions.setRoleMappingData({ + ...mappingServerProps, + roleMapping: undefined, + }); + + expect(RoleMappingsLogic.values.selectedGroups).toEqual(new Set([defaultGroup.id])); + }); + }); + + it('handleRoleChange', () => { + RoleMappingsLogic.actions.handleRoleChange('user'); + + expect(RoleMappingsLogic.values.roleType).toEqual('user'); + }); + + it('handleGroupSelectionChange', () => { + const group = wsRoleMapping.groups[0]; + const otherGroup = groups[0]; + RoleMappingsLogic.actions.setRoleMappingData({ + ...mappingServerProps, + roleMapping: { + ...wsRoleMapping, + groups: [group, otherGroup], + }, + }); + + RoleMappingsLogic.actions.handleGroupSelectionChange(otherGroup.id, true); + expect(RoleMappingsLogic.values.selectedGroups).toEqual(new Set([group.id, otherGroup.id])); + + RoleMappingsLogic.actions.handleGroupSelectionChange(otherGroup.id, false); + expect(RoleMappingsLogic.values.selectedGroups).toEqual(new Set([group.id])); + }); + + it('handleAllGroupsSelectionChange', () => { + RoleMappingsLogic.actions.handleAllGroupsSelectionChange(true); + + expect(RoleMappingsLogic.values.includeInAllGroups).toEqual(true); + }); + + describe('handleAttributeSelectorChange', () => { + const elasticsearchRoles = ['foo', 'bar']; + + it('sets values correctly', () => { + RoleMappingsLogic.actions.setRoleMappingData({ + ...mappingServerProps, + elasticsearchRoles, + }); + RoleMappingsLogic.actions.handleAttributeSelectorChange('role', elasticsearchRoles[0]); + + expect(RoleMappingsLogic.values.attributeValue).toEqual(elasticsearchRoles[0]); + expect(RoleMappingsLogic.values.attributeName).toEqual('role'); + }); + + it('correctly handles "role" fallback', () => { + RoleMappingsLogic.actions.handleAttributeSelectorChange('username', elasticsearchRoles[0]); + + expect(RoleMappingsLogic.values.attributeValue).toEqual(''); + }); + }); + + it('handleAttributeValueChange', () => { + RoleMappingsLogic.actions.handleAttributeValueChange('changed_value'); + + expect(RoleMappingsLogic.values.attributeValue).toEqual('changed_value'); + }); + + describe('handleAuthProviderChange', () => { + beforeEach(() => { + RoleMappingsLogic.actions.setRoleMappingData({ + ...mappingServerProps, + roleMapping: { + ...wsRoleMapping, + authProvider: ['foo'], + }, + }); + }); + const providers = ['bar', 'baz']; + const providerWithAny = [ANY_AUTH_PROVIDER, providers[1]]; + it('handles empty state', () => { + RoleMappingsLogic.actions.handleAuthProviderChange([]); + + expect(RoleMappingsLogic.values.selectedAuthProviders).toEqual([ANY_AUTH_PROVIDER]); + }); + + it('handles single value', () => { + RoleMappingsLogic.actions.handleAuthProviderChange([providers[0]]); + + expect(RoleMappingsLogic.values.selectedAuthProviders).toEqual([providers[0]]); + }); + + it('handles multiple values', () => { + RoleMappingsLogic.actions.handleAuthProviderChange(providers); + + expect(RoleMappingsLogic.values.selectedAuthProviders).toEqual(providers); + }); + + it('handles "any" auth in previous state', () => { + RoleMappingsLogic.actions.setRoleMappingData({ + ...mappingServerProps, + roleMapping: { + ...wsRoleMapping, + authProvider: [ANY_AUTH_PROVIDER], + }, + }); + RoleMappingsLogic.actions.handleAuthProviderChange(providerWithAny); + + expect(RoleMappingsLogic.values.selectedAuthProviders).toEqual([providers[1]]); + }); + + it('handles catch-all state', () => { + RoleMappingsLogic.actions.handleAuthProviderChange(providerWithAny); + + expect(RoleMappingsLogic.values.selectedAuthProviders).toEqual([ANY_AUTH_PROVIDER]); + }); + }); + + it('resetState', () => { + RoleMappingsLogic.actions.setRoleMappingsData(mappingsServerProps); + RoleMappingsLogic.actions.setRoleMappingData(mappingServerProps); + RoleMappingsLogic.actions.resetState(); + + expect(RoleMappingsLogic.values.dataLoading).toEqual(true); + expect(RoleMappingsLogic.values.roleMappings).toEqual([]); + expect(RoleMappingsLogic.values.roleMapping).toEqual(null); + expect(RoleMappingsLogic.values.attributeValue).toEqual(''); + expect(RoleMappingsLogic.values.attributeName).toEqual('username'); + expect(clearFlashMessages).toHaveBeenCalled(); + }); + }); + + describe('listeners', () => { + describe('initializeRoleMappings', () => { + it('calls API and sets values', async () => { + const setRoleMappingsDataSpy = jest.spyOn(RoleMappingsLogic.actions, 'setRoleMappingsData'); + http.get.mockReturnValue(Promise.resolve(mappingsServerProps)); + RoleMappingsLogic.actions.initializeRoleMappings(); + + expect(http.get).toHaveBeenCalledWith('/api/workplace_search/org/role_mappings'); + await nextTick(); + expect(setRoleMappingsDataSpy).toHaveBeenCalledWith(mappingsServerProps); + }); + + it('handles error', async () => { + http.get.mockReturnValue(Promise.reject('this is an error')); + RoleMappingsLogic.actions.initializeRoleMappings(); + await nextTick(); + + expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); + }); + }); + + describe('initializeRoleMapping', () => { + it('calls API and sets values for new mapping', async () => { + const setRoleMappingDataSpy = jest.spyOn(RoleMappingsLogic.actions, 'setRoleMappingData'); + http.get.mockReturnValue(Promise.resolve(mappingServerProps)); + RoleMappingsLogic.actions.initializeRoleMapping(); + + expect(http.get).toHaveBeenCalledWith('/api/workplace_search/org/role_mappings/new'); + await nextTick(); + expect(setRoleMappingDataSpy).toHaveBeenCalledWith(mappingServerProps); + }); + + it('calls API and sets values for existing mapping', async () => { + const setRoleMappingDataSpy = jest.spyOn(RoleMappingsLogic.actions, 'setRoleMappingData'); + http.get.mockReturnValue(Promise.resolve(mappingServerProps)); + RoleMappingsLogic.actions.initializeRoleMapping('123'); + + expect(http.get).toHaveBeenCalledWith('/api/workplace_search/org/role_mappings/123'); + await nextTick(); + expect(setRoleMappingDataSpy).toHaveBeenCalledWith(mappingServerProps); + }); + + it('handles error', async () => { + http.get.mockReturnValue(Promise.reject('this is an error')); + RoleMappingsLogic.actions.initializeRoleMapping(); + await nextTick(); + + expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); + }); + + it('redirects when there is a 404 status', async () => { + http.get.mockReturnValue(Promise.reject({ status: 404 })); + RoleMappingsLogic.actions.initializeRoleMapping(); + await nextTick(); + + expect(navigateToUrl).toHaveBeenCalled(); + }); + }); + + describe('handleSaveMapping', () => { + it('calls API and navigates when new mapping', async () => { + RoleMappingsLogic.actions.setRoleMappingsData(mappingsServerProps); + + http.post.mockReturnValue(Promise.resolve(mappingServerProps)); + RoleMappingsLogic.actions.handleSaveMapping(); + + expect(http.post).toHaveBeenCalledWith('/api/workplace_search/org/role_mappings', { + body: JSON.stringify({ + rules: { + username: '', + }, + roleType: 'admin', + groups: [], + allGroups: false, + authProvider: [ANY_AUTH_PROVIDER], + }), + }); + await nextTick(); + + expect(navigateToUrl).toHaveBeenCalled(); + }); + + it('calls API and navigates when existing mapping', async () => { + RoleMappingsLogic.actions.setRoleMappingData(mappingServerProps); + + http.put.mockReturnValue(Promise.resolve(mappingServerProps)); + RoleMappingsLogic.actions.handleSaveMapping(); + + expect(http.put).toHaveBeenCalledWith( + `/api/workplace_search/org/role_mappings/${wsRoleMapping.id}`, + { + body: JSON.stringify({ + rules: { + username: 'user', + }, + roleType: 'admin', + groups: [], + allGroups: true, + authProvider: [ANY_AUTH_PROVIDER, 'other_auth'], + }), + } + ); + await nextTick(); + + expect(navigateToUrl).toHaveBeenCalled(); + }); + + it('handles error', async () => { + http.post.mockReturnValue(Promise.reject('this is an error')); + RoleMappingsLogic.actions.handleSaveMapping(); + await nextTick(); + + expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); + }); + }); + + describe('handleDeleteMapping', () => { + let confirmSpy: any; + + beforeEach(() => { + confirmSpy = jest.spyOn(window, 'confirm'); + confirmSpy.mockImplementation(jest.fn(() => true)); + }); + + afterEach(() => { + confirmSpy.mockRestore(); + }); + + it('returns when no mapping', () => { + RoleMappingsLogic.actions.handleDeleteMapping(); + + expect(http.delete).not.toHaveBeenCalled(); + }); + + it('calls API and navigates', async () => { + RoleMappingsLogic.actions.setRoleMappingData(mappingServerProps); + http.delete.mockReturnValue(Promise.resolve({})); + RoleMappingsLogic.actions.handleDeleteMapping(); + + expect(http.delete).toHaveBeenCalledWith( + `/api/workplace_search/org/role_mappings/${wsRoleMapping.id}` + ); + await nextTick(); + + expect(navigateToUrl).toHaveBeenCalled(); + }); + + it('handles error', async () => { + RoleMappingsLogic.actions.setRoleMappingData(mappingServerProps); + http.delete.mockReturnValue(Promise.reject('this is an error')); + RoleMappingsLogic.actions.handleDeleteMapping(); + await nextTick(); + + expect(flashAPIErrors).toHaveBeenCalledWith('this is an error'); + }); + + it('will do nothing if not confirmed', async () => { + RoleMappingsLogic.actions.setRoleMappingData(mappingServerProps); + window.confirm = () => false; + RoleMappingsLogic.actions.handleDeleteMapping(); + + expect(http.delete).not.toHaveBeenCalled(); + await nextTick(); + }); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_logic.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_logic.ts new file mode 100644 index 0000000000000..6fc3867d7ab1e --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_logic.ts @@ -0,0 +1,311 @@ +/* + * 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 { kea, MakeLogicType } from 'kea'; + +import { clearFlashMessages, flashAPIErrors } from '../../../shared/flash_messages'; +import { HttpLogic } from '../../../shared/http'; +import { KibanaLogic } from '../../../shared/kibana'; +import { AttributeName } from '../../../shared/role_mapping/attribute_selector'; +import { ANY_AUTH_PROVIDER } from '../../../shared/role_mapping/constants'; +import { ROLE_MAPPINGS_PATH } from '../../routes'; +import { RoleGroup, WSRoleMapping, Role } from '../../types'; + +import { DELETE_ROLE_MAPPING_MESSAGE, DEFAULT_GROUP_NAME } from './constants'; + +interface RoleMappingsServerDetails { + multipleAuthProvidersConfig: boolean; + roleMappings: WSRoleMapping[]; +} + +interface RoleMappingServerDetails { + attributes: string[]; + authProviders: string[]; + availableGroups: RoleGroup[]; + elasticsearchRoles: string[]; + multipleAuthProvidersConfig: boolean; + roleMapping?: WSRoleMapping; +} + +interface RoleMappingsActions { + setRoleMappingsData(data: RoleMappingsServerDetails): RoleMappingsServerDetails; + setRoleMappingData(data: RoleMappingServerDetails): RoleMappingServerDetails; + handleRoleChange(roleType: Role): { roleType: Role }; + handleAllGroupsSelectionChange(selected: boolean): { selected: boolean }; + handleAttributeSelectorChange( + value: AttributeName, + firstElasticsearchRole: string + ): { value: AttributeName; firstElasticsearchRole: string }; + handleAttributeValueChange(value: string): { value: string }; + handleGroupSelectionChange( + groupId: string, + selected: boolean + ): { groupId: string; selected: boolean }; + handleAuthProviderChange(value: string[]): { value: string[] }; + resetState(): void; + initializeRoleMapping(roleId?: string): { roleId?: string }; + handleSaveMapping(): void; + handleDeleteMapping(): void; + initializeRoleMappings(): void; +} + +interface RoleMappingsValues { + attributes: string[]; + availableAuthProviders: string[]; + elasticsearchRoles: string[]; + roleMapping: WSRoleMapping | null; + roleMappings: WSRoleMapping[]; + roleType: Role; + attributeValue: string; + attributeName: AttributeName; + dataLoading: boolean; + multipleAuthProvidersConfig: boolean; + availableGroups: RoleGroup[]; + selectedGroups: Set; + includeInAllGroups: boolean; + selectedAuthProviders: string[]; +} + +const getFirstAttributeName = (roleMapping: WSRoleMapping): AttributeName => + Object.entries(roleMapping.rules)[0][0] as AttributeName; +const getFirstAttributeValue = (roleMapping: WSRoleMapping): string => + Object.entries(roleMapping.rules)[0][1] as string; + +export const RoleMappingsLogic = kea>({ + actions: { + setRoleMappingsData: (data: RoleMappingsServerDetails) => data, + setRoleMappingData: (data: RoleMappingServerDetails) => data, + handleRoleChange: (roleType: Role) => ({ roleType }), + handleGroupSelectionChange: (groupId: string, selected: boolean) => ({ groupId, selected }), + handleAllGroupsSelectionChange: (selected: boolean) => ({ selected }), + handleAttributeSelectorChange: (value: string, firstElasticsearchRole: string) => ({ + value, + firstElasticsearchRole, + }), + handleAttributeValueChange: (value: string) => ({ value }), + handleAuthProviderChange: (value: string[]) => ({ value }), + resetState: () => true, + initializeRoleMapping: (roleId?: string) => ({ roleId }), + handleSaveMapping: () => true, + handleDeleteMapping: () => true, + initializeRoleMappings: () => true, + }, + reducers: { + dataLoading: [ + true, + { + setRoleMappingsData: () => false, + setRoleMappingData: () => false, + resetState: () => true, + }, + ], + roleMappings: [ + [], + { + setRoleMappingsData: (_, { roleMappings }) => roleMappings, + resetState: () => [], + }, + ], + attributes: [ + [], + { + setRoleMappingData: (_, { attributes }) => attributes, + }, + ], + availableGroups: [ + [], + { + setRoleMappingData: (_, { availableGroups }) => availableGroups, + }, + ], + selectedGroups: [ + new Set(), + { + setRoleMappingData: (_, { roleMapping, availableGroups }) => + roleMapping + ? new Set(roleMapping.groups.map((group) => group.id)) + : new Set( + availableGroups + .filter((group) => group.name === DEFAULT_GROUP_NAME) + .map((group) => group.id) + ), + handleGroupSelectionChange: (groups, { groupId, selected }) => { + const newSelectedGroupNames = new Set(groups as Set); + if (selected) { + newSelectedGroupNames.add(groupId); + } else { + newSelectedGroupNames.delete(groupId); + } + return newSelectedGroupNames; + }, + }, + ], + includeInAllGroups: [ + false, + { + setRoleMappingData: (_, { roleMapping }) => (roleMapping ? roleMapping.allGroups : false), + handleAllGroupsSelectionChange: (_, { selected }) => selected, + }, + ], + elasticsearchRoles: [ + [], + { + setRoleMappingData: (_, { elasticsearchRoles }) => elasticsearchRoles, + }, + ], + roleMapping: [ + null, + { + setRoleMappingData: (_, { roleMapping }) => roleMapping || null, + resetState: () => null, + }, + ], + roleType: [ + 'admin', + { + setRoleMappingData: (_, { roleMapping }) => + roleMapping ? (roleMapping.roleType as Role) : 'admin', + handleRoleChange: (_, { roleType }) => roleType, + }, + ], + attributeValue: [ + '', + { + setRoleMappingData: (_, { roleMapping }) => + roleMapping ? getFirstAttributeValue(roleMapping) : '', + handleAttributeSelectorChange: (_, { value, firstElasticsearchRole }) => + value === 'role' ? firstElasticsearchRole : '', + handleAttributeValueChange: (_, { value }) => value, + resetState: () => '', + }, + ], + attributeName: [ + 'username', + { + setRoleMappingData: (_, { roleMapping }) => + roleMapping ? getFirstAttributeName(roleMapping) : 'username', + handleAttributeSelectorChange: (_, { value }) => value, + resetState: () => 'username', + }, + ], + availableAuthProviders: [ + [], + { + setRoleMappingData: (_, { authProviders }) => authProviders, + }, + ], + multipleAuthProvidersConfig: [ + false, + { + setRoleMappingsData: (_, { multipleAuthProvidersConfig }) => multipleAuthProvidersConfig, + setRoleMappingData: (_, { multipleAuthProvidersConfig }) => multipleAuthProvidersConfig, + resetState: () => false, + }, + ], + selectedAuthProviders: [ + [ANY_AUTH_PROVIDER], + { + handleAuthProviderChange: (previous, { value }) => { + const previouslyContainedAny = previous.includes(ANY_AUTH_PROVIDER); + const newSelectionsContainAny = value.includes(ANY_AUTH_PROVIDER); + + if (value.length < 1) return [ANY_AUTH_PROVIDER]; + if (value.length === 1) return value; + if (!newSelectionsContainAny) return value; + if (previouslyContainedAny) return value.filter((v) => v !== ANY_AUTH_PROVIDER); + return [ANY_AUTH_PROVIDER]; + }, + setRoleMappingData: (_, { roleMapping }) => + roleMapping ? roleMapping.authProvider : [ANY_AUTH_PROVIDER], + }, + ], + }, + listeners: ({ actions, values }) => ({ + initializeRoleMappings: async () => { + const { http } = HttpLogic.values; + const route = '/api/workplace_search/org/role_mappings'; + + try { + const response = await http.get(route); + actions.setRoleMappingsData(response); + } catch (e) { + flashAPIErrors(e); + } + }, + initializeRoleMapping: async ({ roleId }) => { + const { http } = HttpLogic.values; + const { navigateToUrl } = KibanaLogic.values; + const route = roleId + ? `/api/workplace_search/org/role_mappings/${roleId}` + : '/api/workplace_search/org/role_mappings/new'; + + try { + const response = await http.get(route); + actions.setRoleMappingData(response); + } catch (e) { + if (e.status === 404) { + navigateToUrl(ROLE_MAPPINGS_PATH); + } + flashAPIErrors(e); + } + }, + handleDeleteMapping: async () => { + const { http } = HttpLogic.values; + const { navigateToUrl } = KibanaLogic.values; + const { roleMapping } = values; + if (!roleMapping) { + return; + } + const route = `/api/workplace_search/org/role_mappings/${roleMapping.id}`; + if (window.confirm(DELETE_ROLE_MAPPING_MESSAGE)) { + try { + await http.delete(route); + navigateToUrl(ROLE_MAPPINGS_PATH); + } catch (e) { + flashAPIErrors(e); + } + } + }, + handleSaveMapping: async () => { + const { http } = HttpLogic.values; + const { navigateToUrl } = KibanaLogic.values; + const { + attributeName, + attributeValue, + roleType, + roleMapping, + selectedGroups, + includeInAllGroups, + selectedAuthProviders, + } = values; + + const body = JSON.stringify({ + rules: { + [attributeName]: attributeValue, + }, + roleType, + groups: includeInAllGroups ? [] : Array.from(selectedGroups), + allGroups: includeInAllGroups, + authProvider: selectedAuthProviders, + }); + + const request = !roleMapping + ? http.post('/api/workplace_search/org/role_mappings', { body }) + : http.put(`/api/workplace_search/org/role_mappings/${roleMapping.id}`, { body }); + + try { + await request; + navigateToUrl(ROLE_MAPPINGS_PATH); + } catch (e) { + flashAPIErrors(e); + } + }, + resetState: () => { + clearFlashMessages(); + }, + }), +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_router.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_router.test.tsx new file mode 100644 index 0000000000000..e9fc40ba1dbb4 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_router.test.tsx @@ -0,0 +1,26 @@ +/* + * 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 { Route, Switch } from 'react-router-dom'; + +import { shallow } from 'enzyme'; + +import { RoleMapping } from './role_mapping'; +import { RoleMappings } from './role_mappings'; +import { RoleMappingsRouter } from './role_mappings_router'; + +describe('RoleMappingsRouter', () => { + it('renders', () => { + const wrapper = shallow(); + + expect(wrapper.find(Switch)).toHaveLength(1); + expect(wrapper.find(Route)).toHaveLength(3); + expect(wrapper.find(RoleMapping)).toHaveLength(2); + expect(wrapper.find(RoleMappings)).toHaveLength(1); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_router.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_router.tsx new file mode 100644 index 0000000000000..fa5ab12c8afc0 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/role_mappings/role_mappings_router.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 { Route, Switch } from 'react-router-dom'; + +import { SetWorkplaceSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; +import { NAV } from '../../constants'; +import { ROLE_MAPPING_NEW_PATH, ROLE_MAPPING_PATH, ROLE_MAPPINGS_PATH } from '../../routes'; + +import { RoleMapping } from './role_mapping'; +import { RoleMappings } from './role_mappings'; + +export const RoleMappingsRouter: React.FC = () => ( + <> + + + + + + + + + + + + + +); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/setup_guide/setup_guide.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/setup_guide/setup_guide.tsx index 13191f42bc566..58a80914fd3c5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/setup_guide/setup_guide.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/setup_guide/setup_guide.tsx @@ -26,8 +26,8 @@ export const SetupGuide: React.FC = () => { diff --git a/x-pack/plugins/enterprise_search/server/routes/app_search/engines.test.ts b/x-pack/plugins/enterprise_search/server/routes/app_search/engines.test.ts index 779c51131b472..6b78f29a6b731 100644 --- a/x-pack/plugins/enterprise_search/server/routes/app_search/engines.test.ts +++ b/x-pack/plugins/enterprise_search/server/routes/app_search/engines.test.ts @@ -122,19 +122,56 @@ describe('engine routes', () => { }); describe('validates', () => { - it('correctly', () => { - const request = { body: { name: 'some-engine', language: 'en' } }; - mockRouter.shouldValidate(request); - }); - - it('missing name', () => { - const request = { body: { language: 'en' } }; - mockRouter.shouldThrow(request); - }); - - it('optional language', () => { - const request = { body: { name: 'some-engine' } }; - mockRouter.shouldValidate(request); + describe('indexed engines', () => { + it('correctly', () => { + const request = { body: { name: 'some-engine', language: 'en' } }; + mockRouter.shouldValidate(request); + }); + + it('missing name', () => { + const request = { body: { language: 'en' } }; + mockRouter.shouldThrow(request); + }); + + it('optional language', () => { + const request = { body: { name: 'some-engine' } }; + mockRouter.shouldValidate(request); + }); + }); + + describe('meta engines', () => { + it('all properties', () => { + const request = { + body: { name: 'some-meta-engine', type: 'any', language: 'en', source_engines: [] }, + }; + mockRouter.shouldValidate(request); + }); + + it('missing name', () => { + const request = { + body: { type: 'any', language: 'en', source_engines: [] }, + }; + mockRouter.shouldThrow(request); + }); + + it('optional language', () => { + const request = { + body: { name: 'some-meta-engine', type: 'any', source_engines: [] }, + }; + mockRouter.shouldValidate(request); + }); + + it('optional source_engines', () => { + const request = { + body: { name: 'some-meta-engine', type: 'any', language: 'en' }, + }; + mockRouter.shouldValidate(request); + }); + + it('optional type', () => { + const request = { body: { name: 'some-engine' } }; + mockRouter.shouldValidate(request); + }); }); }); }); diff --git a/x-pack/plugins/enterprise_search/server/routes/app_search/engines.ts b/x-pack/plugins/enterprise_search/server/routes/app_search/engines.ts index 9bff6cf127dd3..766be196e70e7 100644 --- a/x-pack/plugins/enterprise_search/server/routes/app_search/engines.ts +++ b/x-pack/plugins/enterprise_search/server/routes/app_search/engines.ts @@ -45,6 +45,8 @@ export function registerEnginesRoutes({ body: schema.object({ name: schema.string(), language: schema.maybe(schema.string()), + source_engines: schema.maybe(schema.arrayOf(schema.string())), + type: schema.maybe(schema.string()), }), }, }, diff --git a/x-pack/plugins/enterprise_search/server/routes/workplace_search/index.ts b/x-pack/plugins/enterprise_search/server/routes/workplace_search/index.ts index cc6226e340653..a21ffac02a48c 100644 --- a/x-pack/plugins/enterprise_search/server/routes/workplace_search/index.ts +++ b/x-pack/plugins/enterprise_search/server/routes/workplace_search/index.ts @@ -9,6 +9,7 @@ import { RouteDependencies } from '../../plugin'; import { registerGroupsRoutes } from './groups'; import { registerOverviewRoute } from './overview'; +import { registerRoleMappingsRoutes } from './role_mappings'; import { registerSecurityRoutes } from './security'; import { registerSettingsRoutes } from './settings'; import { registerSourcesRoutes } from './sources'; @@ -16,6 +17,7 @@ import { registerSourcesRoutes } from './sources'; export const registerWorkplaceSearchRoutes = (dependencies: RouteDependencies) => { registerOverviewRoute(dependencies); registerGroupsRoutes(dependencies); + registerRoleMappingsRoutes(dependencies); registerSourcesRoutes(dependencies); registerSettingsRoutes(dependencies); registerSecurityRoutes(dependencies); diff --git a/x-pack/plugins/enterprise_search/server/routes/workplace_search/role_mappings.test.ts b/x-pack/plugins/enterprise_search/server/routes/workplace_search/role_mappings.test.ts new file mode 100644 index 0000000000000..0dade134767e4 --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/routes/workplace_search/role_mappings.test.ts @@ -0,0 +1,154 @@ +/* + * 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 { MockRouter, mockRequestHandler, mockDependencies } from '../../__mocks__'; + +import { + registerOrgRoleMappingsRoute, + registerOrgRoleMappingRoute, + registerOrgNewRoleMappingRoute, +} from './role_mappings'; + +describe('role mappings routes', () => { + describe('GET /api/workplace_search/org/role_mappings', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + mockRouter = new MockRouter({ + method: 'get', + path: '/api/workplace_search/org/role_mappings', + }); + + registerOrgRoleMappingsRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + }); + + it('creates a request handler', () => { + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/role_mappings/collection', + }); + }); + }); + + describe('POST /api/workplace_search/org/role_mappings', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + mockRouter = new MockRouter({ + method: 'post', + path: '/api/workplace_search/org/role_mappings', + }); + + registerOrgRoleMappingsRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + }); + + it('creates a request handler', () => { + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/role_mappings/collection', + }); + }); + }); + + describe('GET /api/workplace_search/org/role_mappings/{id}', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + mockRouter = new MockRouter({ + method: 'get', + path: '/api/workplace_search/org/role_mappings/{id}', + }); + + registerOrgRoleMappingRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + }); + + it('creates a request handler', () => { + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/role_mappings/:id', + }); + }); + }); + + describe('PUT /api/workplace_search/org/role_mappings/{id}', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + mockRouter = new MockRouter({ + method: 'put', + path: '/api/workplace_search/org/role_mappings/{id}', + }); + + registerOrgRoleMappingRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + }); + + it('creates a request handler', () => { + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/role_mappings/:id', + }); + }); + }); + + describe('DELETE /api/workplace_search/org/role_mappings/{id}', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + mockRouter = new MockRouter({ + method: 'delete', + path: '/api/workplace_search/org/role_mappings/{id}', + }); + + registerOrgRoleMappingRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + }); + + it('creates a request handler', () => { + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/role_mappings/:id', + }); + }); + }); + + describe('GET /api/workplace_search/org/role_mappings/new', () => { + let mockRouter: MockRouter; + + beforeEach(() => { + jest.clearAllMocks(); + mockRouter = new MockRouter({ + method: 'get', + path: '/api/workplace_search/org/role_mappings/new', + }); + + registerOrgNewRoleMappingRoute({ + ...mockDependencies, + router: mockRouter.router, + }); + }); + + it('creates a request handler', () => { + expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ + path: '/ws/org/role_mappings/new', + }); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/server/routes/workplace_search/role_mappings.ts b/x-pack/plugins/enterprise_search/server/routes/workplace_search/role_mappings.ts new file mode 100644 index 0000000000000..8c7792f56fd6c --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/routes/workplace_search/role_mappings.ts @@ -0,0 +1,117 @@ +/* + * 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 { RouteDependencies } from '../../plugin'; + +const roleMappingBaseSchema = { + rules: schema.recordOf(schema.string(), schema.string()), + roleType: schema.string(), + groups: schema.arrayOf(schema.string()), + allGroups: schema.boolean(), + authProvider: schema.arrayOf(schema.string()), +}; + +export function registerOrgRoleMappingsRoute({ + router, + enterpriseSearchRequestHandler, +}: RouteDependencies) { + router.get( + { + path: '/api/workplace_search/org/role_mappings', + validate: false, + }, + enterpriseSearchRequestHandler.createRequest({ + path: '/ws/org/role_mappings/collection', + }) + ); + + router.post( + { + path: '/api/workplace_search/org/role_mappings', + validate: { + body: schema.object(roleMappingBaseSchema), + }, + }, + enterpriseSearchRequestHandler.createRequest({ + path: '/ws/org/role_mappings/collection', + }) + ); +} + +export function registerOrgRoleMappingRoute({ + router, + enterpriseSearchRequestHandler, +}: RouteDependencies) { + router.get( + { + path: '/api/workplace_search/org/role_mappings/{id}', + validate: { + params: schema.object({ + id: schema.string(), + }), + }, + }, + enterpriseSearchRequestHandler.createRequest({ + path: '/ws/org/role_mappings/:id', + }) + ); + + router.put( + { + path: '/api/workplace_search/org/role_mappings/{id}', + validate: { + body: schema.object({ + ...roleMappingBaseSchema, + id: schema.string(), + }), + params: schema.object({ + id: schema.string(), + }), + }, + }, + enterpriseSearchRequestHandler.createRequest({ + path: '/ws/org/role_mappings/:id', + }) + ); + + router.delete( + { + path: '/api/workplace_search/org/role_mappings/{id}', + validate: { + params: schema.object({ + id: schema.string(), + }), + }, + }, + enterpriseSearchRequestHandler.createRequest({ + path: '/ws/org/role_mappings/:id', + }) + ); +} + +export function registerOrgNewRoleMappingRoute({ + router, + enterpriseSearchRequestHandler, +}: RouteDependencies) { + router.get( + { + path: '/api/workplace_search/org/role_mappings/new', + validate: false, + }, + enterpriseSearchRequestHandler.createRequest({ + path: '/ws/org/role_mappings/new', + }) + ); +} + +export const registerRoleMappingsRoutes = (dependencies: RouteDependencies) => { + registerOrgRoleMappingsRoute(dependencies); + registerOrgRoleMappingRoute(dependencies); + registerOrgNewRoleMappingRoute(dependencies); +}; diff --git a/x-pack/plugins/fleet/common/constants/agent_policy.ts b/x-pack/plugins/fleet/common/constants/agent_policy.ts index bed9b6e8390b8..51cf0382e2dbc 100644 --- a/x-pack/plugins/fleet/common/constants/agent_policy.ts +++ b/x-pack/plugins/fleet/common/constants/agent_policy.ts @@ -6,7 +6,8 @@ */ import { defaultPackages } from './epm'; -import { AgentPolicy } from '../types'; +import type { AgentPolicy } from '../types'; + export const AGENT_POLICY_SAVED_OBJECT_TYPE = 'ingest-agent-policies'; export const AGENT_POLICY_INDEX = '.fleet-policies'; export const agentPolicyStatuses = { diff --git a/x-pack/plugins/fleet/common/constants/output.ts b/x-pack/plugins/fleet/common/constants/output.ts index 9022be1086744..80c7e56dbb52f 100644 --- a/x-pack/plugins/fleet/common/constants/output.ts +++ b/x-pack/plugins/fleet/common/constants/output.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { NewOutput } from '../types'; +import type { NewOutput } from '../types'; export const OUTPUT_SAVED_OBJECT_TYPE = 'ingest-outputs'; diff --git a/x-pack/plugins/fleet/common/mocks.ts b/x-pack/plugins/fleet/common/mocks.ts index 4edc0fa6f81e9..7ea4be0ee35c6 100644 --- a/x-pack/plugins/fleet/common/mocks.ts +++ b/x-pack/plugins/fleet/common/mocks.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { NewPackagePolicy, PackagePolicy } from './types'; +import type { NewPackagePolicy, PackagePolicy } from './types'; export const createNewPackagePolicyMock = (): NewPackagePolicy => { return { diff --git a/x-pack/plugins/fleet/common/services/agent_status.ts b/x-pack/plugins/fleet/common/services/agent_status.ts index 1b49ba0c015e9..6d1d1c6a309d8 100644 --- a/x-pack/plugins/fleet/common/services/agent_status.ts +++ b/x-pack/plugins/fleet/common/services/agent_status.ts @@ -6,7 +6,7 @@ */ import { AGENT_POLLING_THRESHOLD_MS, AGENT_SAVED_OBJECT_TYPE } from '../constants'; -import { Agent, AgentStatus } from '../types'; +import type { Agent, AgentStatus } from '../types'; export function getAgentStatus(agent: Agent, now: number = Date.now()): AgentStatus { const { last_checkin: lastCheckIn } = agent; diff --git a/x-pack/plugins/fleet/common/services/full_agent_policy_kibana_config.ts b/x-pack/plugins/fleet/common/services/full_agent_policy_kibana_config.ts index 46fddd8bf040b..6b2709cc1961d 100644 --- a/x-pack/plugins/fleet/common/services/full_agent_policy_kibana_config.ts +++ b/x-pack/plugins/fleet/common/services/full_agent_policy_kibana_config.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FullAgentPolicyKibanaConfig } from '../types'; +import type { FullAgentPolicyKibanaConfig } from '../types'; export function getFullAgentPolicyKibanaConfig(kibanaUrls: string[]): FullAgentPolicyKibanaConfig { // paths and protocol are validated to be the same for all urls, so use the first to get them diff --git a/x-pack/plugins/fleet/common/services/full_agent_policy_to_yaml.ts b/x-pack/plugins/fleet/common/services/full_agent_policy_to_yaml.ts index 3dafc65a65235..64d297922f570 100644 --- a/x-pack/plugins/fleet/common/services/full_agent_policy_to_yaml.ts +++ b/x-pack/plugins/fleet/common/services/full_agent_policy_to_yaml.ts @@ -6,7 +6,7 @@ */ import { safeDump } from 'js-yaml'; -import { FullAgentPolicy } from '../types'; +import type { FullAgentPolicy } from '../types'; const POLICY_KEYS_ORDER = [ 'id', diff --git a/x-pack/plugins/fleet/common/services/is_agent_upgradeable.test.ts b/x-pack/plugins/fleet/common/services/is_agent_upgradeable.test.ts index ed5e2a22709c4..38ae63933a076 100644 --- a/x-pack/plugins/fleet/common/services/is_agent_upgradeable.test.ts +++ b/x-pack/plugins/fleet/common/services/is_agent_upgradeable.test.ts @@ -6,7 +6,7 @@ */ import { isAgentUpgradeable } from './is_agent_upgradeable'; -import { Agent } from '../types/models/agent'; +import type { Agent } from '../types/models/agent'; const getAgent = ({ version, diff --git a/x-pack/plugins/fleet/common/services/is_agent_upgradeable.ts b/x-pack/plugins/fleet/common/services/is_agent_upgradeable.ts index 12129816581f1..7de4e7c11d09e 100644 --- a/x-pack/plugins/fleet/common/services/is_agent_upgradeable.ts +++ b/x-pack/plugins/fleet/common/services/is_agent_upgradeable.ts @@ -7,7 +7,7 @@ import semverCoerce from 'semver/functions/coerce'; import semverLt from 'semver/functions/lt'; -import { Agent } from '../types'; +import type { Agent } from '../types'; export function isAgentUpgradeable(agent: Agent, kibanaVersion: string) { let agentVersion: string; diff --git a/x-pack/plugins/fleet/common/services/license.ts b/x-pack/plugins/fleet/common/services/license.ts index a480dd56d8b0c..68cbee5786d3b 100644 --- a/x-pack/plugins/fleet/common/services/license.ts +++ b/x-pack/plugins/fleet/common/services/license.ts @@ -6,7 +6,7 @@ */ import { Observable, Subscription } from 'rxjs'; -import { ILicense } from '../../../licensing/common/types'; +import type { ILicense } from '../../../licensing/common/types'; // Generic license service class that works with the license observable // Both server and client plugins instancates a singleton version of this class diff --git a/x-pack/plugins/fleet/common/services/limited_package.ts b/x-pack/plugins/fleet/common/services/limited_package.ts index da4ee176ee443..e247b61869de1 100644 --- a/x-pack/plugins/fleet/common/services/limited_package.ts +++ b/x-pack/plugins/fleet/common/services/limited_package.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PackageInfo, AgentPolicy, PackagePolicy } from '../types'; +import type { PackageInfo, AgentPolicy, PackagePolicy } from '../types'; // Assume packages only ever include 1 config template for now export const isPackageLimited = (packageInfo: PackageInfo): boolean => { diff --git a/x-pack/plugins/fleet/common/services/package_policies_to_agent_inputs.test.ts b/x-pack/plugins/fleet/common/services/package_policies_to_agent_inputs.test.ts index ee67263f159be..930a111f66d6b 100644 --- a/x-pack/plugins/fleet/common/services/package_policies_to_agent_inputs.test.ts +++ b/x-pack/plugins/fleet/common/services/package_policies_to_agent_inputs.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PackagePolicy, PackagePolicyInput } from '../types'; +import type { PackagePolicy, PackagePolicyInput } from '../types'; import { storedPackagePoliciesToAgentInputs } from './package_policies_to_agent_inputs'; describe('Fleet - storedPackagePoliciesToAgentInputs', () => { diff --git a/x-pack/plugins/fleet/common/services/package_policies_to_agent_inputs.ts b/x-pack/plugins/fleet/common/services/package_policies_to_agent_inputs.ts index f1cd2f60896e7..61d7764a832b1 100644 --- a/x-pack/plugins/fleet/common/services/package_policies_to_agent_inputs.ts +++ b/x-pack/plugins/fleet/common/services/package_policies_to_agent_inputs.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PackagePolicy, FullAgentPolicyInput, FullAgentPolicyInputStream } from '../types'; +import type { PackagePolicy, FullAgentPolicyInput, FullAgentPolicyInputStream } from '../types'; import { DEFAULT_OUTPUT } from '../constants'; export const storedPackagePoliciesToAgentInputs = ( diff --git a/x-pack/plugins/fleet/common/services/package_to_package_policy.test.ts b/x-pack/plugins/fleet/common/services/package_to_package_policy.test.ts index bb07ff152c085..e8ede61098dc2 100644 --- a/x-pack/plugins/fleet/common/services/package_to_package_policy.test.ts +++ b/x-pack/plugins/fleet/common/services/package_to_package_policy.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PackageInfo } from '../types'; +import type { PackageInfo } from '../types'; import { packageToPackagePolicy, packageToPackagePolicyInputs } from './package_to_package_policy'; describe('Fleet - packageToPackagePolicy', () => { diff --git a/x-pack/plugins/fleet/common/services/package_to_package_policy.ts b/x-pack/plugins/fleet/common/services/package_to_package_policy.ts index 36f5dc6ec4167..1fa4d39666cee 100644 --- a/x-pack/plugins/fleet/common/services/package_to_package_policy.ts +++ b/x-pack/plugins/fleet/common/services/package_to_package_policy.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { +import type { PackageInfo, RegistryPolicyTemplate, RegistryVarsEntry, diff --git a/x-pack/plugins/fleet/common/types/models/agent.ts b/x-pack/plugins/fleet/common/types/models/agent.ts index 2e18d427272ce..60eb47a6ecc43 100644 --- a/x-pack/plugins/fleet/common/types/models/agent.ts +++ b/x-pack/plugins/fleet/common/types/models/agent.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FullAgentPolicy } from './agent_policy'; +import type { FullAgentPolicy } from './agent_policy'; import { AGENT_TYPE_EPHEMERAL, AGENT_TYPE_PERMANENT, AGENT_TYPE_TEMPORARY } from '../../constants'; export type AgentType = diff --git a/x-pack/plugins/fleet/common/types/models/agent_policy.ts b/x-pack/plugins/fleet/common/types/models/agent_policy.ts index bc139537400cc..1aaca4fc5d932 100644 --- a/x-pack/plugins/fleet/common/types/models/agent_policy.ts +++ b/x-pack/plugins/fleet/common/types/models/agent_policy.ts @@ -6,9 +6,9 @@ */ import { agentPolicyStatuses } from '../../constants'; -import { DataType, ValueOf } from '../../types'; -import { PackagePolicy, PackagePolicyPackage } from './package_policy'; -import { Output } from './output'; +import type { DataType, ValueOf } from '../../types'; +import type { PackagePolicy, PackagePolicyPackage } from './package_policy'; +import type { Output } from './output'; export type AgentPolicyStatus = typeof agentPolicyStatuses; diff --git a/x-pack/plugins/fleet/common/types/models/epm.ts b/x-pack/plugins/fleet/common/types/models/epm.ts index 5c99831eaac34..e42ef7515b4c1 100644 --- a/x-pack/plugins/fleet/common/types/models/epm.ts +++ b/x-pack/plugins/fleet/common/types/models/epm.ts @@ -7,7 +7,7 @@ // Follow pattern from https://github.com/elastic/kibana/pull/52447 // TODO: Update when https://github.com/elastic/kibana/issues/53021 is closed -import { SavedObject, SavedObjectAttributes, SavedObjectReference } from 'src/core/public'; +import type { SavedObject, SavedObjectAttributes, SavedObjectReference } from 'src/core/public'; import { ASSETS_SAVED_OBJECT_TYPE, agentAssetTypes, @@ -16,8 +16,8 @@ import { installationStatuses, requiredPackages, } from '../../constants'; -import { ValueOf } from '../../types'; -import { PackageSpecManifest, PackageSpecScreenshot } from './package_spec'; +import type { ValueOf } from '../../types'; +import type { PackageSpecManifest, PackageSpecScreenshot } from './package_spec'; export type InstallationStatus = typeof installationStatuses; diff --git a/x-pack/plugins/fleet/common/types/models/package_spec.ts b/x-pack/plugins/fleet/common/types/models/package_spec.ts index f9de06704a697..65be72cbb7b6b 100644 --- a/x-pack/plugins/fleet/common/types/models/package_spec.ts +++ b/x-pack/plugins/fleet/common/types/models/package_spec.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { RegistryPolicyTemplate } from './epm'; +import type { RegistryPolicyTemplate } from './epm'; // Based on https://github.com/elastic/package-spec/blob/master/versions/1/manifest.spec.yml#L8 export interface PackageSpecManifest { diff --git a/x-pack/plugins/fleet/common/types/models/settings.ts b/x-pack/plugins/fleet/common/types/models/settings.ts index 04adfb6a3089c..56557fb6703b4 100644 --- a/x-pack/plugins/fleet/common/types/models/settings.ts +++ b/x-pack/plugins/fleet/common/types/models/settings.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { SavedObjectAttributes } from 'src/core/public'; +import type { SavedObjectAttributes } from 'src/core/public'; export interface BaseSettings { agent_auto_upgrade: boolean; 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 4c4c77c784d84..93cbb8369a3b1 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/agent.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/agent.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { +import type { Agent, AgentAction, NewAgentAction, diff --git a/x-pack/plugins/fleet/common/types/rest_spec/agent_policy.ts b/x-pack/plugins/fleet/common/types/rest_spec/agent_policy.ts index 5f8461019ab49..4b64044e1f2de 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/agent_policy.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/agent_policy.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { AgentPolicy, NewAgentPolicy, FullAgentPolicy } from '../models'; -import { ListWithKuery } from './common'; +import type { AgentPolicy, NewAgentPolicy, FullAgentPolicy } from '../models'; +import type { ListWithKuery } from './common'; export interface GetAgentPoliciesRequest { query: ListWithKuery & { diff --git a/x-pack/plugins/fleet/common/types/rest_spec/common.ts b/x-pack/plugins/fleet/common/types/rest_spec/common.ts index de5e87d2e59a5..15a280a62450a 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/common.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/common.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { HttpFetchQuery } from 'src/core/public'; +import type { HttpFetchQuery } from 'src/core/public'; export interface ListWithKuery extends HttpFetchQuery { page?: number; diff --git a/x-pack/plugins/fleet/common/types/rest_spec/data_stream.ts b/x-pack/plugins/fleet/common/types/rest_spec/data_stream.ts index dc46e0514abd0..bc2eef71721ff 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/data_stream.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/data_stream.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { DataStream } from '../models'; +import type { DataStream } from '../models'; export interface GetDataStreamsResponse { data_streams: DataStream[]; diff --git a/x-pack/plugins/fleet/common/types/rest_spec/enrollment_api_key.ts b/x-pack/plugins/fleet/common/types/rest_spec/enrollment_api_key.ts index b0373e58b045c..da870deb31d9c 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/enrollment_api_key.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/enrollment_api_key.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { EnrollmentAPIKey } from '../models'; +import type { EnrollmentAPIKey } from '../models'; export interface GetEnrollmentAPIKeysRequest { query: { diff --git a/x-pack/plugins/fleet/common/types/rest_spec/epm.ts b/x-pack/plugins/fleet/common/types/rest_spec/epm.ts index af622a51c719b..3a9c9a0cfae9f 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/epm.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/epm.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { +import type { AssetReference, CategorySummaryList, Installable, diff --git a/x-pack/plugins/fleet/common/types/rest_spec/output.ts b/x-pack/plugins/fleet/common/types/rest_spec/output.ts index 43a7e2cfd2e00..ef3c2f9f998ca 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/output.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/output.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Output } from '../models'; +import type { Output } from '../models'; export interface GetOneOutputResponse { item: Output; diff --git a/x-pack/plugins/fleet/common/types/rest_spec/package_policy.ts b/x-pack/plugins/fleet/common/types/rest_spec/package_policy.ts index eeadf6a2f9b6d..e6d893b9376a7 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/package_policy.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/package_policy.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PackagePolicy, NewPackagePolicy, UpdatePackagePolicy } from '../models'; +import type { PackagePolicy, NewPackagePolicy, UpdatePackagePolicy } from '../models'; export interface GetPackagePoliciesRequest { query: { diff --git a/x-pack/plugins/fleet/common/types/rest_spec/settings.ts b/x-pack/plugins/fleet/common/types/rest_spec/settings.ts index caff6573ddd0a..0b01815b2ef44 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/settings.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/settings.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Settings } from '../models'; +import type { Settings } from '../models'; export interface GetSettingsResponse { item: Settings; diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_config.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_config.ts index f32975d1180cd..cee563280e7bf 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_config.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_config.ts @@ -6,7 +6,7 @@ */ import React, { useContext } from 'react'; -import { FleetConfigType } from '../../../plugin'; +import type { FleetConfigType } from '../../../plugin'; export const ConfigContext = React.createContext(null); diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_core.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_core.ts index 21dfdbfc32139..30b3a5da94e1c 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_core.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_core.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FleetStartServices } from '../../../plugin'; +import type { FleetStartServices } from '../../../plugin'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; export function useStartServices(): FleetStartServices { diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_link.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_link.ts index 0463e512bff3e..bcb8c4c749211 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_link.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_link.ts @@ -5,13 +5,8 @@ * 2.0. */ -import { - BASE_PATH, - StaticPage, - DynamicPage, - DynamicPagePathValues, - pagePathGetters, -} from '../constants'; +import { BASE_PATH, pagePathGetters } from '../constants'; +import type { StaticPage, DynamicPage, DynamicPagePathValues } from '../constants'; import { useStartServices } from './'; const getPath = (page: StaticPage | DynamicPage, values: DynamicPagePathValues = {}): string => { diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_package_icon_type.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_package_icon_type.ts index 0d0b455999a8b..679c44f2c0ea9 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_package_icon_type.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_package_icon_type.ts @@ -7,7 +7,7 @@ import { useEffect, useState } from 'react'; import { ICON_TYPES } from '@elastic/eui'; -import { PackageInfo, PackageListItem } from '../types'; +import type { PackageInfo, PackageListItem } from '../types'; import { useLinks } from '../sections/epm/hooks'; import { sendGetPackageInfoByKey } from './index'; diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/agent_policy.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/agent_policy.ts index 2cba3b48a9564..d60383c15d2f4 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/agent_policy.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/agent_policy.ts @@ -5,14 +5,10 @@ * 2.0. */ -import { - useRequest, - sendRequest, - useConditionalRequest, - SendConditionalRequestConfig, -} from './use_request'; +import { useRequest, sendRequest, useConditionalRequest } from './use_request'; +import type { SendConditionalRequestConfig } from './use_request'; import { agentPolicyRouteService } from '../../services'; -import { +import type { GetAgentPoliciesRequest, GetAgentPoliciesResponse, GetOneAgentPolicyResponse, diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/agents.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/agents.ts index 7f774a85ff9d6..a40ebbf78e0f2 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/agents.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/agents.ts @@ -5,9 +5,10 @@ * 2.0. */ -import { useRequest, UseRequestConfig, sendRequest } from './use_request'; +import { useRequest, sendRequest } from './use_request'; +import type { UseRequestConfig } from './use_request'; import { agentRouteService } from '../../services'; -import { +import type { GetOneAgentResponse, GetOneAgentEventsResponse, GetOneAgentEventsRequest, diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/app.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/app.ts index 00f093474695f..2e93a1700d08c 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/app.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/app.ts @@ -7,7 +7,7 @@ import { sendRequest } from './use_request'; import { appRoutesService } from '../../services'; -import { CheckPermissionsResponse } from '../../types'; +import type { CheckPermissionsResponse } from '../../types'; export const sendGetPermissionsCheck = () => { return sendRequest({ diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/data_stream.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/data_stream.ts index 9e275e606f667..16e27596e7090 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/data_stream.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/data_stream.ts @@ -7,7 +7,7 @@ import { useRequest } from './use_request'; import { dataStreamRouteService } from '../../services'; -import { GetDataStreamsResponse } from '../../types'; +import type { GetDataStreamsResponse } from '../../types'; export const useGetDataStreams = () => { return useRequest({ diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/enrollment_api_keys.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/enrollment_api_keys.ts index cd0397d611df1..4aad8b7314482 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/enrollment_api_keys.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/enrollment_api_keys.ts @@ -5,15 +5,10 @@ * 2.0. */ -import { - useRequest, - UseRequestConfig, - sendRequest, - useConditionalRequest, - SendConditionalRequestConfig, -} from './use_request'; +import { useRequest, sendRequest, useConditionalRequest } from './use_request'; +import type { UseRequestConfig, SendConditionalRequestConfig } from './use_request'; import { enrollmentAPIKeyRouteService } from '../../services'; -import { +import type { GetOneEnrollmentAPIKeyResponse, GetEnrollmentAPIKeysResponse, GetEnrollmentAPIKeysRequest, diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/epm.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/epm.ts index f518ee2ea44ff..45e754849b5bc 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/epm.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/epm.ts @@ -7,7 +7,7 @@ import { useRequest, sendRequest } from './use_request'; import { epmRouteService } from '../../services'; -import { +import type { GetCategoriesRequest, GetCategoriesResponse, GetPackagesRequest, @@ -17,7 +17,7 @@ import { InstallPackageResponse, DeletePackageResponse, } from '../../types'; -import { GetStatsResponse } from '../../../../../common'; +import type { GetStatsResponse } from '../../../../../common'; export const useGetCategories = (query: GetCategoriesRequest['query'] = {}) => { return useRequest({ diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/outputs.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/outputs.ts index 1c43b84b2bc02..64c82d2a04790 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/outputs.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/outputs.ts @@ -7,7 +7,7 @@ import { sendRequest, useRequest } from './use_request'; import { outputRoutesService } from '../../services'; -import { PutOutputRequest, GetOutputsResponse } from '../../types'; +import type { PutOutputRequest, GetOutputsResponse } from '../../types'; export function useGetOutputs() { return useRequest({ diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/package_policy.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/package_policy.ts index ee4a4e4c24e28..1266f47a80e21 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/package_policy.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/package_policy.ts @@ -7,13 +7,13 @@ import { sendRequest, useRequest } from './use_request'; import { packagePolicyRouteService } from '../../services'; -import { +import type { CreatePackagePolicyRequest, CreatePackagePolicyResponse, UpdatePackagePolicyRequest, UpdatePackagePolicyResponse, } from '../../types'; -import { +import type { DeletePackagePoliciesRequest, DeletePackagePoliciesResponse, GetPackagePoliciesRequest, diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/settings.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/settings.ts index 9cc54a5c4223b..bf4ea6eacb3c1 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/settings.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/settings.ts @@ -7,7 +7,7 @@ import { sendRequest, useRequest } from './use_request'; import { settingsRoutesService } from '../../services'; -import { PutSettingsResponse, PutSettingsRequest, GetSettingsResponse } from '../../types'; +import type { PutSettingsResponse, PutSettingsRequest, GetSettingsResponse } from '../../types'; export function useGetSettings() { return useRequest({ diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/setup.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/setup.ts index 0f52712e8ded9..001b8af99aec5 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/setup.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/setup.ts @@ -7,7 +7,7 @@ import { sendRequest } from './use_request'; import { setupRouteService, fleetSetupRouteService } from '../../services'; -import { GetFleetStatusResponse } from '../../types'; +import type { GetFleetStatusResponse } from '../../types'; export const sendSetup = () => { return sendRequest({ diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/use_request.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/use_request.ts index 4c4433c2b4f89..985f4d71d6a75 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/use_request.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_request/use_request.ts @@ -6,14 +6,16 @@ */ import { useState, useEffect } from 'react'; -import { HttpSetup } from 'src/core/public'; +import type { HttpSetup } from 'src/core/public'; import { - SendRequestConfig, - SendRequestResponse, UseRequestConfig as _UseRequestConfig, sendRequest as _sendRequest, useRequest as _useRequest, } from '../../../../../../../../src/plugins/es_ui_shared/public'; +import type { + SendRequestConfig, + SendRequestResponse, +} from '../../../../../../../../src/plugins/es_ui_shared/public'; let httpClient: HttpSetup; diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_ui_extension.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_ui_extension.ts index 00eff8f91490b..f6b3cfd2b3642 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_ui_extension.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_ui_extension.ts @@ -6,7 +6,7 @@ */ import React, { useContext } from 'react'; -import { UIExtensionPoint, UIExtensionsStorage } from '../types'; +import type { UIExtensionPoint, UIExtensionsStorage } from '../types'; export const UIExtensionsContext = React.createContext({}); diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_url_pagination.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_url_pagination.ts index 7224a460bf414..090ce34ae244a 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_url_pagination.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_url_pagination.ts @@ -8,7 +8,8 @@ import { useCallback, useEffect, useMemo } from 'react'; import { useHistory, useLocation } from 'react-router-dom'; import { useUrlParams } from './use_url_params'; -import { PAGE_SIZE_OPTIONS, Pagination, usePagination } from './use_pagination'; +import { PAGE_SIZE_OPTIONS, usePagination } from './use_pagination'; +import type { Pagination } from './use_pagination'; type SetUrlPagination = (pagination: Pagination) => void; interface UrlPagination { diff --git a/x-pack/plugins/fleet/public/applications/fleet/mock/plugin_configuration.ts b/x-pack/plugins/fleet/public/applications/fleet/mock/plugin_configuration.ts index c5ae6d7fd4089..81ef6a6703c34 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/mock/plugin_configuration.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/mock/plugin_configuration.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FleetConfigType } from '../../../plugin'; +import type { FleetConfigType } from '../../../plugin'; export const createConfigurationMock = (): FleetConfigType => { return { diff --git a/x-pack/plugins/fleet/public/applications/fleet/mock/plugin_dependencies.ts b/x-pack/plugins/fleet/public/applications/fleet/mock/plugin_dependencies.ts index f8b05e13e2956..8207e3d89fc56 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/mock/plugin_dependencies.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/mock/plugin_dependencies.ts @@ -8,7 +8,7 @@ import { dataPluginMock } from '../../../../../../../src/plugins/data/public/mocks'; import { licensingMock } from '../../../../../licensing/public/mocks'; import { homePluginMock } from '../../../../../../../src/plugins/home/public/mocks'; -import { MockedFleetSetupDeps, MockedFleetStartDeps } from './types'; +import type { MockedFleetSetupDeps, MockedFleetStartDeps } from './types'; export const createSetupDepsMock = (): MockedFleetSetupDeps => { return { diff --git a/x-pack/plugins/fleet/public/applications/fleet/mock/plugin_interfaces.ts b/x-pack/plugins/fleet/public/applications/fleet/mock/plugin_interfaces.ts index d11ca5b041be1..3c76452f17ce7 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/mock/plugin_interfaces.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/mock/plugin_interfaces.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { UIExtensionsStorage } from '../types'; +import type { UIExtensionsStorage } from '../types'; import { createExtensionRegistrationCallback } from '../services/ui_extensions'; -import { MockedFleetStart } from './types'; +import type { MockedFleetStart } from './types'; export const createStartMock = (extensionsStorage: UIExtensionsStorage = {}): MockedFleetStart => { return { diff --git a/x-pack/plugins/fleet/public/applications/fleet/mock/types.ts b/x-pack/plugins/fleet/public/applications/fleet/mock/types.ts index 0a55fa43bf18d..660fe6af29fb1 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/mock/types.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/mock/types.ts @@ -5,8 +5,13 @@ * 2.0. */ -import { MockedKeys } from '@kbn/utility-types/jest'; -import { FleetSetupDeps, FleetStart, FleetStartDeps, FleetStartServices } from '../../../plugin'; +import type { MockedKeys } from '@kbn/utility-types/jest'; +import type { + FleetSetupDeps, + FleetStart, + FleetStartDeps, + FleetStartServices, +} from '../../../plugin'; export type MockedFleetStartServices = MockedKeys; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/has_invalid_but_required_var.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/has_invalid_but_required_var.ts index 84bdb3798f73f..a9a0480098323 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/has_invalid_but_required_var.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/has_invalid_but_required_var.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PackagePolicyConfigRecord, RegistryVarsEntry } from '../../../../types'; +import type { PackagePolicyConfigRecord, RegistryVarsEntry } from '../../../../types'; import { validatePackagePolicyConfig } from './'; export const hasInvalidButRequiredVar = ( diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/is_advanced_var.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/is_advanced_var.ts index 1e60b5e6e0bbb..1f72073573d7b 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/is_advanced_var.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/is_advanced_var.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { RegistryVarsEntry } from '../../../../types'; +import type { RegistryVarsEntry } from '../../../../types'; export const isAdvancedVar = (varDef: RegistryVarsEntry): boolean => { if (varDef.show_user || (varDef.required && varDef.default === undefined)) { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/validate_package_policy.test.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/validate_package_policy.test.ts index 5e05f10cd74be..e1e0d026966c3 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/validate_package_policy.test.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/validate_package_policy.test.ts @@ -6,7 +6,7 @@ */ import { installationStatuses } from '../../../../../../../common/constants'; -import { PackageInfo, NewPackagePolicy, RegistryPolicyTemplate } from '../../../../types'; +import type { PackageInfo, NewPackagePolicy, RegistryPolicyTemplate } from '../../../../types'; import { validatePackagePolicy, validationHasErrors } from './validate_package_policy'; describe('Fleet - validatePackagePolicy()', () => { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/validate_package_policy.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/validate_package_policy.ts index c39dfb4a99c12..c727be683c130 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/validate_package_policy.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/services/validate_package_policy.ts @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n'; import { safeLoad } from 'js-yaml'; import { getFlattenedObject, isValidNamespace } from '../../../../services'; -import { +import type { NewPackagePolicy, PackagePolicyInput, PackagePolicyInputStream, diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/components/release_badge.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/components/release_badge.ts index 21d205f4ac56d..9e4e51e410e7e 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/components/release_badge.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/components/release_badge.ts @@ -6,7 +6,7 @@ */ import { i18n } from '@kbn/i18n'; -import { RegistryRelease } from '../../../types'; +import type { RegistryRelease } from '../../../types'; export const RELEASE_BADGE_LABEL: { [key in Exclude]: string } = { beta: i18n.translate('xpack.fleet.epm.releaseBadge.betaLabel', { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/policies/use_package_policies_with_agent_policy.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/policies/use_package_policies_with_agent_policy.ts index ff8343314b4ac..77811a92093ee 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/policies/use_package_policies_with_agent_policy.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/policies/use_package_policies_with_agent_policy.ts @@ -6,7 +6,7 @@ */ import { useEffect, useMemo, useState } from 'react'; -import { +import type { PackagePolicy, GetAgentPoliciesResponse, GetAgentPoliciesResponseItem, @@ -15,10 +15,8 @@ import { import { agentPolicyRouteService } from '../../../../../services'; import { AGENT_POLICY_SAVED_OBJECT_TYPE } from '../../../../../constants'; import { useGetPackagePolicies } from '../../../../../hooks'; -import { - SendConditionalRequestConfig, - useConditionalRequest, -} from '../../../../../hooks/use_request/use_request'; +import { useConditionalRequest } from '../../../../../hooks/use_request/use_request'; +import type { SendConditionalRequestConfig } from '../../../../../hooks/use_request/use_request'; export interface PackagePolicyEnriched extends PackagePolicy { _agentPolicy: GetAgentPoliciesResponseItem | undefined; diff --git a/x-pack/plugins/fleet/public/applications/fleet/services/ui_extensions.test.ts b/x-pack/plugins/fleet/public/applications/fleet/services/ui_extensions.test.ts index d0e22f90e2640..bcddcb4afdbb3 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/services/ui_extensions.test.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/services/ui_extensions.test.ts @@ -6,8 +6,7 @@ */ import { lazy } from 'react'; - -import { +import type { PackagePolicyEditExtensionComponent, UIExtensionRegistrationCallback, UIExtensionsStorage, diff --git a/x-pack/plugins/fleet/public/applications/fleet/services/ui_extensions.ts b/x-pack/plugins/fleet/public/applications/fleet/services/ui_extensions.ts index 3583c9be93b99..d8b3e6212dbc1 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/services/ui_extensions.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/services/ui_extensions.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { UIExtensionRegistrationCallback, UIExtensionsStorage } from '../types'; +import type { UIExtensionRegistrationCallback, UIExtensionsStorage } from '../types'; /** Factory that returns a callback that can be used to register UI extensions */ export const createExtensionRegistrationCallback = ( diff --git a/x-pack/plugins/fleet/public/applications/fleet/types/intra_app_route_state.ts b/x-pack/plugins/fleet/public/applications/fleet/types/intra_app_route_state.ts index 52d93924a6312..b118797d7d38e 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/types/intra_app_route_state.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/types/intra_app_route_state.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { ApplicationStart } from 'kibana/public'; -import { PackagePolicy } from './'; +import type { ApplicationStart } from 'kibana/public'; +import type { PackagePolicy } from './'; /** * Supported routing state for the create package policy page routes diff --git a/x-pack/plugins/fleet/public/applications/fleet/types/ui_extensions.ts b/x-pack/plugins/fleet/public/applications/fleet/types/ui_extensions.ts index 2765c7e4b8b84..a9cea79ee7d8b 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/types/ui_extensions.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/types/ui_extensions.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { ComponentType, LazyExoticComponent } from 'react'; -import { NewPackagePolicy, PackageInfo, PackagePolicy } from './index'; +import type { ComponentType, LazyExoticComponent } from 'react'; +import type { NewPackagePolicy, PackageInfo, PackagePolicy } from './index'; /** Register a Fleet UI extension */ export type UIExtensionRegistrationCallback = (extensionPoint: UIExtensionPoint) => void; diff --git a/x-pack/plugins/fleet/public/index.ts b/x-pack/plugins/fleet/public/index.ts index 34bdc99abdf77..3b1136747f343 100644 --- a/x-pack/plugins/fleet/public/index.ts +++ b/x-pack/plugins/fleet/public/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PluginInitializerContext } from 'src/core/public'; +import type { PluginInitializerContext } from 'src/core/public'; import { FleetPlugin } from './plugin'; export { FleetSetup, FleetStart } from './plugin'; diff --git a/x-pack/plugins/fleet/public/plugin.ts b/x-pack/plugins/fleet/public/plugin.ts index 50e647e271ecc..7f2fd4ee24d4f 100644 --- a/x-pack/plugins/fleet/public/plugin.ts +++ b/x-pack/plugins/fleet/public/plugin.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { +import type { AppMountParameters, CoreSetup, Plugin, @@ -14,18 +14,18 @@ import { } from 'src/core/public'; import { i18n } from '@kbn/i18n'; import { DEFAULT_APP_CATEGORIES, AppNavLinkStatus } from '../../../../src/core/public'; -import { DataPublicPluginSetup, DataPublicPluginStart } from '../../../../src/plugins/data/public'; -import { - HomePublicPluginSetup, - FeatureCatalogueCategory, -} from '../../../../src/plugins/home/public'; +import type { + DataPublicPluginSetup, + DataPublicPluginStart, +} from '../../../../src/plugins/data/public'; +import { FeatureCatalogueCategory } from '../../../../src/plugins/home/public'; +import type { HomePublicPluginSetup } from '../../../../src/plugins/home/public'; import { Storage } from '../../../../src/plugins/kibana_utils/public'; -import { LicensingPluginSetup } from '../../licensing/public'; -import { PLUGIN_ID, CheckPermissionsResponse, PostIngestSetupResponse } from '../common'; +import type { LicensingPluginSetup } from '../../licensing/public'; +import { PLUGIN_ID, setupRouteService, appRoutesService } from '../common'; +import type { CheckPermissionsResponse, PostIngestSetupResponse } from '../common'; import { BASE_PATH } from './applications/fleet/constants'; - -import { FleetConfigType } from '../common/types'; -import { setupRouteService, appRoutesService } from '../common'; +import type { FleetConfigType } from '../common/types'; import { licenseService } from './applications/fleet/hooks/use_license'; import { setHttpClient } from './applications/fleet/hooks/use_request/use_request'; import { @@ -34,7 +34,10 @@ import { TutorialModuleNotice, } from './applications/fleet/components/home_integration'; import { createExtensionRegistrationCallback } from './applications/fleet/services/ui_extensions'; -import { UIExtensionRegistrationCallback, UIExtensionsStorage } from './applications/fleet/types'; +import type { + UIExtensionRegistrationCallback, + UIExtensionsStorage, +} from './applications/fleet/types'; export { FleetConfigType } from '../common/types'; diff --git a/x-pack/plugins/fleet/scripts/dev_agent/script.ts b/x-pack/plugins/fleet/scripts/dev_agent/script.ts index fc4a10f4f655f..87727ef657e5f 100644 --- a/x-pack/plugins/fleet/scripts/dev_agent/script.ts +++ b/x-pack/plugins/fleet/scripts/dev_agent/script.ts @@ -8,7 +8,7 @@ import { createFlagError, run, ToolingLog } from '@kbn/dev-utils'; import fetch from 'node-fetch'; import os from 'os'; -import { +import type { Agent as _Agent, PostAgentCheckinRequest, PostAgentCheckinResponse, diff --git a/x-pack/plugins/fleet/server/collectors/agent_collectors.ts b/x-pack/plugins/fleet/server/collectors/agent_collectors.ts index 154e78feae283..9aeae1dba0ea5 100644 --- a/x-pack/plugins/fleet/server/collectors/agent_collectors.ts +++ b/x-pack/plugins/fleet/server/collectors/agent_collectors.ts @@ -5,7 +5,9 @@ * 2.0. */ -import { ElasticsearchClient, SavedObjectsClient } from 'kibana/server'; +import { SavedObjectsClient } from 'kibana/server'; +import type { ElasticsearchClient } from 'kibana/server'; +import { FleetConfigType } from '../../common/types'; import * as AgentService from '../services/agents'; import { isFleetServerSetup } from '../services/fleet_server'; @@ -17,11 +19,13 @@ export interface AgentUsage { } export const getAgentUsage = async ( + config: FleetConfigType, soClient?: SavedObjectsClient, esClient?: ElasticsearchClient ): Promise => { // TODO: unsure if this case is possible at all. - if (!soClient || !esClient || !(await isFleetServerSetup())) { + const fleetServerMissing = config.agents.fleetServerEnabled && !(await isFleetServerSetup()); + if (!soClient || !esClient || fleetServerMissing) { return { total: 0, online: 0, diff --git a/x-pack/plugins/fleet/server/collectors/config_collectors.ts b/x-pack/plugins/fleet/server/collectors/config_collectors.ts index d6a9e4868c9ab..d651ad4b5d3be 100644 --- a/x-pack/plugins/fleet/server/collectors/config_collectors.ts +++ b/x-pack/plugins/fleet/server/collectors/config_collectors.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FleetConfigType } from '..'; +import type { FleetConfigType } from '..'; export const getIsAgentsEnabled = (config: FleetConfigType) => { return config.agents.enabled; diff --git a/x-pack/plugins/fleet/server/collectors/helpers.ts b/x-pack/plugins/fleet/server/collectors/helpers.ts index 6104b8a8adee9..4de2330e70a2c 100644 --- a/x-pack/plugins/fleet/server/collectors/helpers.ts +++ b/x-pack/plugins/fleet/server/collectors/helpers.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { CoreSetup } from 'kibana/server'; -import { ElasticsearchClient, SavedObjectsClient } from '../../../../../src/core/server'; +import type { CoreSetup } from 'kibana/server'; +import { SavedObjectsClient } from '../../../../../src/core/server'; +import type { ElasticsearchClient } from '../../../../../src/core/server'; export async function getInternalClients( core: CoreSetup diff --git a/x-pack/plugins/fleet/server/collectors/package_collectors.ts b/x-pack/plugins/fleet/server/collectors/package_collectors.ts index 542208a557182..e0f5667fbe458 100644 --- a/x-pack/plugins/fleet/server/collectors/package_collectors.ts +++ b/x-pack/plugins/fleet/server/collectors/package_collectors.ts @@ -9,7 +9,7 @@ import { SavedObjectsClient } from 'kibana/server'; import _ from 'lodash'; import { getPackageSavedObjects } from '../services/epm/packages/get'; import { agentPolicyService } from '../services'; -import { NewPackagePolicy } from '../types'; +import type { NewPackagePolicy } from '../types'; export interface PackageUsage { name: string; diff --git a/x-pack/plugins/fleet/server/collectors/register.ts b/x-pack/plugins/fleet/server/collectors/register.ts index 3e4ed80a3a83f..30b3ced260172 100644 --- a/x-pack/plugins/fleet/server/collectors/register.ts +++ b/x-pack/plugins/fleet/server/collectors/register.ts @@ -5,13 +5,15 @@ * 2.0. */ -import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; -import { CoreSetup } from 'kibana/server'; +import type { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; +import type { CoreSetup } from 'kibana/server'; import { getIsAgentsEnabled } from './config_collectors'; -import { AgentUsage, getAgentUsage } from './agent_collectors'; +import { getAgentUsage } from './agent_collectors'; +import type { AgentUsage } from './agent_collectors'; import { getInternalClients } from './helpers'; -import { PackageUsage, getPackageUsage } from './package_collectors'; -import { FleetConfigType } from '..'; +import { getPackageUsage } from './package_collectors'; +import type { PackageUsage } from './package_collectors'; +import type { FleetConfigType } from '..'; interface Usage { agents_enabled: boolean; @@ -38,7 +40,7 @@ export function registerFleetUsageCollector( const [soClient, esClient] = await getInternalClients(core); return { agents_enabled: getIsAgentsEnabled(config), - agents: await getAgentUsage(soClient, esClient), + agents: await getAgentUsage(config, soClient, esClient), packages: await getPackageUsage(soClient), }; }, diff --git a/x-pack/plugins/fleet/server/errors/handlers.ts b/x-pack/plugins/fleet/server/errors/handlers.ts index 77db050309a60..2d5339b158d9b 100644 --- a/x-pack/plugins/fleet/server/errors/handlers.ts +++ b/x-pack/plugins/fleet/server/errors/handlers.ts @@ -6,9 +6,9 @@ */ import Boom, { isBoom } from '@hapi/boom'; -import { +import { KibanaRequest } from 'src/core/server'; +import type { RequestHandlerContext, - KibanaRequest, IKibanaResponse, KibanaResponseFactory, } from 'src/core/server'; diff --git a/x-pack/plugins/fleet/server/index.ts b/x-pack/plugins/fleet/server/index.ts index 2d189d5f940ae..cb5eb6413fdf8 100644 --- a/x-pack/plugins/fleet/server/index.ts +++ b/x-pack/plugins/fleet/server/index.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { schema, TypeOf } from '@kbn/config-schema'; -import { PluginConfigDescriptor, PluginInitializerContext } from 'src/core/server'; +import { schema } from '@kbn/config-schema'; +import type { TypeOf } from '@kbn/config-schema'; +import type { PluginConfigDescriptor, PluginInitializerContext } from 'src/core/server'; import { FleetPlugin } from './plugin'; import { AGENT_POLICY_ROLLOUT_RATE_LIMIT_INTERVAL_MS, diff --git a/x-pack/plugins/fleet/server/mocks.ts b/x-pack/plugins/fleet/server/mocks.ts index 430e38bd1bc3e..3a7f9ebcc9e53 100644 --- a/x-pack/plugins/fleet/server/mocks.ts +++ b/x-pack/plugins/fleet/server/mocks.ts @@ -12,12 +12,11 @@ import { } from 'src/core/server/mocks'; import { coreMock } from '../../../../src/core/server/mocks'; import { licensingMock } from '../../../plugins/licensing/server/mocks'; - -import { FleetAppContext } from './plugin'; +import type { FleetAppContext } from './plugin'; import { encryptedSavedObjectsMock } from '../../encrypted_saved_objects/server/mocks'; import { securityMock } from '../../security/server/mocks'; -import { PackagePolicyServiceInterface } from './services/package_policy'; -import { AgentPolicyServiceInterface, AgentService } from './services'; +import type { PackagePolicyServiceInterface } from './services/package_policy'; +import type { AgentPolicyServiceInterface, AgentService } from './services'; export const createAppContextStartContractMock = (): FleetAppContext => { return { diff --git a/x-pack/plugins/fleet/server/routes/agent/acks_handlers.test.ts b/x-pack/plugins/fleet/server/routes/agent/acks_handlers.test.ts index e1ed453a572f6..b1bd10e8a4a77 100644 --- a/x-pack/plugins/fleet/server/routes/agent/acks_handlers.test.ts +++ b/x-pack/plugins/fleet/server/routes/agent/acks_handlers.test.ts @@ -6,7 +6,7 @@ */ import { postAgentAcksHandlerBuilder } from './acks_handlers'; -import { +import type { ElasticsearchClient, KibanaResponseFactory, RequestHandlerContext, @@ -17,9 +17,9 @@ import { httpServerMock, savedObjectsClientMock, } from '../../../../../../src/core/server/mocks'; -import { PostAgentAcksResponse } from '../../../common/types/rest_spec'; +import type { PostAgentAcksResponse } from '../../../common/types/rest_spec'; import { AckEventSchema } from '../../types/models'; -import { AcksService } from '../../services/agents'; +import type { AcksService } from '../../services/agents'; describe('test acks schema', () => { it('validate that ack event schema expect action id', async () => { diff --git a/x-pack/plugins/fleet/server/routes/agent/acks_handlers.ts b/x-pack/plugins/fleet/server/routes/agent/acks_handlers.ts index 22b5035378a20..e05638b9e6d8e 100644 --- a/x-pack/plugins/fleet/server/routes/agent/acks_handlers.ts +++ b/x-pack/plugins/fleet/server/routes/agent/acks_handlers.ts @@ -7,10 +7,10 @@ // handlers that handle events from agents in response to actions received -import { RequestHandler } from 'kibana/server'; -import { AcksService } from '../../services/agents'; -import { AgentEvent } from '../../../common/types/models'; -import { PostAgentAcksRequest, PostAgentAcksResponse } from '../../../common/types/rest_spec'; +import type { RequestHandler } from 'kibana/server'; +import type { AcksService } from '../../services/agents'; +import type { AgentEvent } from '../../../common/types/models'; +import type { PostAgentAcksRequest, PostAgentAcksResponse } from '../../../common/types/rest_spec'; import { defaultIngestErrorHandler } from '../../errors'; export const postAgentAcksHandlerBuilder = function ( diff --git a/x-pack/plugins/fleet/server/routes/agent/actions_handlers.test.ts b/x-pack/plugins/fleet/server/routes/agent/actions_handlers.test.ts index 6affe332b8f87..6c12a826a11df 100644 --- a/x-pack/plugins/fleet/server/routes/agent/actions_handlers.test.ts +++ b/x-pack/plugins/fleet/server/routes/agent/actions_handlers.test.ts @@ -6,7 +6,7 @@ */ import { NewAgentActionSchema } from '../../types/models'; -import { +import type { ElasticsearchClient, KibanaResponseFactory, RequestHandlerContext, @@ -17,10 +17,10 @@ import { savedObjectsClientMock, httpServerMock, } from 'src/core/server/mocks'; -import { ActionsService } from '../../services/agents'; -import { AgentAction } from '../../../common/types/models'; +import type { ActionsService } from '../../services/agents'; +import type { AgentAction } from '../../../common/types/models'; import { postNewAgentActionHandlerBuilder } from './actions_handlers'; -import { +import type { PostNewAgentActionRequest, PostNewAgentActionResponse, } from '../../../common/types/rest_spec'; diff --git a/x-pack/plugins/fleet/server/routes/agent/actions_handlers.ts b/x-pack/plugins/fleet/server/routes/agent/actions_handlers.ts index d032945245faf..2d5cfa4fd5b4f 100644 --- a/x-pack/plugins/fleet/server/routes/agent/actions_handlers.ts +++ b/x-pack/plugins/fleet/server/routes/agent/actions_handlers.ts @@ -7,11 +7,11 @@ // handlers that handle agent actions request -import { RequestHandler } from 'kibana/server'; -import { TypeOf } from '@kbn/config-schema'; +import type { RequestHandler } from 'kibana/server'; +import type { TypeOf } from '@kbn/config-schema'; import { PostNewAgentActionRequestSchema } from '../../types/rest_spec'; -import { ActionsService } from '../../services/agents'; -import { PostNewAgentActionResponse } from '../../../common/types/rest_spec'; +import type { ActionsService } from '../../services/agents'; +import type { PostNewAgentActionResponse } from '../../../common/types/rest_spec'; import { defaultIngestErrorHandler } from '../../errors'; export const postNewAgentActionHandlerBuilder = function ( diff --git a/x-pack/plugins/fleet/server/routes/agent/handlers.ts b/x-pack/plugins/fleet/server/routes/agent/handlers.ts index cd91e8c325c06..d5e2df56da601 100644 --- a/x-pack/plugins/fleet/server/routes/agent/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/agent/handlers.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { RequestHandler } from 'src/core/server'; -import { TypeOf } from '@kbn/config-schema'; +import type { RequestHandler } from 'src/core/server'; +import type { TypeOf } from '@kbn/config-schema'; import { AbortController } from 'abort-controller'; -import { +import type { GetAgentsResponse, GetOneAgentResponse, GetOneAgentEventsResponse, @@ -25,11 +25,11 @@ import { UpdateAgentRequestSchema, DeleteAgentRequestSchema, GetOneAgentEventsRequestSchema, - PostAgentCheckinRequest, GetAgentStatusRequestSchema, PutAgentReassignRequestSchema, PostBulkAgentReassignRequestSchema, } from '../../types'; +import type { PostAgentCheckinRequest } from '../../types'; import { defaultIngestErrorHandler } from '../../errors'; import { licenseService } from '../../services'; import * as AgentService from '../../services/agents'; diff --git a/x-pack/plugins/fleet/server/routes/agent/index.ts b/x-pack/plugins/fleet/server/routes/agent/index.ts index 86c88aeaf46ac..0b9e180a1cfd8 100644 --- a/x-pack/plugins/fleet/server/routes/agent/index.ts +++ b/x-pack/plugins/fleet/server/routes/agent/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IRouter, RouteValidationResultFactory } from 'src/core/server'; +import type { IRouter, RouteValidationResultFactory } from 'src/core/server'; import Ajv from 'ajv'; import { PLUGIN_ID, @@ -51,7 +51,7 @@ import * as AgentService from '../../services/agents'; import { postNewAgentActionHandlerBuilder } from './actions_handlers'; import { appContextService } from '../../services'; import { postAgentUnenrollHandler, postBulkAgentsUnenrollHandler } from './unenroll_handler'; -import { FleetConfigType } from '../..'; +import type { FleetConfigType } from '../..'; import { postAgentUpgradeHandler, postBulkAgentsUpgradeHandler } from './upgrade_handler'; const ajv = new Ajv({ diff --git a/x-pack/plugins/fleet/server/routes/agent/unenroll_handler.ts b/x-pack/plugins/fleet/server/routes/agent/unenroll_handler.ts index 614ccd8a26624..07ca776ef104b 100644 --- a/x-pack/plugins/fleet/server/routes/agent/unenroll_handler.ts +++ b/x-pack/plugins/fleet/server/routes/agent/unenroll_handler.ts @@ -5,9 +5,12 @@ * 2.0. */ -import { RequestHandler } from 'src/core/server'; -import { TypeOf } from '@kbn/config-schema'; -import { PostAgentUnenrollResponse, PostBulkAgentUnenrollResponse } from '../../../common/types'; +import type { RequestHandler } from 'src/core/server'; +import type { TypeOf } from '@kbn/config-schema'; +import type { + PostAgentUnenrollResponse, + PostBulkAgentUnenrollResponse, +} from '../../../common/types'; import { PostAgentUnenrollRequestSchema, PostBulkAgentUnenrollRequestSchema } from '../../types'; import { licenseService } from '../../services'; import * as AgentService from '../../services/agents'; diff --git a/x-pack/plugins/fleet/server/routes/agent/upgrade_handler.ts b/x-pack/plugins/fleet/server/routes/agent/upgrade_handler.ts index 086a9411f20b8..4999801c4122a 100644 --- a/x-pack/plugins/fleet/server/routes/agent/upgrade_handler.ts +++ b/x-pack/plugins/fleet/server/routes/agent/upgrade_handler.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { RequestHandler } from 'src/core/server'; -import { TypeOf } from '@kbn/config-schema'; +import type { RequestHandler } from 'src/core/server'; +import type { TypeOf } from '@kbn/config-schema'; import semverCoerce from 'semver/functions/coerce'; -import { PostAgentUpgradeResponse, PostBulkAgentUpgradeResponse } from '../../../common/types'; +import type { PostAgentUpgradeResponse, PostBulkAgentUpgradeResponse } from '../../../common/types'; import { PostAgentUpgradeRequestSchema, PostBulkAgentUpgradeRequestSchema } from '../../types'; import * as AgentService from '../../services/agents'; import { appContextService } from '../../services'; 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 411f7a74a6ab2..a0a30b1c1190b 100644 --- a/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { TypeOf } from '@kbn/config-schema'; -import { RequestHandler, ResponseHeaders } from 'src/core/server'; +import type { TypeOf } from '@kbn/config-schema'; +import type { RequestHandler, ResponseHeaders } from 'src/core/server'; import bluebird from 'bluebird'; import { fullAgentPolicyToYaml } from '../../../common/services'; import { appContextService, agentPolicyService, packagePolicyService } from '../../services'; @@ -20,10 +20,10 @@ import { CopyAgentPolicyRequestSchema, DeleteAgentPolicyRequestSchema, GetFullAgentPolicyRequestSchema, - AgentPolicy, - NewPackagePolicy, } from '../../types'; -import { +import type { AgentPolicy, NewPackagePolicy } from '../../types'; +import { defaultPackages } from '../../../common'; +import type { GetAgentPoliciesResponse, GetAgentPoliciesResponseItem, GetOneAgentPolicyResponse, @@ -32,7 +32,6 @@ import { CopyAgentPolicyResponse, DeleteAgentPolicyResponse, GetFullAgentPolicyResponse, - defaultPackages, } from '../../../common'; import { defaultIngestErrorHandler } from '../../errors'; diff --git a/x-pack/plugins/fleet/server/routes/agent_policy/index.ts b/x-pack/plugins/fleet/server/routes/agent_policy/index.ts index 256e24217558e..5cf58414f7992 100644 --- a/x-pack/plugins/fleet/server/routes/agent_policy/index.ts +++ b/x-pack/plugins/fleet/server/routes/agent_policy/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IRouter } from 'src/core/server'; +import type { IRouter } from 'src/core/server'; import { PLUGIN_ID, AGENT_POLICY_API_ROUTES } from '../../constants'; import { GetAgentPoliciesRequestSchema, diff --git a/x-pack/plugins/fleet/server/routes/app/index.ts b/x-pack/plugins/fleet/server/routes/app/index.ts index 64c1bdf1d02f9..04c5bf2df47be 100644 --- a/x-pack/plugins/fleet/server/routes/app/index.ts +++ b/x-pack/plugins/fleet/server/routes/app/index.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { IRouter, RequestHandler } from 'src/core/server'; +import type { IRouter, RequestHandler } from 'src/core/server'; import { APP_API_ROUTES } from '../../constants'; import { appContextService } from '../../services'; -import { CheckPermissionsResponse } from '../../../common'; +import type { CheckPermissionsResponse } from '../../../common'; export const getCheckPermissionsHandler: RequestHandler = async (context, request, response) => { const body: CheckPermissionsResponse = { success: true }; diff --git a/x-pack/plugins/fleet/server/routes/data_streams/handlers.ts b/x-pack/plugins/fleet/server/routes/data_streams/handlers.ts index 4424fc478c682..2826840d773e0 100644 --- a/x-pack/plugins/fleet/server/routes/data_streams/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/data_streams/handlers.ts @@ -5,10 +5,11 @@ * 2.0. */ -import { RequestHandler, SavedObjectsClientContract } from 'src/core/server'; import { keyBy, keys, merge } from 'lodash'; -import { DataStream } from '../../types'; -import { GetDataStreamsResponse, KibanaAssetType, KibanaSavedObjectType } from '../../../common'; +import type { RequestHandler, SavedObjectsClientContract } from 'src/core/server'; +import type { DataStream } from '../../types'; +import { KibanaAssetType, KibanaSavedObjectType } from '../../../common'; +import type { GetDataStreamsResponse } from '../../../common'; import { getPackageSavedObjects, getKibanaSavedObject } from '../../services/epm/packages/get'; import { defaultIngestErrorHandler } from '../../errors'; diff --git a/x-pack/plugins/fleet/server/routes/data_streams/index.ts b/x-pack/plugins/fleet/server/routes/data_streams/index.ts index 7373b684002f2..05efff12d01da 100644 --- a/x-pack/plugins/fleet/server/routes/data_streams/index.ts +++ b/x-pack/plugins/fleet/server/routes/data_streams/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IRouter } from 'src/core/server'; +import type { IRouter } from 'src/core/server'; import { PLUGIN_ID, DATA_STREAM_API_ROUTES } from '../../constants'; import { getListHandler } from './handlers'; diff --git a/x-pack/plugins/fleet/server/routes/enrollment_api_key/handler.ts b/x-pack/plugins/fleet/server/routes/enrollment_api_key/handler.ts index a46675c5be3ff..b41af3b0c770c 100644 --- a/x-pack/plugins/fleet/server/routes/enrollment_api_key/handler.ts +++ b/x-pack/plugins/fleet/server/routes/enrollment_api_key/handler.ts @@ -5,15 +5,15 @@ * 2.0. */ -import { RequestHandler } from 'src/core/server'; -import { TypeOf } from '@kbn/config-schema'; +import type { RequestHandler } from 'src/core/server'; +import type { TypeOf } from '@kbn/config-schema'; import { GetEnrollmentAPIKeysRequestSchema, PostEnrollmentAPIKeyRequestSchema, DeleteEnrollmentAPIKeyRequestSchema, GetOneEnrollmentAPIKeyRequestSchema, } from '../../types'; -import { +import type { GetEnrollmentAPIKeysResponse, GetOneEnrollmentAPIKeyResponse, DeleteEnrollmentAPIKeyResponse, diff --git a/x-pack/plugins/fleet/server/routes/enrollment_api_key/index.ts b/x-pack/plugins/fleet/server/routes/enrollment_api_key/index.ts index ee319987d1e91..cf736edd4633e 100644 --- a/x-pack/plugins/fleet/server/routes/enrollment_api_key/index.ts +++ b/x-pack/plugins/fleet/server/routes/enrollment_api_key/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IRouter } from 'src/core/server'; +import type { IRouter } from 'src/core/server'; import { PLUGIN_ID, ENROLLMENT_API_KEY_ROUTES } from '../../constants'; import { GetEnrollmentAPIKeysRequestSchema, diff --git a/x-pack/plugins/fleet/server/routes/epm/handlers.ts b/x-pack/plugins/fleet/server/routes/epm/handlers.ts index 47e53b27a600f..09a53f2c0d8ff 100644 --- a/x-pack/plugins/fleet/server/routes/epm/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/epm/handlers.ts @@ -5,11 +5,11 @@ * 2.0. */ -import { TypeOf } from '@kbn/config-schema'; +import type { TypeOf } from '@kbn/config-schema'; import mime from 'mime-types'; import path from 'path'; -import { RequestHandler, ResponseHeaders, KnownHeaders } from 'src/core/server'; -import { +import type { RequestHandler, ResponseHeaders, KnownHeaders } from 'src/core/server'; +import type { GetInfoResponse, InstallPackageResponse, DeletePackageResponse, @@ -33,7 +33,6 @@ import { GetStatsRequestSchema, } from '../../types'; import { - BulkInstallResponse, bulkInstallPackages, getCategories, getPackages, @@ -47,6 +46,7 @@ import { getInstallationObject, getInstallation, } from '../../services/epm/packages'; +import type { BulkInstallResponse } from '../../services/epm/packages'; import { defaultIngestErrorHandler, ingestErrorToResponseOptions } from '../../errors'; import { splitPkgKey } from '../../services/epm/registry'; import { licenseService } from '../../services'; diff --git a/x-pack/plugins/fleet/server/routes/epm/index.ts b/x-pack/plugins/fleet/server/routes/epm/index.ts index f5788fe252beb..9ed4d7e11ad29 100644 --- a/x-pack/plugins/fleet/server/routes/epm/index.ts +++ b/x-pack/plugins/fleet/server/routes/epm/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IRouter } from 'src/core/server'; +import type { IRouter } from 'src/core/server'; import { PLUGIN_ID, EPM_API_ROUTES } from '../../constants'; import { getCategoriesHandler, diff --git a/x-pack/plugins/fleet/server/routes/install_script/index.ts b/x-pack/plugins/fleet/server/routes/install_script/index.ts index c7cc0da1ce48c..5fb2ea726c62b 100644 --- a/x-pack/plugins/fleet/server/routes/install_script/index.ts +++ b/x-pack/plugins/fleet/server/routes/install_script/index.ts @@ -6,7 +6,8 @@ */ import url from 'url'; -import { IRouter, BasePath, KibanaRequest } from 'src/core/server'; +import { BasePath, KibanaRequest } from 'src/core/server'; +import type { IRouter } from 'src/core/server'; import { INSTALL_SCRIPT_API_ROUTES } from '../../constants'; import { getScript } from '../../services/install_script'; import { InstallScriptRequestSchema } from '../../types'; diff --git a/x-pack/plugins/fleet/server/routes/limited_concurrency.test.ts b/x-pack/plugins/fleet/server/routes/limited_concurrency.test.ts index f71aeb80a6d3e..626df529c1236 100644 --- a/x-pack/plugins/fleet/server/routes/limited_concurrency.test.ts +++ b/x-pack/plugins/fleet/server/routes/limited_concurrency.test.ts @@ -11,7 +11,7 @@ import { isLimitedRoute, registerLimitedConcurrencyRoutes, } from './limited_concurrency'; -import { FleetConfigType } from '../index'; +import type { FleetConfigType } from '../index'; describe('registerLimitedConcurrencyRoutes', () => { test(`doesn't call registerOnPreAuth if maxConcurrentConnections is 0`, async () => { diff --git a/x-pack/plugins/fleet/server/routes/limited_concurrency.ts b/x-pack/plugins/fleet/server/routes/limited_concurrency.ts index 92195ae08681a..ae4cab2839c79 100644 --- a/x-pack/plugins/fleet/server/routes/limited_concurrency.ts +++ b/x-pack/plugins/fleet/server/routes/limited_concurrency.ts @@ -5,15 +5,15 @@ * 2.0. */ +import { KibanaRequest } from 'kibana/server'; import type { CoreSetup, - KibanaRequest, LifecycleResponseFactory, OnPreAuthToolkit, OnPreAuthHandler, } from 'kibana/server'; import { LIMITED_CONCURRENCY_ROUTE_TAG } from '../../common'; -import { FleetConfigType } from '../index'; +import type { FleetConfigType } from '../index'; export class MaxCounter { constructor(private readonly max: number = 1) {} diff --git a/x-pack/plugins/fleet/server/routes/output/handler.ts b/x-pack/plugins/fleet/server/routes/output/handler.ts index e9f4b8c797689..a1bbe1112d04b 100644 --- a/x-pack/plugins/fleet/server/routes/output/handler.ts +++ b/x-pack/plugins/fleet/server/routes/output/handler.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { RequestHandler } from 'src/core/server'; -import { TypeOf } from '@kbn/config-schema'; +import type { RequestHandler } from 'src/core/server'; +import type { TypeOf } from '@kbn/config-schema'; import { GetOneOutputRequestSchema, PutOutputRequestSchema } from '../../types'; -import { GetOneOutputResponse, GetOutputsResponse } from '../../../common'; +import type { GetOneOutputResponse, GetOutputsResponse } from '../../../common'; import { outputService } from '../../services/output'; import { defaultIngestErrorHandler } from '../../errors'; diff --git a/x-pack/plugins/fleet/server/routes/output/index.ts b/x-pack/plugins/fleet/server/routes/output/index.ts index 7114a7c673d6b..ce4610cf7f85b 100644 --- a/x-pack/plugins/fleet/server/routes/output/index.ts +++ b/x-pack/plugins/fleet/server/routes/output/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IRouter } from 'src/core/server'; +import type { IRouter } from 'src/core/server'; import { PLUGIN_ID, OUTPUT_API_ROUTES } from '../../constants'; import { getOneOuputHandler, getOutputsHandler, putOuputHandler } from './handler'; import { diff --git a/x-pack/plugins/fleet/server/routes/package_policy/handlers.test.ts b/x-pack/plugins/fleet/server/routes/package_policy/handlers.test.ts index 813279f2a800f..a94313282a360 100644 --- a/x-pack/plugins/fleet/server/routes/package_policy/handlers.test.ts +++ b/x-pack/plugins/fleet/server/routes/package_policy/handlers.test.ts @@ -6,14 +6,14 @@ */ import { httpServerMock, httpServiceMock } from 'src/core/server/mocks'; -import { IRouter, KibanaRequest, RequestHandler, RouteConfig } from 'kibana/server'; +import { KibanaRequest } from 'kibana/server'; +import type { IRouter, RequestHandler, RouteConfig } from 'kibana/server'; import { registerRoutes } from './index'; import { PACKAGE_POLICY_API_ROUTES } from '../../../common/constants'; -import { appContextService } from '../../services'; +import { appContextService, packagePolicyService } from '../../services'; import { createAppContextStartContractMock, xpackMocks } from '../../mocks'; -import { PackagePolicyServiceInterface, ExternalCallback } from '../..'; +import type { PackagePolicyServiceInterface, ExternalCallback } from '../..'; import { CreatePackagePolicyRequestSchema } from '../../types/rest_spec'; -import { packagePolicyService } from '../../services'; const packagePolicyServiceMock = packagePolicyService as jest.Mocked; diff --git a/x-pack/plugins/fleet/server/routes/package_policy/handlers.ts b/x-pack/plugins/fleet/server/routes/package_policy/handlers.ts index 6b35f74b3febc..fb2c853f506c9 100644 --- a/x-pack/plugins/fleet/server/routes/package_policy/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/package_policy/handlers.ts @@ -5,9 +5,10 @@ * 2.0. */ -import { TypeOf } from '@kbn/config-schema'; +import type { TypeOf } from '@kbn/config-schema'; import Boom from '@hapi/boom'; -import { RequestHandler, SavedObjectsErrorHelpers } from '../../../../../../src/core/server'; +import { SavedObjectsErrorHelpers } from '../../../../../../src/core/server'; +import type { RequestHandler } from '../../../../../../src/core/server'; import { appContextService, packagePolicyService } from '../../services'; import { GetPackagePoliciesRequestSchema, @@ -16,7 +17,7 @@ import { UpdatePackagePolicyRequestSchema, DeletePackagePoliciesRequestSchema, } from '../../types'; -import { CreatePackagePolicyResponse, DeletePackagePoliciesResponse } from '../../../common'; +import type { CreatePackagePolicyResponse, DeletePackagePoliciesResponse } from '../../../common'; import { defaultIngestErrorHandler } from '../../errors'; export const getPackagePoliciesHandler: RequestHandler< diff --git a/x-pack/plugins/fleet/server/routes/package_policy/index.ts b/x-pack/plugins/fleet/server/routes/package_policy/index.ts index 2df70e1a51b34..19fc261685ff7 100644 --- a/x-pack/plugins/fleet/server/routes/package_policy/index.ts +++ b/x-pack/plugins/fleet/server/routes/package_policy/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IRouter } from 'src/core/server'; +import type { IRouter } from 'src/core/server'; import { PLUGIN_ID, PACKAGE_POLICY_API_ROUTES } from '../../constants'; import { GetPackagePoliciesRequestSchema, diff --git a/x-pack/plugins/fleet/server/routes/security.ts b/x-pack/plugins/fleet/server/routes/security.ts index 995dad545ed94..001dbf4b9b2f4 100644 --- a/x-pack/plugins/fleet/server/routes/security.ts +++ b/x-pack/plugins/fleet/server/routes/security.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IRouter, RequestHandler } from 'src/core/server'; +import type { IRouter, RequestHandler } from 'src/core/server'; import { appContextService } from '../services'; export function enforceSuperUser( diff --git a/x-pack/plugins/fleet/server/routes/settings/index.ts b/x-pack/plugins/fleet/server/routes/settings/index.ts index 63b5b9c881e13..2f71e3967c38c 100644 --- a/x-pack/plugins/fleet/server/routes/settings/index.ts +++ b/x-pack/plugins/fleet/server/routes/settings/index.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { IRouter, RequestHandler } from 'src/core/server'; -import { TypeOf } from '@kbn/config-schema'; +import type { IRouter, RequestHandler } from 'src/core/server'; +import type { TypeOf } from '@kbn/config-schema'; import { PLUGIN_ID, SETTINGS_API_ROUTES } from '../../constants'; import { PutSettingsRequestSchema, GetSettingsRequestSchema } from '../../types'; import { defaultIngestErrorHandler } from '../../errors'; diff --git a/x-pack/plugins/fleet/server/routes/setup/handlers.test.ts b/x-pack/plugins/fleet/server/routes/setup/handlers.test.ts index 946f17ad8129d..4016e90ea19b3 100644 --- a/x-pack/plugins/fleet/server/routes/setup/handlers.test.ts +++ b/x-pack/plugins/fleet/server/routes/setup/handlers.test.ts @@ -6,7 +6,7 @@ */ import { httpServerMock } from 'src/core/server/mocks'; -import { PostIngestSetupResponse } from '../../../common'; +import type { PostIngestSetupResponse } from '../../../common'; import { RegistryError } from '../../errors'; import { createAppContextStartContractMock, xpackMocks } from '../../mocks'; import { FleetSetupHandler } from './handlers'; diff --git a/x-pack/plugins/fleet/server/routes/setup/handlers.ts b/x-pack/plugins/fleet/server/routes/setup/handlers.ts index 0c6ba6d14b1be..8d4d44276dfc1 100644 --- a/x-pack/plugins/fleet/server/routes/setup/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/setup/handlers.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { RequestHandler } from 'src/core/server'; -import { TypeOf } from '@kbn/config-schema'; +import type { RequestHandler } from 'src/core/server'; +import type { TypeOf } from '@kbn/config-schema'; import { outputService, appContextService } from '../../services'; -import { GetFleetStatusResponse, PostIngestSetupResponse } from '../../../common'; +import type { GetFleetStatusResponse, PostIngestSetupResponse } from '../../../common'; import { setupIngestManager, setupFleet } from '../../services/setup'; import { PostFleetSetupRequestSchema } from '../../types'; import { defaultIngestErrorHandler } from '../../errors'; diff --git a/x-pack/plugins/fleet/server/routes/setup/index.ts b/x-pack/plugins/fleet/server/routes/setup/index.ts index 3698b74c8c02b..7e07723b4acd8 100644 --- a/x-pack/plugins/fleet/server/routes/setup/index.ts +++ b/x-pack/plugins/fleet/server/routes/setup/index.ts @@ -5,10 +5,9 @@ * 2.0. */ -import { IRouter } from 'src/core/server'; - +import type { IRouter } from 'src/core/server'; import { PLUGIN_ID, AGENTS_SETUP_API_ROUTES, SETUP_API_ROUTE } from '../../constants'; -import { FleetConfigType } from '../../../common'; +import type { FleetConfigType } from '../../../common'; import { getFleetStatusHandler, createFleetSetupHandler, FleetSetupHandler } from './handlers'; import { PostFleetSetupRequestSchema } from '../../types'; diff --git a/x-pack/plugins/fleet/server/saved_objects/index.ts b/x-pack/plugins/fleet/server/saved_objects/index.ts index d6e3cba998907..e41881c6f8b09 100644 --- a/x-pack/plugins/fleet/server/saved_objects/index.ts +++ b/x-pack/plugins/fleet/server/saved_objects/index.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { SavedObjectsServiceSetup, SavedObjectsType } from 'kibana/server'; -import { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objects/server'; +import type { SavedObjectsServiceSetup, SavedObjectsType } from 'kibana/server'; +import type { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objects/server'; import { migratePackagePolicyToV7110, migratePackagePolicyToV7120, diff --git a/x-pack/plugins/fleet/server/saved_objects/migrations/to_v7_10_0.ts b/x-pack/plugins/fleet/server/saved_objects/migrations/to_v7_10_0.ts index aa980e4b9428a..976f02e1f242c 100644 --- a/x-pack/plugins/fleet/server/saved_objects/migrations/to_v7_10_0.ts +++ b/x-pack/plugins/fleet/server/saved_objects/migrations/to_v7_10_0.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { SavedObjectMigrationFn, SavedObjectUnsanitizedDoc } from 'kibana/server'; -import { EncryptedSavedObjectsPluginSetup } from '../../../../encrypted_saved_objects/server'; -import { +import type { SavedObjectMigrationFn, SavedObjectUnsanitizedDoc } from 'kibana/server'; +import type { EncryptedSavedObjectsPluginSetup } from '../../../../encrypted_saved_objects/server'; +import type { Agent, AgentEvent, AgentPolicy, diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index 44962ea31c56c..bda754a1800b8 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -8,18 +8,18 @@ import { uniq } from 'lodash'; import { safeLoad } from 'js-yaml'; import uuid from 'uuid/v4'; -import { +import type { ElasticsearchClient, SavedObjectsClientContract, SavedObjectsBulkUpdateResponse, } from 'src/core/server'; -import { AuthenticatedUser } from '../../../security/server'; +import type { AuthenticatedUser } from '../../../security/server'; import { DEFAULT_AGENT_POLICY, AGENT_POLICY_SAVED_OBJECT_TYPE, AGENT_SAVED_OBJECT_TYPE, } from '../constants'; -import { +import type { PackagePolicy, NewAgentPolicy, AgentPolicy, @@ -28,15 +28,13 @@ import { ListWithKuery, } from '../types'; import { - DeleteAgentPolicyResponse, - Settings, agentPolicyStatuses, storedPackagePoliciesToAgentInputs, dataTypes, - FleetServerPolicy, AGENT_POLICY_INDEX, DEFAULT_FLEET_SERVER_AGENT_POLICY, } from '../../common'; +import type { DeleteAgentPolicyResponse, Settings, FleetServerPolicy } from '../../common'; import { AgentPolicyNameExistsError, AgentPolicyDeletionError, diff --git a/x-pack/plugins/fleet/server/services/agent_policy_update.ts b/x-pack/plugins/fleet/server/services/agent_policy_update.ts index 561c8043978ae..b6acafc667c9b 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy_update.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy_update.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { ElasticsearchClient, KibanaRequest, SavedObjectsClientContract } from 'src/core/server'; +import { KibanaRequest } from 'src/core/server'; +import type { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; import { generateEnrollmentAPIKey, deleteEnrollmentApiKeyForAgentPolicyId } from './api_keys'; import { isAgentsSetup, unenrollForAgentPolicyId } from './agents'; import { agentPolicyService } from './agent_policy'; diff --git a/x-pack/plugins/fleet/server/services/agents/acks.test.ts b/x-pack/plugins/fleet/server/services/agents/acks.test.ts index 5aec696f5e144..1a4b89a9b2a94 100644 --- a/x-pack/plugins/fleet/server/services/agents/acks.test.ts +++ b/x-pack/plugins/fleet/server/services/agents/acks.test.ts @@ -6,10 +6,9 @@ */ import Boom from '@hapi/boom'; -import { SavedObjectsBulkResponse } from 'kibana/server'; +import type { SavedObjectsBulkResponse } from 'kibana/server'; import { elasticsearchServiceMock, savedObjectsClientMock } from 'src/core/server/mocks'; - -import { +import type { Agent, AgentActionSOAttributes, BaseAgentActionSOAttributes, diff --git a/x-pack/plugins/fleet/server/services/agents/acks.ts b/x-pack/plugins/fleet/server/services/agents/acks.ts index c639a9b0332ac..0fecc18f7a622 100644 --- a/x-pack/plugins/fleet/server/services/agents/acks.ts +++ b/x-pack/plugins/fleet/server/services/agents/acks.ts @@ -5,16 +5,16 @@ * 2.0. */ -import { +import { KibanaRequest } from 'src/core/server'; +import type { ElasticsearchClient, - KibanaRequest, SavedObjectsBulkCreateObject, SavedObjectsBulkResponse, SavedObjectsClientContract, } from 'src/core/server'; import Boom from '@hapi/boom'; import LRU from 'lru-cache'; -import { +import type { Agent, AgentAction, AgentPolicyAction, diff --git a/x-pack/plugins/fleet/server/services/agents/actions.test.ts b/x-pack/plugins/fleet/server/services/agents/actions.test.ts index 3d391cc89a7e3..18e954d4aa9bd 100644 --- a/x-pack/plugins/fleet/server/services/agents/actions.test.ts +++ b/x-pack/plugins/fleet/server/services/agents/actions.test.ts @@ -6,8 +6,8 @@ */ import { createAgentAction } from './actions'; -import { SavedObject } from 'kibana/server'; -import { AgentAction } from '../../../common/types/models'; +import type { SavedObject } from 'kibana/server'; +import type { AgentAction } from '../../../common/types/models'; import { savedObjectsClientMock, elasticsearchServiceMock } from 'src/core/server/mocks'; describe('test agent actions services', () => { diff --git a/x-pack/plugins/fleet/server/services/agents/actions.ts b/x-pack/plugins/fleet/server/services/agents/actions.ts index 8dfeac11dacf3..58d52f408f1fb 100644 --- a/x-pack/plugins/fleet/server/services/agents/actions.ts +++ b/x-pack/plugins/fleet/server/services/agents/actions.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { ElasticsearchClient, SavedObjectsClientContract } from 'kibana/server'; -import { +import type { ElasticsearchClient, SavedObjectsClientContract } from 'kibana/server'; +import type { Agent, AgentAction, AgentPolicyAction, diff --git a/x-pack/plugins/fleet/server/services/agents/authenticate.ts b/x-pack/plugins/fleet/server/services/agents/authenticate.ts index a03c35bdc6e73..10469fcb3a013 100644 --- a/x-pack/plugins/fleet/server/services/agents/authenticate.ts +++ b/x-pack/plugins/fleet/server/services/agents/authenticate.ts @@ -6,8 +6,9 @@ */ import Boom from '@hapi/boom'; -import { KibanaRequest, SavedObjectsClientContract, ElasticsearchClient } from 'src/core/server'; -import { Agent } from '../../types'; +import { KibanaRequest } from 'src/core/server'; +import type { SavedObjectsClientContract, ElasticsearchClient } from 'src/core/server'; +import type { Agent } from '../../types'; import * as APIKeyService from '../api_keys'; import { getAgentByAccessAPIKeyId } from './crud'; diff --git a/x-pack/plugins/fleet/server/services/agents/checkin/index.ts b/x-pack/plugins/fleet/server/services/agents/checkin/index.ts index bcebedae2e07a..925006f9e67b3 100644 --- a/x-pack/plugins/fleet/server/services/agents/checkin/index.ts +++ b/x-pack/plugins/fleet/server/services/agents/checkin/index.ts @@ -6,19 +6,18 @@ */ import deepEqual from 'fast-deep-equal'; -import { +import type { ElasticsearchClient, SavedObjectsClientContract, SavedObjectsBulkCreateObject, } from 'src/core/server'; -import { +import type { Agent, NewAgentEvent, AgentEvent, AgentSOAttributes, AgentEventSOAttributes, } from '../../../types'; - import { AGENT_EVENT_SAVED_OBJECT_TYPE } from '../../../constants'; import { agentCheckinState } from './state'; import { getAgentActionsForCheckin } from '../actions'; diff --git a/x-pack/plugins/fleet/server/services/agents/checkin/state.ts b/x-pack/plugins/fleet/server/services/agents/checkin/state.ts index e1cec6292a355..de965646a59c3 100644 --- a/x-pack/plugins/fleet/server/services/agents/checkin/state.ts +++ b/x-pack/plugins/fleet/server/services/agents/checkin/state.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; -import { Agent } from '../../../types'; +import type { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; +import type { Agent } from '../../../types'; import { appContextService } from '../../app_context'; import { agentCheckinStateConnectedAgentsFactory } from './state_connected_agents'; import { agentCheckinStateNewActionsFactory } from './state_new_actions'; diff --git a/x-pack/plugins/fleet/server/services/agents/checkin/state_new_actions.test.ts b/x-pack/plugins/fleet/server/services/agents/checkin/state_new_actions.test.ts index cd6e0ef61e3f0..1433eccab038b 100644 --- a/x-pack/plugins/fleet/server/services/agents/checkin/state_new_actions.test.ts +++ b/x-pack/plugins/fleet/server/services/agents/checkin/state_new_actions.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ElasticsearchClient } from 'kibana/server'; +import type { ElasticsearchClient } from 'kibana/server'; import { savedObjectsClientMock } from 'src/core/server/mocks'; import { take } from 'rxjs/operators'; import { @@ -13,7 +13,7 @@ import { createNewActionsSharedObservable, } from './state_new_actions'; import { getNewActionsSince } from '../actions'; -import { Agent, AgentAction, AgentPolicyAction } from '../../../types'; +import type { Agent, AgentAction, AgentPolicyAction } from '../../../types'; import { outputType } from '../../../../common/constants'; jest.mock('../../app_context', () => ({ diff --git a/x-pack/plugins/fleet/server/services/agents/checkin/state_new_actions.ts b/x-pack/plugins/fleet/server/services/agents/checkin/state_new_actions.ts index 01759c2015cdf..c66bff30a2e57 100644 --- a/x-pack/plugins/fleet/server/services/agents/checkin/state_new_actions.ts +++ b/x-pack/plugins/fleet/server/services/agents/checkin/state_new_actions.ts @@ -22,8 +22,9 @@ import { timeout, take, } from 'rxjs/operators'; -import { ElasticsearchClient, SavedObjectsClientContract, KibanaRequest } from 'src/core/server'; -import { +import { KibanaRequest } from 'src/core/server'; +import type { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; +import type { Agent, AgentAction, AgentPolicyAction, diff --git a/x-pack/plugins/fleet/server/services/agents/crud.ts b/x-pack/plugins/fleet/server/services/agents/crud.ts index c80fd77fc11ec..60a2ed8f67cee 100644 --- a/x-pack/plugins/fleet/server/services/agents/crud.ts +++ b/x-pack/plugins/fleet/server/services/agents/crud.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { SavedObjectsClientContract, ElasticsearchClient } from 'src/core/server'; -import { AgentSOAttributes, Agent, ListWithKuery } from '../../types'; +import type { SavedObjectsClientContract, ElasticsearchClient } from 'src/core/server'; +import type { AgentSOAttributes, Agent, ListWithKuery } from '../../types'; import { appContextService, agentPolicyService } from '../../services'; import * as crudServiceSO from './crud_so'; import * as crudServiceFleetServer from './crud_fleet_server'; diff --git a/x-pack/plugins/fleet/server/services/agents/crud_fleet_server.ts b/x-pack/plugins/fleet/server/services/agents/crud_fleet_server.ts index caff15efff68c..53a22e842a544 100644 --- a/x-pack/plugins/fleet/server/services/agents/crud_fleet_server.ts +++ b/x-pack/plugins/fleet/server/services/agents/crud_fleet_server.ts @@ -6,17 +6,18 @@ */ import Boom from '@hapi/boom'; -import { SearchResponse } from 'elasticsearch'; -import { ElasticsearchClient } from 'src/core/server'; - -import { FleetServerAgent, isAgentUpgradeable, SO_SEARCH_LIMIT } from '../../../common'; +import type { SearchResponse } from 'elasticsearch'; +import type { ElasticsearchClient } from 'src/core/server'; +import { isAgentUpgradeable, SO_SEARCH_LIMIT } from '../../../common'; +import type { FleetServerAgent } from '../../../common'; import { AGENT_SAVED_OBJECT_TYPE, AGENTS_INDEX } from '../../constants'; -import { ESSearchHit } from '../../../../../typings/elasticsearch'; -import { AgentSOAttributes, Agent, ListWithKuery } from '../../types'; +import type { ESSearchHit } from '../../../../../typings/elasticsearch'; +import type { AgentSOAttributes, Agent, ListWithKuery } from '../../types'; import { escapeSearchQueryPhrase, normalizeKuery } from '../saved_object'; import { searchHitToAgent, agentSOAttributesToFleetServerAgentDoc } from './helpers'; import { appContextService } from '../../services'; -import { esKuery, KueryNode } from '../../../../../../src/plugins/data/server'; +import { esKuery } from '../../../../../../src/plugins/data/server'; +import type { KueryNode } from '../../../../../../src/plugins/data/server'; const ACTIVE_AGENT_CONDITION = 'active:true'; const INACTIVE_AGENT_CONDITION = `NOT (${ACTIVE_AGENT_CONDITION})`; diff --git a/x-pack/plugins/fleet/server/services/agents/crud_so.ts b/x-pack/plugins/fleet/server/services/agents/crud_so.ts index c3ceb4b7502e2..2daeff9b7344d 100644 --- a/x-pack/plugins/fleet/server/services/agents/crud_so.ts +++ b/x-pack/plugins/fleet/server/services/agents/crud_so.ts @@ -6,15 +6,15 @@ */ import Boom from '@hapi/boom'; -import { SavedObjectsBulkUpdateObject, SavedObjectsClientContract } from 'src/core/server'; - +import type { SavedObjectsBulkUpdateObject, SavedObjectsClientContract } from 'src/core/server'; import { isAgentUpgradeable } from '../../../common'; import { AGENT_SAVED_OBJECT_TYPE } from '../../constants'; -import { AgentSOAttributes, Agent, ListWithKuery } from '../../types'; +import type { AgentSOAttributes, Agent, ListWithKuery } from '../../types'; import { escapeSearchQueryPhrase, normalizeKuery, findAllSOs } from '../saved_object'; import { savedObjectToAgent } from './saved_objects'; import { appContextService } from '../../services'; -import { esKuery, KueryNode } from '../../../../../../src/plugins/data/server'; +import { esKuery } from '../../../../../../src/plugins/data/server'; +import type { KueryNode } from '../../../../../../src/plugins/data/server'; const ACTIVE_AGENT_CONDITION = `${AGENT_SAVED_OBJECT_TYPE}.attributes.active:true`; const INACTIVE_AGENT_CONDITION = `NOT (${ACTIVE_AGENT_CONDITION})`; diff --git a/x-pack/plugins/fleet/server/services/agents/events.ts b/x-pack/plugins/fleet/server/services/agents/events.ts index 71df5ebad4947..29b42a5de8282 100644 --- a/x-pack/plugins/fleet/server/services/agents/events.ts +++ b/x-pack/plugins/fleet/server/services/agents/events.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'src/core/server'; +import type { SavedObjectsClientContract } from 'src/core/server'; import { AGENT_EVENT_SAVED_OBJECT_TYPE } from '../../constants'; -import { AgentEventSOAttributes, AgentEvent } from '../../types'; +import type { AgentEventSOAttributes, AgentEvent } from '../../types'; import { normalizeKuery } from '../saved_object'; export async function getAgentEvents( diff --git a/x-pack/plugins/fleet/server/services/agents/helpers.ts b/x-pack/plugins/fleet/server/services/agents/helpers.ts index 90d85e98ecd67..1dab3b64755fd 100644 --- a/x-pack/plugins/fleet/server/services/agents/helpers.ts +++ b/x-pack/plugins/fleet/server/services/agents/helpers.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { ESSearchHit } from '../../../../../typings/elasticsearch'; -import { Agent, AgentSOAttributes, FleetServerAgent } from '../../types'; +import type { ESSearchHit } from '../../../../../typings/elasticsearch'; +import type { Agent, AgentSOAttributes, FleetServerAgent } from '../../types'; export function searchHitToAgent(hit: ESSearchHit): Agent { return { diff --git a/x-pack/plugins/fleet/server/services/agents/saved_objects.ts b/x-pack/plugins/fleet/server/services/agents/saved_objects.ts index 7b439c2729987..45d5a0de040ea 100644 --- a/x-pack/plugins/fleet/server/services/agents/saved_objects.ts +++ b/x-pack/plugins/fleet/server/services/agents/saved_objects.ts @@ -6,8 +6,8 @@ */ import Boom from '@hapi/boom'; -import { SavedObject } from 'src/core/server'; -import { +import type { SavedObject } from 'src/core/server'; +import type { Agent, AgentSOAttributes, AgentAction, diff --git a/x-pack/plugins/fleet/server/services/agents/setup.ts b/x-pack/plugins/fleet/server/services/agents/setup.ts index bbd14209b5b37..b55eb8efb1370 100644 --- a/x-pack/plugins/fleet/server/services/agents/setup.ts +++ b/x-pack/plugins/fleet/server/services/agents/setup.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'src/core/server'; +import type { SavedObjectsClientContract } from 'src/core/server'; import { SO_SEARCH_LIMIT } from '../../constants'; import { agentPolicyService } from '../agent_policy'; import { outputService } from '../output'; diff --git a/x-pack/plugins/fleet/server/services/agents/status.test.ts b/x-pack/plugins/fleet/server/services/agents/status.test.ts index a6b8bf41b6cb4..c6a021195f8f8 100644 --- a/x-pack/plugins/fleet/server/services/agents/status.test.ts +++ b/x-pack/plugins/fleet/server/services/agents/status.test.ts @@ -8,8 +8,8 @@ import { elasticsearchServiceMock, savedObjectsClientMock } from 'src/core/server/mocks'; import { getAgentStatusById } from './status'; import { AGENT_TYPE_PERMANENT } from '../../../common/constants'; -import { AgentSOAttributes } from '../../../common/types/models'; -import { SavedObject } from 'kibana/server'; +import type { AgentSOAttributes } from '../../../common/types/models'; +import type { SavedObject } from 'kibana/server'; describe('Agent status service', () => { it('should return inactive when agent is not active', async () => { diff --git a/x-pack/plugins/fleet/server/services/agents/status.ts b/x-pack/plugins/fleet/server/services/agents/status.ts index 42d3aff2b0d70..29171adf92bb9 100644 --- a/x-pack/plugins/fleet/server/services/agents/status.ts +++ b/x-pack/plugins/fleet/server/services/agents/status.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; +import type { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; import pMap from 'p-map'; import { getAgent, listAgents } from './crud'; import { AGENT_EVENT_SAVED_OBJECT_TYPE, AGENT_SAVED_OBJECT_TYPE } from '../../constants'; -import { AgentStatus } from '../../types'; - +import type { AgentStatus } from '../../types'; import { AgentStatusKueryHelper } from '../../../common/services'; -import { esKuery, KueryNode } from '../../../../../../src/plugins/data/server'; +import { esKuery } from '../../../../../../src/plugins/data/server'; +import type { KueryNode } from '../../../../../../src/plugins/data/server'; import { normalizeKuery } from '../saved_object'; import { appContextService } from '../app_context'; import { removeSOAttributes } from './crud_fleet_server'; diff --git a/x-pack/plugins/fleet/server/services/agents/unenroll.ts b/x-pack/plugins/fleet/server/services/agents/unenroll.ts index 72d551a122980..97dc7ea87706e 100644 --- a/x-pack/plugins/fleet/server/services/agents/unenroll.ts +++ b/x-pack/plugins/fleet/server/services/agents/unenroll.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; +import type { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; import * as APIKeyService from '../api_keys'; import { createAgentAction, bulkCreateAgentActions } from './actions'; import { diff --git a/x-pack/plugins/fleet/server/services/agents/update.ts b/x-pack/plugins/fleet/server/services/agents/update.ts index 21087be392bcd..81214b6fd0eb5 100644 --- a/x-pack/plugins/fleet/server/services/agents/update.ts +++ b/x-pack/plugins/fleet/server/services/agents/update.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; +import type { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; import { listAgents } from './crud'; import { AGENT_SAVED_OBJECT_TYPE } from '../../constants'; import { unenrollAgent } from './unenroll'; diff --git a/x-pack/plugins/fleet/server/services/agents/upgrade.ts b/x-pack/plugins/fleet/server/services/agents/upgrade.ts index d73cc38e32c39..9986edd3d805f 100644 --- a/x-pack/plugins/fleet/server/services/agents/upgrade.ts +++ b/x-pack/plugins/fleet/server/services/agents/upgrade.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; -import { AgentAction, AgentActionSOAttributes } from '../../types'; +import type { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; +import type { AgentAction, AgentActionSOAttributes } from '../../types'; import { AGENT_ACTION_SAVED_OBJECT_TYPE } from '../../constants'; import { agentPolicyService } from '../../services'; import { IngestManagerError } from '../../errors'; diff --git a/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key.ts b/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key.ts index 85812fee3885c..5d86393f0905e 100644 --- a/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key.ts +++ b/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { SavedObjectsClientContract, ElasticsearchClient } from 'src/core/server'; -import { EnrollmentAPIKey } from '../../types'; +import type { SavedObjectsClientContract, ElasticsearchClient } from 'src/core/server'; +import type { EnrollmentAPIKey } from '../../types'; import { appContextService } from '../app_context'; import * as enrollmentApiKeyServiceSO from './enrollment_api_key_so'; import * as enrollmentApiKeyServiceFleetServer from './enrollment_api_key_fleet_server'; diff --git a/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key_fleet_server.ts b/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key_fleet_server.ts index f5d0015297daa..5cde87da95cdf 100644 --- a/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key_fleet_server.ts +++ b/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key_fleet_server.ts @@ -7,11 +7,11 @@ import uuid from 'uuid'; import Boom from '@hapi/boom'; -import { GetResponse } from 'elasticsearch'; +import type { GetResponse } from 'elasticsearch'; import { ResponseError } from '@elastic/elasticsearch/lib/errors'; -import { SavedObjectsClientContract, ElasticsearchClient } from 'src/core/server'; -import { ESSearchResponse as SearchResponse } from '../../../../../typings/elasticsearch'; -import { EnrollmentAPIKey, FleetServerEnrollmentAPIKey } from '../../types'; +import type { SavedObjectsClientContract, ElasticsearchClient } from 'src/core/server'; +import type { ESSearchResponse as SearchResponse } from '../../../../../typings/elasticsearch'; +import type { EnrollmentAPIKey, FleetServerEnrollmentAPIKey } from '../../types'; import { ENROLLMENT_API_KEYS_INDEX } from '../../constants'; import { createAPIKey, invalidateAPIKeys } from './security'; import { agentPolicyService } from '../agent_policy'; diff --git a/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key_so.ts b/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key_so.ts index 014bc58e747ea..4001cabe76aa3 100644 --- a/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key_so.ts +++ b/x-pack/plugins/fleet/server/services/api_keys/enrollment_api_key_so.ts @@ -7,8 +7,8 @@ import uuid from 'uuid'; import Boom from '@hapi/boom'; -import { SavedObjectsClientContract, SavedObject } from 'src/core/server'; -import { EnrollmentAPIKey, EnrollmentAPIKeySOAttributes } from '../../types'; +import type { SavedObjectsClientContract, SavedObject } from 'src/core/server'; +import type { EnrollmentAPIKey, EnrollmentAPIKeySOAttributes } from '../../types'; import { ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE } from '../../constants'; import { createAPIKey, invalidateAPIKeys } from './security'; import { agentPolicyService } from '../agent_policy'; diff --git a/x-pack/plugins/fleet/server/services/api_keys/index.ts b/x-pack/plugins/fleet/server/services/api_keys/index.ts index 911cb700dd56b..724583e42efe0 100644 --- a/x-pack/plugins/fleet/server/services/api_keys/index.ts +++ b/x-pack/plugins/fleet/server/services/api_keys/index.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { SavedObjectsClientContract, KibanaRequest } from 'src/core/server'; +import { KibanaRequest } from 'src/core/server'; +import type { SavedObjectsClientContract } from 'src/core/server'; import { createAPIKey } from './security'; export { invalidateAPIKeys } from './security'; diff --git a/x-pack/plugins/fleet/server/services/api_keys/security.ts b/x-pack/plugins/fleet/server/services/api_keys/security.ts index efd46c1a547dd..356f9012791eb 100644 --- a/x-pack/plugins/fleet/server/services/api_keys/security.ts +++ b/x-pack/plugins/fleet/server/services/api_keys/security.ts @@ -6,9 +6,10 @@ */ import type { Request } from '@hapi/hapi'; -import { KibanaRequest, SavedObjectsClientContract } from '../../../../../../src/core/server'; +import { KibanaRequest } from '../../../../../../src/core/server'; +import type { SavedObjectsClientContract } from '../../../../../../src/core/server'; import { FleetAdminUserInvalidError, isESClientError } from '../../errors'; -import { CallESAsCurrentUser } from '../../types'; +import type { CallESAsCurrentUser } from '../../types'; import { appContextService } from '../app_context'; import { outputService } from '../output'; diff --git a/x-pack/plugins/fleet/server/services/app_context.ts b/x-pack/plugins/fleet/server/services/app_context.ts index 1ada940dd793c..f63d3b2d7ccab 100644 --- a/x-pack/plugins/fleet/server/services/app_context.ts +++ b/x-pack/plugins/fleet/server/services/app_context.ts @@ -8,22 +8,21 @@ import { BehaviorSubject, Observable } from 'rxjs'; import { first } from 'rxjs/operators'; import { kibanaPackageJson } from '@kbn/utils'; - -import { +import { KibanaRequest } from 'src/core/server'; +import type { ElasticsearchClient, SavedObjectsServiceStart, HttpServiceSetup, Logger, - KibanaRequest, } from 'src/core/server'; -import { +import type { EncryptedSavedObjectsClient, EncryptedSavedObjectsPluginSetup, } from '../../../encrypted_saved_objects/server'; -import { SecurityPluginStart } from '../../../security/server'; -import { FleetConfigType } from '../../common'; -import { ExternalCallback, ExternalCallbacksStorage, FleetAppContext } from '../plugin'; -import { CloudSetup } from '../../../cloud/server'; +import type { SecurityPluginStart } from '../../../security/server'; +import type { FleetConfigType } from '../../common'; +import type { ExternalCallback, ExternalCallbacksStorage, FleetAppContext } from '../plugin'; +import type { CloudSetup } from '../../../cloud/server'; class AppContextService { private encryptedSavedObjects: EncryptedSavedObjectsClient | undefined; diff --git a/x-pack/plugins/fleet/server/services/config.ts b/x-pack/plugins/fleet/server/services/config.ts index 3e2c7be1e3fde..d14e31e5b510f 100644 --- a/x-pack/plugins/fleet/server/services/config.ts +++ b/x-pack/plugins/fleet/server/services/config.ts @@ -6,7 +6,7 @@ */ import { Observable, Subscription } from 'rxjs'; -import { FleetConfigType } from '../'; +import type { FleetConfigType } from '../'; /** * Kibana config observable service, *NOT* agent policy diff --git a/x-pack/plugins/fleet/server/services/epm/agent/agent.ts b/x-pack/plugins/fleet/server/services/epm/agent/agent.ts index a71776af245f7..38631ad784ea9 100644 --- a/x-pack/plugins/fleet/server/services/epm/agent/agent.ts +++ b/x-pack/plugins/fleet/server/services/epm/agent/agent.ts @@ -7,7 +7,7 @@ import Handlebars from 'handlebars'; import { safeLoad, safeDump } from 'js-yaml'; -import { PackagePolicyConfigRecord } from '../../../../common'; +import type { PackagePolicyConfigRecord } from '../../../../common'; const handlebars = Handlebars.create(); diff --git a/x-pack/plugins/fleet/server/services/epm/archive/cache.ts b/x-pack/plugins/fleet/server/services/epm/archive/cache.ts index 97e0303e9f50f..8d4234e3cf538 100644 --- a/x-pack/plugins/fleet/server/services/epm/archive/cache.ts +++ b/x-pack/plugins/fleet/server/services/epm/archive/cache.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { ArchiveEntry } from './index'; -import { ArchivePackage, RegistryPackage } from '../../../../common'; +import type { ArchiveEntry } from './index'; +import type { ArchivePackage, RegistryPackage } from '../../../../common'; const archiveEntryCache: Map = new Map(); export const getArchiveEntry = (key: string) => archiveEntryCache.get(key); diff --git a/x-pack/plugins/fleet/server/services/epm/archive/extract.ts b/x-pack/plugins/fleet/server/services/epm/archive/extract.ts index 817eff7d42788..8d576310813c0 100644 --- a/x-pack/plugins/fleet/server/services/epm/archive/extract.ts +++ b/x-pack/plugins/fleet/server/services/epm/archive/extract.ts @@ -8,7 +8,7 @@ import tar from 'tar'; import yauzl from 'yauzl'; import { bufferToStream, streamToBuffer } from '../streams'; -import { ArchiveEntry } from './index'; +import type { ArchiveEntry } from './index'; export async function untarBuffer( buffer: Buffer, diff --git a/x-pack/plugins/fleet/server/services/epm/archive/index.ts b/x-pack/plugins/fleet/server/services/epm/archive/index.ts index 7ee217979cdae..44046ac749f6c 100644 --- a/x-pack/plugins/fleet/server/services/epm/archive/index.ts +++ b/x-pack/plugins/fleet/server/services/epm/archive/index.ts @@ -5,10 +5,9 @@ * 2.0. */ -import { AssetParts, InstallSource } from '../../../../common/types'; +import type { AssetParts, InstallSource } from '../../../../common/types'; import { PackageInvalidArchiveError, PackageUnsupportedMediaTypeError } from '../../../errors'; import { - SharedKey, getArchiveEntry, setArchiveEntry, deleteArchiveEntry, @@ -17,6 +16,7 @@ import { deleteArchiveFilelist, deletePackageInfo, } from './cache'; +import type { SharedKey } from './cache'; import { getBufferExtractor } from './extract'; export * from './cache'; diff --git a/x-pack/plugins/fleet/server/services/epm/archive/storage.ts b/x-pack/plugins/fleet/server/services/epm/archive/storage.ts index 20e1e8825fbd8..671d428918caf 100644 --- a/x-pack/plugins/fleet/server/services/epm/archive/storage.ts +++ b/x-pack/plugins/fleet/server/services/epm/archive/storage.ts @@ -11,15 +11,16 @@ import { safeLoad } from 'js-yaml'; import { isBinaryFile } from 'isbinaryfile'; import mime from 'mime-types'; import uuidv5 from 'uuid/v5'; -import { SavedObjectsClientContract, SavedObjectsBulkCreateObject } from 'src/core/server'; -import { - ASSETS_SAVED_OBJECT_TYPE, +import type { SavedObjectsClientContract, SavedObjectsBulkCreateObject } from 'src/core/server'; +import { ASSETS_SAVED_OBJECT_TYPE } from '../../../../common'; +import type { InstallablePackage, InstallSource, PackageAssetReference, RegistryDataStream, } from '../../../../common'; -import { ArchiveEntry, getArchiveEntry, setArchiveEntry, setArchiveFilelist } from './index'; +import { getArchiveEntry, setArchiveEntry, setArchiveFilelist } from './index'; +import type { ArchiveEntry } from './index'; import { parseAndVerifyPolicyTemplates, parseAndVerifyStreams } from './validation'; import { pkgToPkgKey } from '../registry'; diff --git a/x-pack/plugins/fleet/server/services/epm/archive/validation.ts b/x-pack/plugins/fleet/server/services/epm/archive/validation.ts index 05daa98579079..03f30cab45734 100644 --- a/x-pack/plugins/fleet/server/services/epm/archive/validation.ts +++ b/x-pack/plugins/fleet/server/services/epm/archive/validation.ts @@ -7,7 +7,7 @@ import yaml from 'js-yaml'; import { pick, uniq } from 'lodash'; -import { +import type { ArchivePackage, RegistryPolicyTemplate, RegistryDataStream, diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/install.ts index a18c2710ce776..e18cf2eb52bcd 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/install.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'kibana/server'; -import { - ElasticsearchAssetType, +import type { SavedObjectsClientContract } from 'kibana/server'; +import { ElasticsearchAssetType } from '../../../../../common/types/models'; +import type { EsAssetReference, InstallablePackage, RegistryDataStream, } from '../../../../../common/types/models'; -import { CallESAsCurrentUser } from '../../../../types'; +import type { CallESAsCurrentUser } from '../../../../types'; import { getInstallation } from '../../packages'; import { deleteIlmRefs, deleteIlms } from './remove'; import { saveInstalledEsRefs } from '../../packages/install'; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/remove.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/remove.ts index 6f0cd6ecc935f..7da980e61f0ec 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/remove.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/remove.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'kibana/server'; -import { CallESAsCurrentUser, ElasticsearchAssetType, EsAssetReference } from '../../../../types'; +import type { SavedObjectsClientContract } from 'kibana/server'; +import { ElasticsearchAssetType } from '../../../../types'; +import type { CallESAsCurrentUser, EsAssetReference } from '../../../../types'; import { PACKAGES_SAVED_OBJECT_TYPE } from '../../../../../common/constants'; export const deleteIlms = async (callCluster: CallESAsCurrentUser, ilmPolicyIds: string[]) => { diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ilm/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ilm/install.ts index 644baa3a77e7d..b6123d190c0eb 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ilm/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ilm/install.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { CallESAsCurrentUser, ElasticsearchAssetType } from '../../../../types'; +import { ElasticsearchAssetType } from '../../../../types'; +import type { CallESAsCurrentUser } from '../../../../types'; import { getAsset, getPathParts } from '../../archive'; export async function installILMPolicy(paths: string[], callCluster: CallESAsCurrentUser) { diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/index.test.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/index.test.ts index 178d0c53703f3..aa64cd7a6ed02 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/index.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/index.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { RegistryDataStream } from '../../../types'; +import type { RegistryDataStream } from '../../../types'; import { getRegistryDataStreamAssetBaseName } from './index'; test('getBaseName', () => { diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/index.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/index.ts index 95873ef0c9b29..81e05ef7d6314 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/index.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { RegistryDataStream } from '../../../types'; +import type { RegistryDataStream } from '../../../types'; /** * Creates the base name for Elasticsearch assets in the form of diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/ingest_pipelines.test.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/ingest_pipelines.test.ts index 001add36ea95d..0a96186339bc0 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/ingest_pipelines.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/ingest_pipelines.test.ts @@ -8,7 +8,7 @@ import { readFileSync } from 'fs'; import path from 'path'; import { rewriteIngestPipeline, getPipelineNameForInstallation } from './install'; -import { RegistryDataStream } from '../../../../types'; +import type { RegistryDataStream } from '../../../../types'; test('a json-format pipeline with pipeline references is correctly rewritten', () => { const inputStandard = readFileSync( diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/install.ts index 983e10e15bfff..ff3262cb65418 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/install.ts @@ -5,15 +5,16 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'src/core/server'; -import { +import type { SavedObjectsClientContract } from 'src/core/server'; +import { ElasticsearchAssetType } from '../../../../types'; +import type { EsAssetReference, RegistryDataStream, - ElasticsearchAssetType, InstallablePackage, + CallESAsCurrentUser, } from '../../../../types'; -import { ArchiveEntry, getAsset, getPathParts } from '../../archive'; -import { CallESAsCurrentUser } from '../../../../types'; +import { getAsset, getPathParts } from '../../archive'; +import type { ArchiveEntry } from '../../archive'; import { saveInstalledEsRefs } from '../../packages/install'; import { getInstallationObject } from '../../packages'; import { deletePipelineRefs } from './remove'; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/remove.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/remove.ts index 4acc4767de525..d78c9d989bd4d 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/remove.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/remove.ts @@ -5,12 +5,14 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'src/core/server'; +import type { SavedObjectsClientContract } from 'src/core/server'; import { appContextService } from '../../../'; -import { CallESAsCurrentUser, ElasticsearchAssetType } from '../../../../types'; +import { ElasticsearchAssetType } from '../../../../types'; +import type { CallESAsCurrentUser } from '../../../../types'; import { IngestManagerError } from '../../../../errors'; import { getInstallation } from '../../packages/get'; -import { PACKAGES_SAVED_OBJECT_TYPE, EsAssetReference } from '../../../../../common'; +import { PACKAGES_SAVED_OBJECT_TYPE } from '../../../../../common'; +import type { EsAssetReference } from '../../../../../common'; export const deletePreviousPipelines = async ( callCluster: CallESAsCurrentUser, diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.test.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.test.ts index cdcd3972fd189..42e724794b791 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.test.ts @@ -5,9 +5,8 @@ * 2.0. */ -import { RegistryDataStream } from '../../../../types'; -import { Field } from '../../fields/field'; - +import type { RegistryDataStream } from '../../../../types'; +import type { Field } from '../../fields/field'; import { elasticsearchServiceMock } from 'src/core/server/mocks'; import { installTemplate } from './install'; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.ts index 70afa78e723bc..353331528ca3c 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.ts @@ -6,16 +6,17 @@ */ import Boom from '@hapi/boom'; -import { SavedObjectsClientContract } from 'src/core/server'; -import { +import type { SavedObjectsClientContract } from 'src/core/server'; +import { ElasticsearchAssetType } from '../../../../types'; +import type { RegistryDataStream, - ElasticsearchAssetType, TemplateRef, RegistryElasticsearch, InstallablePackage, + CallESAsCurrentUser, } from '../../../../types'; -import { CallESAsCurrentUser } from '../../../../types'; -import { Field, loadFieldsFromYaml, processFields } from '../../fields/field'; +import { loadFieldsFromYaml, processFields } from '../../fields/field'; +import type { Field } from '../../fields/field'; import { getPipelineNameForInstallation } from '../ingest_pipeline/install'; import { generateMappings, diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts index a176805307845..95e9e8e6d5c71 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts @@ -8,8 +8,9 @@ import { readFileSync } from 'fs'; import { safeLoad } from 'js-yaml'; import path from 'path'; -import { RegistryDataStream } from '../../../../types'; -import { Field, processFields } from '../../fields/field'; +import type { RegistryDataStream } from '../../../../types'; +import { processFields } from '../../fields/field'; +import type { Field } from '../../fields/field'; import { generateMappings, getTemplate, diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts index b86c989f8c24c..a13ad007663d8 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { Field, Fields } from '../../fields/field'; -import { +import type { Field, Fields } from '../../fields/field'; +import type { RegistryDataStream, CallESAsCurrentUser, TemplateRef, diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/install.ts index 948a9c56746f3..e68c5070affd3 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/install.ts @@ -5,16 +5,12 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'kibana/server'; - +import type { SavedObjectsClientContract } from 'kibana/server'; import { saveInstalledEsRefs } from '../../packages/install'; import { getPathParts } from '../../archive'; -import { - ElasticsearchAssetType, - EsAssetReference, - InstallablePackage, -} from '../../../../../common/types/models'; -import { CallESAsCurrentUser } from '../../../../types'; +import { ElasticsearchAssetType } from '../../../../../common/types/models'; +import type { EsAssetReference, InstallablePackage } from '../../../../../common/types/models'; +import type { CallESAsCurrentUser } from '../../../../types'; import { getInstallation } from '../../packages'; import { deleteTransforms, deleteTransformRefs } from './remove'; import { getAsset } from './common'; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/remove.test.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/remove.test.ts index 658a130d70c61..6df9f34489aeb 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/remove.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/remove.test.ts @@ -5,11 +5,11 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'kibana/server'; +import type { SavedObjectsClientContract } from 'kibana/server'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { savedObjectsClientMock } from '../../../../../../../../src/core/server/saved_objects/service/saved_objects_client.mock'; import { deleteTransformRefs } from './remove'; -import { EsAssetReference } from '../../../../../common/types/models'; +import type { EsAssetReference } from '../../../../../common/types/models'; describe('test transform install', () => { let savedObjectsClient: jest.Mocked; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/remove.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/remove.ts index 0e947e0f0b90b..510071f119910 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/remove.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/remove.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'kibana/server'; -import { CallESAsCurrentUser, ElasticsearchAssetType, EsAssetReference } from '../../../../types'; +import type { SavedObjectsClientContract } from 'kibana/server'; +import { ElasticsearchAssetType } from '../../../../types'; +import type { CallESAsCurrentUser, EsAssetReference } from '../../../../types'; import { PACKAGES_SAVED_OBJECT_TYPE } from '../../../../../common/constants'; import { appContextService } from '../../../app_context'; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/transform.test.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/transform.test.ts index bd944391b5f23..602908c5908e5 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/transform.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/transform.test.ts @@ -19,8 +19,13 @@ jest.mock('./common', () => { import { errors as LegacyESErrors } from 'elasticsearch'; import { installTransform } from './install'; -import { ILegacyScopedClusterClient, SavedObject, SavedObjectsClientContract } from 'kibana/server'; -import { ElasticsearchAssetType, Installation, RegistryPackage } from '../../../../types'; +import type { + ILegacyScopedClusterClient, + SavedObject, + SavedObjectsClientContract, +} from 'kibana/server'; +import { ElasticsearchAssetType } from '../../../../types'; +import type { Installation, RegistryPackage } from '../../../../types'; import { getInstallation, getInstallationObject } from '../../packages'; import { getAsset } from './common'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths diff --git a/x-pack/plugins/fleet/server/services/epm/fields/field.test.ts b/x-pack/plugins/fleet/server/services/epm/fields/field.test.ts index b10c417210656..21c0fc52f6b3f 100644 --- a/x-pack/plugins/fleet/server/services/epm/fields/field.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/fields/field.test.ts @@ -9,7 +9,8 @@ import { readFileSync } from 'fs'; import glob from 'glob'; import { safeLoad } from 'js-yaml'; import path from 'path'; -import { Field, Fields, getField, processFields } from './field'; +import { getField, processFields } from './field'; +import type { Field, Fields } from './field'; // Add our own serialiser to just do JSON.stringify expect.addSnapshotSerializer({ diff --git a/x-pack/plugins/fleet/server/services/epm/fields/field.ts b/x-pack/plugins/fleet/server/services/epm/fields/field.ts index cc925bbb14ba0..7144a4ca4e7f0 100644 --- a/x-pack/plugins/fleet/server/services/epm/fields/field.ts +++ b/x-pack/plugins/fleet/server/services/epm/fields/field.ts @@ -6,7 +6,7 @@ */ import { safeLoad } from 'js-yaml'; -import { InstallablePackage } from '../../../types'; +import type { InstallablePackage } from '../../../types'; import { getAssetsData } from '../packages/assets'; // This should become a copy of https://github.com/elastic/beats/blob/d9a4c9c240a9820fab15002592e5bb6db318543b/libbeat/mapping/field.go#L39 diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts b/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts index 64d65da2c3e14..a004bf0f21f62 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts @@ -5,20 +5,15 @@ * 2.0. */ -import { +import type { SavedObject, SavedObjectsBulkCreateObject, SavedObjectsClientContract, } from 'src/core/server'; import { PACKAGES_SAVED_OBJECT_TYPE } from '../../../../../common'; import { getAsset, getPathParts } from '../../archive'; -import { - AssetType, - KibanaAssetType, - AssetReference, - AssetParts, - KibanaSavedObjectType, -} from '../../../../types'; +import { KibanaAssetType, KibanaSavedObjectType } from '../../../../types'; +import type { AssetType, AssetReference, AssetParts } from '../../../../types'; import { savedObjectTypes } from '../../packages'; import { indexPatternTypes } from '../index_pattern/install'; diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.test.ts b/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.test.ts index afac05f6ecaec..e6d36235f0384 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.test.ts @@ -14,12 +14,12 @@ import { dedupeFields, transformField, findFieldByPath, - IndexPatternField, createFieldFormatMap, createIndexPatternFields, createIndexPattern, } from './install'; -import { Fields, Field } from '../../fields/field'; +import type { IndexPatternField } from './install'; +import type { Fields, Field } from '../../fields/field'; import { dupeFields } from './tests/test_data'; // Add our own serialiser to just do JSON.stringify diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.ts b/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.ts index 8b8ff8b4c9d95..f45eeab8bc2ba 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.ts @@ -5,12 +5,18 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'src/core/server'; +import type { SavedObjectsClientContract } from 'src/core/server'; import { INDEX_PATTERN_SAVED_OBJECT_TYPE } from '../../../../constants'; -import { loadFieldsFromYaml, Fields, Field } from '../../fields/field'; +import { loadFieldsFromYaml } from '../../fields/field'; +import type { Fields, Field } from '../../fields/field'; import { dataTypes, installationStatuses } from '../../../../../common/constants'; -import { ArchivePackage, Installation, InstallSource, ValueOf } from '../../../../../common/types'; -import { RegistryPackage, DataType } from '../../../../types'; +import type { + ArchivePackage, + Installation, + InstallSource, + ValueOf, +} from '../../../../../common/types'; +import type { RegistryPackage, DataType } from '../../../../types'; import { getInstallation, getPackageFromSource, getPackageSavedObjects } from '../../packages/get'; interface FieldFormatMap { diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/tests/test_data.ts b/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/tests/test_data.ts index 1b17c6d812b4c..49a32de703776 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/tests/test_data.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/tests/test_data.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IndexPatternField } from '../install'; +import type { IndexPatternField } from '../install'; export const dupeFields: IndexPatternField[] = [ { diff --git a/x-pack/plugins/fleet/server/services/epm/packages/_install_package.test.ts b/x-pack/plugins/fleet/server/services/epm/packages/_install_package.test.ts index a55b763d7b2bb..cf928d5b80d63 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/_install_package.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/_install_package.test.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { SavedObjectsClientContract, LegacyScopedClusterClient } from 'src/core/server'; +import { LegacyScopedClusterClient } from 'src/core/server'; +import type { SavedObjectsClientContract } from 'src/core/server'; import { savedObjectsClientMock, elasticsearchServiceMock } from 'src/core/server/mocks'; import { appContextService } from '../../app_context'; import { createAppContextStartContractMock } from '../../../mocks'; diff --git a/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts b/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts index 2a6a4c93cb8e0..206bef75df14b 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/_install_package.ts @@ -5,20 +5,15 @@ * 2.0. */ -import { SavedObject, SavedObjectsClientContract } from 'src/core/server'; -import { - InstallablePackage, - InstallSource, - PackageAssetReference, - MAX_TIME_COMPLETE_INSTALL, - ASSETS_SAVED_OBJECT_TYPE, -} from '../../../../common'; +import type { SavedObject, SavedObjectsClientContract } from 'src/core/server'; +import { MAX_TIME_COMPLETE_INSTALL, ASSETS_SAVED_OBJECT_TYPE } from '../../../../common'; +import type { InstallablePackage, InstallSource, PackageAssetReference } from '../../../../common'; import { PACKAGES_SAVED_OBJECT_TYPE } from '../../../constants'; -import { +import { ElasticsearchAssetType } from '../../../types'; +import type { AssetReference, Installation, CallESAsCurrentUser, - ElasticsearchAssetType, InstallType, } from '../../../types'; import { installIndexPatterns } from '../kibana/index_pattern/install'; diff --git a/x-pack/plugins/fleet/server/services/epm/packages/assets.test.ts b/x-pack/plugins/fleet/server/services/epm/packages/assets.test.ts index aa35ddd2c294b..6e5c257badef7 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/assets.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/assets.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { InstallablePackage } from '../../../types'; +import type { InstallablePackage } from '../../../types'; import { getAssets } from './assets'; import { getArchiveFilelist } from '../archive/cache'; diff --git a/x-pack/plugins/fleet/server/services/epm/packages/assets.ts b/x-pack/plugins/fleet/server/services/epm/packages/assets.ts index a2a2bce91d8e5..c28c982f4ea4c 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/assets.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/assets.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { InstallablePackage } from '../../../types'; -import { ArchiveEntry, getArchiveFilelist, getAsset } from '../archive'; +import type { InstallablePackage } from '../../../types'; +import { getArchiveFilelist, getAsset } from '../archive'; +import type { ArchiveEntry } from '../archive'; // paths from RegistryPackage are routes to the assets on EPR // e.g. `/package/nginx/1.2.0/data_stream/access/fields/fields.yml` diff --git a/x-pack/plugins/fleet/server/services/epm/packages/bulk_install_packages.ts b/x-pack/plugins/fleet/server/services/epm/packages/bulk_install_packages.ts index ac41f550c1c72..64fd132145ffc 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/bulk_install_packages.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/bulk_install_packages.ts @@ -5,11 +5,12 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'src/core/server'; -import { CallESAsCurrentUser } from '../../../types'; +import type { SavedObjectsClientContract } from 'src/core/server'; +import type { CallESAsCurrentUser } from '../../../types'; import * as Registry from '../registry'; import { getInstallationObject } from './index'; -import { BulkInstallResponse, IBulkInstallPackageError, upgradePackage } from './install'; +import { upgradePackage } from './install'; +import type { BulkInstallResponse, IBulkInstallPackageError } from './install'; interface BulkInstallPackagesParams { savedObjectsClient: SavedObjectsClientContract; diff --git a/x-pack/plugins/fleet/server/services/epm/packages/ensure_installed_default_packages.test.ts b/x-pack/plugins/fleet/server/services/epm/packages/ensure_installed_default_packages.test.ts index aeb08bad06184..6c2a98450c1a7 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/ensure_installed_default_packages.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/ensure_installed_default_packages.test.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { ElasticsearchAssetType, Installation, KibanaSavedObjectType } from '../../../types'; -import { SavedObject, SavedObjectsClientContract } from 'src/core/server'; +import { ElasticsearchAssetType, KibanaSavedObjectType } from '../../../types'; +import type { Installation } from '../../../types'; +import type { SavedObject, SavedObjectsClientContract } from 'src/core/server'; jest.mock('./install'); jest.mock('./bulk_install_packages'); diff --git a/x-pack/plugins/fleet/server/services/epm/packages/get.test.ts b/x-pack/plugins/fleet/server/services/epm/packages/get.test.ts index afd150c3335af..354bcf88685cb 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/get.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/get.test.ts @@ -5,9 +5,10 @@ * 2.0. */ -import { SavedObjectsClientContract, SavedObjectsFindResult } from 'kibana/server'; +import type { SavedObjectsClientContract, SavedObjectsFindResult } from 'kibana/server'; import { savedObjectsClientMock } from '../../../../../../../src/core/server/mocks'; -import { PACKAGE_POLICY_SAVED_OBJECT_TYPE, PackagePolicySOAttributes } from '../../../../common'; +import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../../../../common'; +import type { PackagePolicySOAttributes } from '../../../../common'; import { getPackageUsageStats } from './get'; describe('When using EPM `get` services', () => { diff --git a/x-pack/plugins/fleet/server/services/epm/packages/get.ts b/x-pack/plugins/fleet/server/services/epm/packages/get.ts index c07b88a45e6dc..a32ac2ad4d88f 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/get.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/get.ts @@ -5,17 +5,21 @@ * 2.0. */ -import { SavedObjectsClientContract, SavedObjectsFindOptions } from 'src/core/server'; +import type { SavedObjectsClientContract, SavedObjectsFindOptions } from 'src/core/server'; import { isPackageLimited, installationStatuses, - PackageUsageStats, - PackagePolicySOAttributes, PACKAGE_POLICY_SAVED_OBJECT_TYPE, } from '../../../../common'; +import type { PackageUsageStats, PackagePolicySOAttributes } from '../../../../common'; import { PACKAGES_SAVED_OBJECT_TYPE } from '../../../constants'; -import { ArchivePackage, RegistryPackage, EpmPackageAdditions } from '../../../../common/types'; -import { Installation, PackageInfo, KibanaAssetType } from '../../../types'; +import type { + ArchivePackage, + RegistryPackage, + EpmPackageAdditions, +} from '../../../../common/types'; +import { KibanaAssetType } from '../../../types'; +import type { Installation, PackageInfo } from '../../../types'; import { IngestManagerError } from '../../../errors'; import * as Registry from '../registry'; import { createInstallableFrom, isRequiredPackage } from './index'; diff --git a/x-pack/plugins/fleet/server/services/epm/packages/get_install_type.test.ts b/x-pack/plugins/fleet/server/services/epm/packages/get_install_type.test.ts index f7bc2ce1b07b4..ae29a1c7956cf 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/get_install_type.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/get_install_type.test.ts @@ -5,9 +5,10 @@ * 2.0. */ -import { SavedObject } from 'src/core/server'; -import { ElasticsearchAssetType, Installation, KibanaSavedObjectType } from '../../../types'; import { getInstallType } from './install'; +import type { SavedObject } from 'src/core/server'; +import { ElasticsearchAssetType, KibanaSavedObjectType } from '../../../types'; +import type { Installation } from '../../../types'; const mockInstallation: SavedObject = { id: 'test-pkg', diff --git a/x-pack/plugins/fleet/server/services/epm/packages/index.ts b/x-pack/plugins/fleet/server/services/epm/packages/index.ts index b03d260e8e080..2dc845f94991e 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/index.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/index.ts @@ -5,14 +5,11 @@ * 2.0. */ -import { SavedObject } from 'src/core/server'; -import { - RequiredPackage, - requiredPackages, - ValueOf, - installationStatuses, -} from '../../../../common'; -import { AssetType, Installable, Installation, KibanaAssetType } from '../../../types'; +import type { SavedObject } from 'src/core/server'; +import { requiredPackages, installationStatuses } from '../../../../common'; +import type { RequiredPackage, ValueOf } from '../../../../common'; +import { KibanaAssetType } from '../../../types'; +import type { AssetType, Installable, Installation } from '../../../types'; export { bulkInstallPackages, isBulkInstallError } from './bulk_install_packages'; export { diff --git a/x-pack/plugins/fleet/server/services/epm/packages/install.ts b/x-pack/plugins/fleet/server/services/epm/packages/install.ts index ac3c0f3952127..96b4b63312edd 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/install.ts @@ -8,35 +8,32 @@ import semverGt from 'semver/functions/gt'; import semverLt from 'semver/functions/lt'; import Boom from '@hapi/boom'; -import { UnwrapPromise } from '@kbn/utility-types'; -import { SavedObject, SavedObjectsClientContract } from 'src/core/server'; +import type { UnwrapPromise } from '@kbn/utility-types'; +import type { SavedObject, SavedObjectsClientContract } from 'src/core/server'; import { generateESIndexPatterns } from '../elasticsearch/template/template'; -import { isRequiredPackage } from './index'; import { - BulkInstallPackageInfo, - InstallablePackage, - InstallSource, - defaultPackages, -} from '../../../../common'; + isRequiredPackage, + getInstallation, + getInstallationObject, + bulkInstallPackages, + isBulkInstallError, +} from './index'; +import { defaultPackages } from '../../../../common'; +import type { BulkInstallPackageInfo, InstallablePackage, InstallSource } from '../../../../common'; import { PACKAGES_SAVED_OBJECT_TYPE, MAX_TIME_COMPLETE_INSTALL } from '../../../constants'; -import { +import { KibanaAssetType } from '../../../types'; +import type { AssetReference, Installation, CallESAsCurrentUser, AssetType, EsAssetReference, InstallType, - KibanaAssetType, } from '../../../types'; import * as Registry from '../registry'; import { setPackageInfo, parseAndVerifyArchiveEntries, unpackBufferToCache } from '../archive'; -import { - getInstallation, - getInstallationObject, - bulkInstallPackages, - isBulkInstallError, -} from './index'; -import { toAssetReference, ArchiveAsset } from '../kibana/assets/install'; +import { toAssetReference } from '../kibana/assets/install'; +import type { ArchiveAsset } from '../kibana/assets/install'; import { removeInstallation } from './remove'; import { IngestManagerError, diff --git a/x-pack/plugins/fleet/server/services/epm/packages/remove.ts b/x-pack/plugins/fleet/server/services/epm/packages/remove.ts index 78471f70adc3c..4d05daaf82500 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/remove.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/remove.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'src/core/server'; +import type { SavedObjectsClientContract } from 'src/core/server'; import Boom from '@hapi/boom'; import { PACKAGE_POLICY_SAVED_OBJECT_TYPE, PACKAGES_SAVED_OBJECT_TYPE } from '../../../constants'; -import { +import { ElasticsearchAssetType } from '../../../types'; +import type { AssetReference, AssetType, CallESAsCurrentUser, - ElasticsearchAssetType, EsAssetReference, KibanaAssetReference, Installation, diff --git a/x-pack/plugins/fleet/server/services/epm/registry/index.test.ts b/x-pack/plugins/fleet/server/services/epm/registry/index.test.ts index ca476b4ee2033..e7ac5a0ce912e 100644 --- a/x-pack/plugins/fleet/server/services/epm/registry/index.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/registry/index.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { AssetParts } from '../../../types'; +import type { AssetParts } from '../../../types'; import { getBufferExtractor, getPathParts, untarBuffer, unzipBuffer } from '../archive'; import { splitPkgKey } from './index'; diff --git a/x-pack/plugins/fleet/server/services/epm/registry/index.ts b/x-pack/plugins/fleet/server/services/epm/registry/index.ts index bee979a58076b..8c5e2c9530b61 100644 --- a/x-pack/plugins/fleet/server/services/epm/registry/index.ts +++ b/x-pack/plugins/fleet/server/services/epm/registry/index.ts @@ -9,12 +9,12 @@ import mime from 'mime-types'; import semverValid from 'semver/functions/valid'; import { Response } from 'node-fetch'; import { URL } from 'url'; -import { +import { KibanaAssetType } from '../../../types'; +import type { AssetsGroupedByServiceByType, CategoryId, CategorySummaryList, InstallSource, - KibanaAssetType, RegistryPackage, RegistrySearchResults, RegistrySearchResult, diff --git a/x-pack/plugins/fleet/server/services/epm/registry/proxy.ts b/x-pack/plugins/fleet/server/services/epm/registry/proxy.ts index 655e1318d5134..0be25da2bca23 100644 --- a/x-pack/plugins/fleet/server/services/epm/registry/proxy.ts +++ b/x-pack/plugins/fleet/server/services/epm/registry/proxy.ts @@ -6,11 +6,10 @@ */ import HttpProxyAgent from 'http-proxy-agent'; -import HttpsProxyAgent, { - HttpsProxyAgent as IHttpsProxyAgent, - HttpsProxyAgentOptions, -} from 'https-proxy-agent'; +import HttpsProxyAgent, { HttpsProxyAgent as IHttpsProxyAgent } from 'https-proxy-agent'; +import type { HttpsProxyAgentOptions } from 'https-proxy-agent'; import { appContextService } from '../../index'; + export interface RegistryProxySettings { proxyUrl: string; proxyHeaders?: Record; diff --git a/x-pack/plugins/fleet/server/services/epm/registry/requests.ts b/x-pack/plugins/fleet/server/services/epm/registry/requests.ts index 8612e1d50d7e8..1b4abbc7e9b71 100644 --- a/x-pack/plugins/fleet/server/services/epm/registry/requests.ts +++ b/x-pack/plugins/fleet/server/services/epm/registry/requests.ts @@ -5,7 +5,8 @@ * 2.0. */ -import fetch, { FetchError, Response, RequestInit } from 'node-fetch'; +import fetch, { FetchError, Response } from 'node-fetch'; +import type { RequestInit } from 'node-fetch'; import pRetry from 'p-retry'; import { streamToString } from '../streams'; import { appContextService } from '../../app_context'; diff --git a/x-pack/plugins/fleet/server/services/es_index_pattern.ts b/x-pack/plugins/fleet/server/services/es_index_pattern.ts index 0d5a4c888e93f..015fb91a9660e 100644 --- a/x-pack/plugins/fleet/server/services/es_index_pattern.ts +++ b/x-pack/plugins/fleet/server/services/es_index_pattern.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'kibana/server'; +import type { SavedObjectsClientContract } from 'kibana/server'; import { getInstallation } from './epm/packages'; -import { ESIndexPatternService } from '../../server'; +import type { ESIndexPatternService } from '../../server'; export class ESIndexPatternSavedObjectService implements ESIndexPatternService { public async getESIndexPattern( diff --git a/x-pack/plugins/fleet/server/services/fleet_server/elastic_index.ts b/x-pack/plugins/fleet/server/services/fleet_server/elastic_index.ts index 4b85f753740e3..9722c28d96d23 100644 --- a/x-pack/plugins/fleet/server/services/fleet_server/elastic_index.ts +++ b/x-pack/plugins/fleet/server/services/fleet_server/elastic_index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ElasticsearchClient } from 'kibana/server'; +import type { ElasticsearchClient } from 'kibana/server'; import hash from 'object-hash'; import { FLEET_SERVER_INDICES, FLEET_SERVER_INDICES_VERSION } from '../../../common'; diff --git a/x-pack/plugins/fleet/server/services/fleet_server/saved_object_migrations.ts b/x-pack/plugins/fleet/server/services/fleet_server/saved_object_migrations.ts index 84e6b06e59844..d160925544adf 100644 --- a/x-pack/plugins/fleet/server/services/fleet_server/saved_object_migrations.ts +++ b/x-pack/plugins/fleet/server/services/fleet_server/saved_object_migrations.ts @@ -12,15 +12,16 @@ import { ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE, AGENT_POLICY_INDEX, AGENTS_INDEX, - FleetServerEnrollmentAPIKey, AGENT_SAVED_OBJECT_TYPE, + SO_SEARCH_LIMIT, +} from '../../../common'; +import type { + FleetServerEnrollmentAPIKey, AgentSOAttributes, FleetServerAgent, - SO_SEARCH_LIMIT, } from '../../../common'; import { listEnrollmentApiKeys, getEnrollmentAPIKey } from '../api_keys/enrollment_api_key_so'; import { appContextService } from '../app_context'; - import { isAgentsSetup } from '../agents'; import { agentPolicyService } from '../agent_policy'; diff --git a/x-pack/plugins/fleet/server/services/index.ts b/x-pack/plugins/fleet/server/services/index.ts index 77ce882275b6b..3f28a3f987a8e 100644 --- a/x-pack/plugins/fleet/server/services/index.ts +++ b/x-pack/plugins/fleet/server/services/index.ts @@ -5,13 +5,14 @@ * 2.0. */ -import { ElasticsearchClient, SavedObjectsClientContract, KibanaRequest } from 'kibana/server'; -import { AgentStatus, Agent, EsAssetReference } from '../types'; -import * as settingsService from './settings'; +import { KibanaRequest } from 'kibana/server'; +import type { ElasticsearchClient, SavedObjectsClientContract } from 'kibana/server'; +import type { AgentStatus, Agent, EsAssetReference } from '../types'; import { getAgent, listAgents } from './agents'; -export { ESIndexPatternSavedObjectService } from './es_index_pattern'; import { agentPolicyService } from './agent_policy'; +import * as settingsService from './settings'; +export { ESIndexPatternSavedObjectService } from './es_index_pattern'; export { getRegistryUrl } from './epm/registry/registry_url'; /** diff --git a/x-pack/plugins/fleet/server/services/install_script/install_templates/linux.ts b/x-pack/plugins/fleet/server/services/install_script/install_templates/linux.ts index dc04d099c4eb7..4e31193efc0e6 100644 --- a/x-pack/plugins/fleet/server/services/install_script/install_templates/linux.ts +++ b/x-pack/plugins/fleet/server/services/install_script/install_templates/linux.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { InstallTemplateFunction } from './types'; +import type { InstallTemplateFunction } from './types'; export const linuxInstallTemplate: InstallTemplateFunction = (variables) => { const artifact = `elastic-agent-${variables.kibanaVersion}-linux-x86_64`; diff --git a/x-pack/plugins/fleet/server/services/install_script/install_templates/macos.ts b/x-pack/plugins/fleet/server/services/install_script/install_templates/macos.ts index 14043fe8647fe..abe52f64d0e5c 100644 --- a/x-pack/plugins/fleet/server/services/install_script/install_templates/macos.ts +++ b/x-pack/plugins/fleet/server/services/install_script/install_templates/macos.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { InstallTemplateFunction } from './types'; +import type { InstallTemplateFunction } from './types'; export const macosInstallTemplate: InstallTemplateFunction = (variables) => { const artifact = `elastic-agent-${variables.kibanaVersion}-darwin-x86_64`; diff --git a/x-pack/plugins/fleet/server/services/output.ts b/x-pack/plugins/fleet/server/services/output.ts index c3e453bc0e24f..2301570c54cd2 100644 --- a/x-pack/plugins/fleet/server/services/output.ts +++ b/x-pack/plugins/fleet/server/services/output.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { SavedObjectsClientContract } from 'src/core/server'; -import { NewOutput, Output, OutputSOAttributes } from '../types'; +import type { SavedObjectsClientContract } from 'src/core/server'; +import type { NewOutput, Output, OutputSOAttributes } from '../types'; import { DEFAULT_OUTPUT, OUTPUT_SAVED_OBJECT_TYPE } from '../constants'; import { appContextService } from './app_context'; import { decodeCloudId } from '../../common'; 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 604592a0a8d87..e8991f2d66647 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.test.ts @@ -5,14 +5,17 @@ * 2.0. */ -import { elasticsearchServiceMock, savedObjectsClientMock } from 'src/core/server/mocks'; +import { + elasticsearchServiceMock, + savedObjectsClientMock, + httpServerMock, +} from 'src/core/server/mocks'; import { createPackagePolicyMock } from '../../common/mocks'; import { packagePolicyService } from './package_policy'; -import { PackageInfo, PackagePolicySOAttributes } from '../types'; -import { SavedObjectsUpdateResponse } from 'src/core/server'; -import { httpServerMock } from 'src/core/server/mocks'; +import type { PackageInfo, PackagePolicySOAttributes } from '../types'; +import type { SavedObjectsUpdateResponse } from 'src/core/server'; import { KibanaRequest } from 'kibana/server'; -import { ExternalCallback } from '..'; +import type { ExternalCallback } from '..'; import { appContextService } from './app_context'; import { createAppContextStartContractMock, xpackMocks } from '../mocks'; diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index 335cd7c956faf..3a350ded2d7ed 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -5,15 +5,20 @@ * 2.0. */ -import { +import { KibanaRequest } from 'src/core/server'; +import type { ElasticsearchClient, - KibanaRequest, RequestHandlerContext, SavedObjectsClientContract, } from 'src/core/server'; import uuid from 'uuid'; -import { AuthenticatedUser } from '../../../security/server'; +import type { AuthenticatedUser } from '../../../security/server'; import { + packageToPackagePolicy, + isPackageLimited, + doesAgentPolicyAlreadyIncludePackage, +} from '../../common'; +import type { DeletePackagePoliciesResponse, PackagePolicyInput, NewPackagePolicyInput, @@ -21,21 +26,17 @@ import { PackageInfo, ListWithKuery, ListResult, - packageToPackagePolicy, - isPackageLimited, - doesAgentPolicyAlreadyIncludePackage, } from '../../common'; import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../constants'; import { IngestManagerError, ingestErrorToResponseOptions } from '../errors'; -import { +import { NewPackagePolicySchema, UpdatePackagePolicySchema } from '../types'; +import type { NewPackagePolicy, UpdatePackagePolicy, PackagePolicy, PackagePolicySOAttributes, RegistryPackage, CallESAsCurrentUser, - NewPackagePolicySchema, - UpdatePackagePolicySchema, } from '../types'; import { agentPolicyService } from './agent_policy'; import { outputService } from './output'; @@ -45,7 +46,7 @@ import { getAssetsData } from './epm/packages/assets'; import { compileTemplate } from './epm/agent/agent'; import { normalizeKuery } from './saved_object'; import { appContextService } from '.'; -import { ExternalCallback } from '..'; +import type { ExternalCallback } from '..'; const SAVED_OBJECT_TYPE = PACKAGE_POLICY_SAVED_OBJECT_TYPE; diff --git a/x-pack/plugins/fleet/server/services/saved_object.ts b/x-pack/plugins/fleet/server/services/saved_object.ts index e6a792e4179f7..da416fa812cc4 100644 --- a/x-pack/plugins/fleet/server/services/saved_object.ts +++ b/x-pack/plugins/fleet/server/services/saved_object.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { SavedObjectsClientContract, SavedObjectsFindResponse } from 'src/core/server'; +import type { SavedObjectsClientContract, SavedObjectsFindResponse } from 'src/core/server'; import { SO_SEARCH_LIMIT } from '../constants'; -import { ListWithKuery } from '../types'; +import type { ListWithKuery } from '../types'; /** * Escape a value with double quote to use with saved object search diff --git a/x-pack/plugins/fleet/server/services/settings.ts b/x-pack/plugins/fleet/server/services/settings.ts index c58d3de9db1a7..01454c6217c05 100644 --- a/x-pack/plugins/fleet/server/services/settings.ts +++ b/x-pack/plugins/fleet/server/services/settings.ts @@ -6,15 +6,10 @@ */ import Boom from '@hapi/boom'; -import { SavedObjectsClientContract } from 'kibana/server'; +import type { SavedObjectsClientContract } from 'kibana/server'; import url from 'url'; -import { - GLOBAL_SETTINGS_SAVED_OBJECT_TYPE, - SettingsSOAttributes, - Settings, - decodeCloudId, - BaseSettings, -} from '../../common'; +import { GLOBAL_SETTINGS_SAVED_OBJECT_TYPE, decodeCloudId } from '../../common'; +import type { SettingsSOAttributes, Settings, BaseSettings } from '../../common'; import { appContextService } from './app_context'; export async function getSettings(soClient: SavedObjectsClientContract): Promise { diff --git a/x-pack/plugins/fleet/server/services/setup.ts b/x-pack/plugins/fleet/server/services/setup.ts index 2a3166e9dc729..b90f223629b60 100644 --- a/x-pack/plugins/fleet/server/services/setup.ts +++ b/x-pack/plugins/fleet/server/services/setup.ts @@ -6,8 +6,8 @@ */ import uuid from 'uuid'; -import { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; -import { CallESAsCurrentUser } from '../types'; +import type { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server'; +import type { CallESAsCurrentUser } from '../types'; import { agentPolicyService } from './agent_policy'; import { outputService } from './output'; import { @@ -17,13 +17,10 @@ import { } from './epm/packages/install'; import { packageToPackagePolicy, - PackagePolicy, - AgentPolicy, - Installation, - Output, DEFAULT_AGENT_POLICIES_PACKAGES, FLEET_SERVER_PACKAGE, } from '../../common'; +import type { PackagePolicy, AgentPolicy, Installation, Output } from '../../common'; import { SO_SEARCH_LIMIT } from '../constants'; import { getPackageInfo } from './epm/packages'; import { packagePolicyService } from './package_policy'; diff --git a/x-pack/plugins/fleet/server/types/rest_spec/common.ts b/x-pack/plugins/fleet/server/types/rest_spec/common.ts index 78af66dd50f41..2d12bd5d7c987 100644 --- a/x-pack/plugins/fleet/server/types/rest_spec/common.ts +++ b/x-pack/plugins/fleet/server/types/rest_spec/common.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { schema, TypeOf } from '@kbn/config-schema'; +import { schema } from '@kbn/config-schema'; +import type { TypeOf } from '@kbn/config-schema'; export const ListWithKuerySchema = schema.object({ page: schema.maybe(schema.number({ defaultValue: 1 })), diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/constants.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/constants.ts index 2c8fbfc749a82..e47036b82e594 100644 --- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/constants.ts +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/constants.ts @@ -13,26 +13,6 @@ export const POLICY_NAME = 'my_policy'; export const SNAPSHOT_POLICY_NAME = 'my_snapshot_policy'; export const NEW_SNAPSHOT_POLICY_NAME = 'my_new_snapshot_policy'; -export const DEFAULT_POLICY: PolicyFromES = { - version: 1, - modified_date: Date.now().toString(), - policy: { - name: 'my_policy', - phases: { - hot: { - min_age: '0ms', - actions: { - rollover: { - max_age: '30d', - max_size: '50gb', - }, - }, - }, - }, - }, - name: 'my_policy', -}; - export const POLICY_WITH_MIGRATE_OFF: PolicyFromES = { version: 1, modified_date: Date.now().toString(), @@ -191,6 +171,7 @@ export const POLICY_WITH_NODE_ROLE_ALLOCATION: PolicyFromES = { }, }, warm: { + min_age: '0ms', actions: {}, }, }, diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx index c61b431eed46d..b692d7fe69cd4 100644 --- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx @@ -183,13 +183,6 @@ export const setup = async (arg?: { const enable = (phase: Phases) => createFormToggleAction(`enablePhaseSwitch-${phase}`); - const showDataAllocationOptions = (phase: Phases) => () => { - act(() => { - find(`${phase}-dataTierAllocationControls.dataTierSelect`).simulate('click'); - }); - component.update(); - }; - const createMinAgeActions = (phase: Phases) => { return { hasMinAgeInput: () => exists(`${phase}-selectedMinimumAge`), @@ -384,7 +377,6 @@ export const setup = async (arg?: { }, warm: { enable: enable('warm'), - showDataAllocationOptions: showDataAllocationOptions('warm'), ...createMinAgeActions('warm'), setReplicas: setReplicas('warm'), hasErrorIndicator: () => exists('phaseErrorIndicator-warm'), @@ -396,7 +388,6 @@ export const setup = async (arg?: { }, cold: { enable: enable('cold'), - showDataAllocationOptions: showDataAllocationOptions('cold'), ...createMinAgeActions('cold'), setReplicas: setReplicas('cold'), setFreeze, diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts deleted file mode 100644 index 740aeebb852f1..0000000000000 --- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts +++ /dev/null @@ -1,1136 +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 { act } from 'react-dom/test-utils'; - -import { licensingMock } from '../../../../licensing/public/mocks'; -import { API_BASE_PATH } from '../../../common/constants'; -import { setupEnvironment } from '../helpers/setup_environment'; -import { EditPolicyTestBed, setup } from './edit_policy.helpers'; - -import { - DELETE_PHASE_POLICY, - NEW_SNAPSHOT_POLICY_NAME, - SNAPSHOT_POLICY_NAME, - DEFAULT_POLICY, - POLICY_WITH_MIGRATE_OFF, - POLICY_WITH_INCLUDE_EXCLUDE, - POLICY_WITH_NODE_ATTR_AND_OFF_ALLOCATION, - POLICY_WITH_NODE_ROLE_ALLOCATION, - POLICY_WITH_KNOWN_AND_UNKNOWN_FIELDS, - getDefaultHotPhasePolicy, -} from './constants'; - -describe('', () => { - let testBed: EditPolicyTestBed; - const { server, httpRequestsMockHelpers } = setupEnvironment(); - - afterAll(() => { - server.restore(); - }); - - describe('serialization', () => { - /** - * We assume that policies that populate this form are loaded directly from ES and so - * are valid according to ES. There may be settings in the policy created through the ILM - * API that the UI does not cater for, like the unfollow action. We do not want to overwrite - * the configuration for these actions in the UI. - */ - it('preserves policy settings it did not configure', async () => { - httpRequestsMockHelpers.setLoadPolicies([POLICY_WITH_KNOWN_AND_UNKNOWN_FIELDS]); - httpRequestsMockHelpers.setLoadSnapshotPolicies([]); - httpRequestsMockHelpers.setListNodes({ - nodesByRoles: {}, - nodesByAttributes: { test: ['123'] }, - isUsingDeprecatedDataRoleConfig: false, - }); - - await act(async () => { - testBed = await setup(); - }); - - const { component, actions } = testBed; - component.update(); - - // Set max docs to test whether we keep the unknown fields in that object after serializing - await actions.hot.setMaxDocs('1000'); - // Remove the delete phase to ensure that we also correctly remove data - await actions.delete.disablePhase(); - await actions.savePolicy(); - - const latestRequest = server.requests[server.requests.length - 1]; - const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body); - - expect(entirePolicy).toEqual({ - foo: 'bar', // Made up value - name: 'my_policy', - phases: { - hot: { - actions: { - rollover: { - max_docs: 1000, - max_size: '50gb', - unknown_setting: 123, // Made up setting that should stay preserved - }, - }, - min_age: '0ms', - }, - warm: { - actions: { - my_unfollow_action: {}, // Made up action - set_priority: { - priority: 22, - unknown_setting: true, - }, - }, - min_age: '0d', - }, - }, - }); - }); - }); - - describe('hot phase', () => { - describe('serialization', () => { - beforeEach(async () => { - httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]); - httpRequestsMockHelpers.setListNodes({ - nodesByRoles: {}, - nodesByAttributes: { test: ['123'] }, - isUsingDeprecatedDataRoleConfig: false, - }); - httpRequestsMockHelpers.setLoadSnapshotPolicies([]); - - await act(async () => { - testBed = await setup(); - }); - - const { component } = testBed; - component.update(); - }); - - test('setting all values', async () => { - const { actions } = testBed; - - await actions.hot.toggleDefaultRollover(false); - await actions.hot.setMaxSize('123', 'mb'); - await actions.hot.setMaxDocs('123'); - await actions.hot.setMaxAge('123', 'h'); - await actions.hot.toggleForceMerge(true); - await actions.hot.setForcemergeSegmentsCount('123'); - await actions.hot.setBestCompression(true); - await actions.hot.toggleShrink(true); - await actions.hot.setShrink('2'); - await actions.hot.toggleReadonly(true); - await actions.hot.toggleIndexPriority(true); - await actions.hot.setIndexPriority('123'); - - await actions.savePolicy(); - const latestRequest = server.requests[server.requests.length - 1]; - const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body); - expect(entirePolicy).toMatchInlineSnapshot(` - Object { - "name": "my_policy", - "phases": Object { - "hot": Object { - "actions": Object { - "forcemerge": Object { - "index_codec": "best_compression", - "max_num_segments": 123, - }, - "readonly": Object {}, - "rollover": Object { - "max_age": "123h", - "max_docs": 123, - "max_size": "123mb", - }, - "set_priority": Object { - "priority": 123, - }, - "shrink": Object { - "number_of_shards": 2, - }, - }, - "min_age": "0ms", - }, - }, - } - `); - }); - - test('setting searchable snapshot', async () => { - const { actions } = testBed; - - await actions.hot.setSearchableSnapshot('my-repo'); - - await actions.savePolicy(); - const latestRequest = server.requests[server.requests.length - 1]; - const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body); - expect(entirePolicy.phases.hot.actions.searchable_snapshot.snapshot_repository).toBe( - 'my-repo' - ); - }); - - test('disabling rollover', async () => { - const { actions } = testBed; - await actions.hot.toggleDefaultRollover(false); - await actions.hot.toggleRollover(false); - await actions.savePolicy(); - const latestRequest = server.requests[server.requests.length - 1]; - const policy = JSON.parse(JSON.parse(latestRequest.requestBody).body); - const hotActions = policy.phases.hot.actions; - const rolloverAction = hotActions.rollover; - expect(rolloverAction).toBe(undefined); - expect(hotActions).toMatchInlineSnapshot(`Object {}`); - }); - - test('enabling searchable snapshot should hide force merge, freeze and shrink in subsequent phases', async () => { - const { actions } = testBed; - - await actions.warm.enable(true); - await actions.cold.enable(true); - - expect(actions.warm.forceMergeFieldExists()).toBeTruthy(); - expect(actions.warm.shrinkExists()).toBeTruthy(); - expect(actions.cold.searchableSnapshotsExists()).toBeTruthy(); - expect(actions.cold.freezeExists()).toBeTruthy(); - - await actions.hot.setSearchableSnapshot('my-repo'); - - expect(actions.warm.forceMergeFieldExists()).toBeFalsy(); - expect(actions.warm.shrinkExists()).toBeFalsy(); - // searchable snapshot in cold is still visible - expect(actions.cold.searchableSnapshotsExists()).toBeTruthy(); - expect(actions.cold.freezeExists()).toBeFalsy(); - }); - - test('disabling rollover toggle, but enabling default rollover', async () => { - const { actions } = testBed; - await actions.hot.toggleDefaultRollover(false); - await actions.hot.toggleRollover(false); - await actions.hot.toggleDefaultRollover(true); - - expect(actions.hot.forceMergeFieldExists()).toBeTruthy(); - expect(actions.hot.shrinkExists()).toBeTruthy(); - expect(actions.hot.searchableSnapshotsExists()).toBeTruthy(); - }); - }); - }); - - describe('warm phase', () => { - describe('serialization', () => { - beforeEach(async () => { - httpRequestsMockHelpers.setLoadPolicies([DEFAULT_POLICY]); - httpRequestsMockHelpers.setListNodes({ - nodesByRoles: {}, - nodesByAttributes: { test: ['123'] }, - isUsingDeprecatedDataRoleConfig: false, - }); - httpRequestsMockHelpers.setLoadSnapshotPolicies([]); - - await act(async () => { - testBed = await setup(); - }); - - const { component } = testBed; - component.update(); - }); - - test('default values', async () => { - const { actions } = testBed; - await actions.warm.enable(true); - await actions.savePolicy(); - const latestRequest = server.requests[server.requests.length - 1]; - const warmPhase = JSON.parse(JSON.parse(latestRequest.requestBody).body).phases.warm; - expect(warmPhase).toMatchInlineSnapshot(` - Object { - "actions": Object { - "set_priority": Object { - "priority": 50, - }, - }, - "min_age": "0d", - } - `); - }); - - test('setting all values', async () => { - const { actions } = testBed; - await actions.warm.enable(true); - await actions.warm.setDataAllocation('node_attrs'); - await actions.warm.setSelectedNodeAttribute('test:123'); - await actions.warm.setReplicas('123'); - await actions.warm.toggleShrink(true); - await actions.warm.setShrink('123'); - await actions.warm.toggleForceMerge(true); - await actions.warm.setForcemergeSegmentsCount('123'); - await actions.warm.setBestCompression(true); - await actions.warm.toggleReadonly(true); - await actions.warm.setIndexPriority('123'); - await actions.savePolicy(); - const latestRequest = server.requests[server.requests.length - 1]; - const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body); - // Check shape of entire policy - expect(entirePolicy).toMatchInlineSnapshot(` - Object { - "name": "my_policy", - "phases": Object { - "hot": Object { - "actions": Object { - "rollover": Object { - "max_age": "30d", - "max_size": "50gb", - }, - }, - "min_age": "0ms", - }, - "warm": Object { - "actions": Object { - "allocate": Object { - "number_of_replicas": 123, - "require": Object { - "test": "123", - }, - }, - "forcemerge": Object { - "index_codec": "best_compression", - "max_num_segments": 123, - }, - "readonly": Object {}, - "set_priority": Object { - "priority": 123, - }, - "shrink": Object { - "number_of_shards": 123, - }, - }, - "min_age": "0d", - }, - }, - } - `); - }); - }); - - describe('policy with include and exclude', () => { - beforeEach(async () => { - httpRequestsMockHelpers.setLoadPolicies([POLICY_WITH_INCLUDE_EXCLUDE]); - httpRequestsMockHelpers.setListNodes({ - nodesByRoles: {}, - nodesByAttributes: { test: ['123'] }, - isUsingDeprecatedDataRoleConfig: false, - }); - httpRequestsMockHelpers.setLoadSnapshotPolicies([]); - - await act(async () => { - testBed = await setup(); - }); - - const { component } = testBed; - component.update(); - }); - - test('preserves include, exclude allocation settings', async () => { - const { actions } = testBed; - await actions.warm.setDataAllocation('node_attrs'); - await actions.warm.setSelectedNodeAttribute('test:123'); - await actions.savePolicy(); - const latestRequest = server.requests[server.requests.length - 1]; - const warmPhaseAllocate = JSON.parse(JSON.parse(latestRequest.requestBody).body).phases.warm - .actions.allocate; - expect(warmPhaseAllocate).toMatchInlineSnapshot(` - Object { - "exclude": Object { - "def": "456", - }, - "include": Object { - "abc": "123", - }, - "require": Object { - "test": "123", - }, - } - `); - }); - }); - }); - - describe('cold phase', () => { - describe('serialization', () => { - beforeEach(async () => { - httpRequestsMockHelpers.setLoadPolicies([DEFAULT_POLICY]); - httpRequestsMockHelpers.setListNodes({ - nodesByRoles: {}, - nodesByAttributes: { test: ['123'] }, - isUsingDeprecatedDataRoleConfig: false, - }); - httpRequestsMockHelpers.setLoadSnapshotPolicies([]); - - await act(async () => { - testBed = await setup(); - }); - - const { component } = testBed; - component.update(); - }); - - test('default values', async () => { - const { actions } = testBed; - - await actions.cold.enable(true); - await actions.savePolicy(); - const latestRequest = server.requests[server.requests.length - 1]; - const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body); - expect(entirePolicy.phases.cold).toMatchInlineSnapshot(` - Object { - "actions": Object { - "set_priority": Object { - "priority": 0, - }, - }, - "min_age": "0d", - } - `); - }); - - test('setting all values, excluding searchable snapshot', async () => { - const { actions } = testBed; - - await actions.cold.enable(true); - await actions.cold.setMinAgeValue('123'); - await actions.cold.setMinAgeUnits('s'); - await actions.cold.setDataAllocation('node_attrs'); - await actions.cold.setSelectedNodeAttribute('test:123'); - await actions.cold.setSearchableSnapshot('my-repo'); - await actions.cold.setReplicas('123'); - await actions.cold.setFreeze(true); - await actions.cold.setIndexPriority('123'); - - await actions.savePolicy(); - const latestRequest = server.requests[server.requests.length - 1]; - const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body); - - expect(entirePolicy).toMatchInlineSnapshot(` - Object { - "name": "my_policy", - "phases": Object { - "cold": Object { - "actions": Object { - "allocate": Object { - "number_of_replicas": 123, - "require": Object { - "test": "123", - }, - }, - "freeze": Object {}, - "searchable_snapshot": Object { - "snapshot_repository": "my-repo", - }, - "set_priority": Object { - "priority": 123, - }, - }, - "min_age": "123s", - }, - "hot": Object { - "actions": Object { - "rollover": Object { - "max_age": "30d", - "max_size": "50gb", - }, - }, - "min_age": "0ms", - }, - }, - } - `); - }); - }); - }); - - describe('delete phase', () => { - beforeEach(async () => { - httpRequestsMockHelpers.setLoadPolicies([DELETE_PHASE_POLICY]); - httpRequestsMockHelpers.setLoadSnapshotPolicies([ - SNAPSHOT_POLICY_NAME, - NEW_SNAPSHOT_POLICY_NAME, - ]); - - await act(async () => { - testBed = await setup(); - }); - - const { component } = testBed; - component.update(); - }); - - test('serialization', async () => { - httpRequestsMockHelpers.setLoadPolicies([DEFAULT_POLICY]); - await act(async () => { - testBed = await setup(); - }); - const { component, actions } = testBed; - component.update(); - await actions.delete.enablePhase(); - await actions.setWaitForSnapshotPolicy('test'); - await actions.savePolicy(); - const latestRequest = server.requests[server.requests.length - 1]; - const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body); - expect(entirePolicy.phases.delete).toEqual({ - min_age: '365d', - actions: { - delete: {}, - wait_for_snapshot: { - policy: 'test', - }, - }, - }); - }); - - test('wait for snapshot policy field should correctly display snapshot policy name', () => { - expect(testBed.find('snapshotPolicyCombobox').prop('data-currentvalue')).toEqual([ - { - label: DELETE_PHASE_POLICY.policy.phases.delete?.actions.wait_for_snapshot?.policy, - }, - ]); - }); - - test('wait for snapshot field should correctly update snapshot policy name', async () => { - const { actions } = testBed; - - await actions.setWaitForSnapshotPolicy(NEW_SNAPSHOT_POLICY_NAME); - await actions.savePolicy(); - - const expected = { - name: DELETE_PHASE_POLICY.name, - phases: { - ...DELETE_PHASE_POLICY.policy.phases, - delete: { - ...DELETE_PHASE_POLICY.policy.phases.delete, - actions: { - ...DELETE_PHASE_POLICY.policy.phases.delete?.actions, - wait_for_snapshot: { - policy: NEW_SNAPSHOT_POLICY_NAME, - }, - }, - }, - }, - }; - - const latestRequest = server.requests[server.requests.length - 1]; - expect(latestRequest.url).toBe(`${API_BASE_PATH}/policies`); - expect(latestRequest.method).toBe('POST'); - expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual(expected); - }); - - test('wait for snapshot field should display a callout when the input is not an existing policy', async () => { - const { actions } = testBed; - - await actions.setWaitForSnapshotPolicy('my_custom_policy'); - expect(testBed.find('noPoliciesCallout').exists()).toBeFalsy(); - expect(testBed.find('policiesErrorCallout').exists()).toBeFalsy(); - expect(testBed.find('customPolicyCallout').exists()).toBeTruthy(); - }); - - test('wait for snapshot field should delete action if field is empty', async () => { - const { actions } = testBed; - - await actions.setWaitForSnapshotPolicy(''); - await actions.savePolicy(); - - const expected = { - name: DELETE_PHASE_POLICY.name, - phases: { - ...DELETE_PHASE_POLICY.policy.phases, - delete: { - ...DELETE_PHASE_POLICY.policy.phases.delete, - actions: { - ...DELETE_PHASE_POLICY.policy.phases.delete?.actions, - }, - }, - }, - }; - - delete expected.phases.delete.actions.wait_for_snapshot; - - const latestRequest = server.requests[server.requests.length - 1]; - expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual(expected); - }); - - test('wait for snapshot field should display a callout when there are no snapshot policies', async () => { - // need to call setup on testBed again for it to use a newly defined snapshot policies response - httpRequestsMockHelpers.setLoadSnapshotPolicies([]); - await act(async () => { - testBed = await setup(); - }); - - testBed.component.update(); - expect(testBed.find('customPolicyCallout').exists()).toBeFalsy(); - expect(testBed.find('policiesErrorCallout').exists()).toBeFalsy(); - expect(testBed.find('noPoliciesCallout').exists()).toBeTruthy(); - }); - - test('wait for snapshot field should display a callout when there is an error loading snapshot policies', async () => { - // need to call setup on testBed again for it to use a newly defined snapshot policies response - httpRequestsMockHelpers.setLoadSnapshotPolicies([], { status: 500, body: 'error' }); - await act(async () => { - testBed = await setup(); - }); - - testBed.component.update(); - expect(testBed.find('customPolicyCallout').exists()).toBeFalsy(); - expect(testBed.find('noPoliciesCallout').exists()).toBeFalsy(); - expect(testBed.find('policiesErrorCallout').exists()).toBeTruthy(); - }); - }); - - describe('data allocation', () => { - beforeEach(async () => { - httpRequestsMockHelpers.setLoadPolicies([POLICY_WITH_MIGRATE_OFF]); - httpRequestsMockHelpers.setListNodes({ - nodesByRoles: {}, - nodesByAttributes: { test: ['123'] }, - isUsingDeprecatedDataRoleConfig: false, - }); - httpRequestsMockHelpers.setLoadSnapshotPolicies([]); - - await act(async () => { - testBed = await setup(); - }); - - const { component } = testBed; - component.update(); - }); - - test('setting node_attr based allocation, but not selecting node attribute', async () => { - const { actions } = testBed; - await actions.warm.setDataAllocation('node_attrs'); - await actions.savePolicy(); - const latestRequest = server.requests[server.requests.length - 1]; - const warmPhase = JSON.parse(JSON.parse(latestRequest.requestBody).body).phases.warm; - - expect(warmPhase.actions.migrate).toEqual({ enabled: false }); - }); - - describe('node roles', () => { - beforeEach(async () => { - httpRequestsMockHelpers.setLoadPolicies([POLICY_WITH_NODE_ROLE_ALLOCATION]); - httpRequestsMockHelpers.setListNodes({ - isUsingDeprecatedDataRoleConfig: false, - nodesByAttributes: { test: ['123'] }, - nodesByRoles: { data: ['123'] }, - }); - - await act(async () => { - testBed = await setup(); - }); - - const { component } = testBed; - component.update(); - }); - - test('detecting use of the recommended allocation type', () => { - const { find } = testBed; - const selectedDataAllocation = find( - 'warm-dataTierAllocationControls.dataTierSelect' - ).text(); - expect(selectedDataAllocation).toBe('Use warm nodes (recommended)'); - }); - - test('setting replicas serialization', async () => { - const { actions } = testBed; - await actions.warm.setReplicas('123'); - await actions.savePolicy(); - const latestRequest = server.requests[server.requests.length - 1]; - const warmPhaseActions = JSON.parse(JSON.parse(latestRequest.requestBody).body).phases.warm - .actions; - expect(warmPhaseActions).toMatchInlineSnapshot(` - Object { - "allocate": Object { - "number_of_replicas": 123, - }, - } - `); - }); - }); - - describe('node attr and none', () => { - beforeEach(async () => { - httpRequestsMockHelpers.setLoadPolicies([POLICY_WITH_NODE_ATTR_AND_OFF_ALLOCATION]); - httpRequestsMockHelpers.setListNodes({ - isUsingDeprecatedDataRoleConfig: false, - nodesByAttributes: { test: ['123'] }, - nodesByRoles: { data: ['123'] }, - }); - - await act(async () => { - testBed = await setup(); - }); - - const { component } = testBed; - component.update(); - }); - - test('detecting use of the custom allocation type', () => { - const { find } = testBed; - expect(find('warm-dataTierAllocationControls.dataTierSelect').text()).toBe('Custom'); - }); - test('detecting use of the "off" allocation type', () => { - const { find } = testBed; - expect(find('cold-dataTierAllocationControls.dataTierSelect').text()).toContain('Off'); - }); - }); - describe('on cloud', () => { - describe('using legacy data role config', () => { - beforeEach(async () => { - httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]); - httpRequestsMockHelpers.setListNodes({ - nodesByAttributes: { test: ['123'] }, - // On cloud, even if there are data_* roles set, the default, recommended allocation option should not - // be available. - nodesByRoles: { data_hot: ['123'] }, - isUsingDeprecatedDataRoleConfig: true, - }); - httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['found-snapshots'] }); - - await act(async () => { - testBed = await setup({ - appServicesContext: { - cloud: { - isCloudEnabled: true, - }, - license: licensingMock.createLicense({ license: { type: 'basic' } }), - }, - }); - }); - - const { component } = testBed; - component.update(); - }); - test('removes default, recommended option', async () => { - const { actions, find } = testBed; - await actions.warm.enable(true); - actions.warm.showDataAllocationOptions(); - - expect(find('defaultDataAllocationOption').exists()).toBeFalsy(); - expect(find('customDataAllocationOption').exists()).toBeTruthy(); - expect(find('noneDataAllocationOption').exists()).toBeTruthy(); - // Show the call-to-action for users to migrate their cluster to use node roles - expect(find('cloudDataTierCallout').exists()).toBeTruthy(); - }); - }); - describe('using node roles', () => { - beforeEach(async () => { - httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]); - httpRequestsMockHelpers.setListNodes({ - nodesByAttributes: { test: ['123'] }, - nodesByRoles: { data_hot: ['123'] }, - isUsingDeprecatedDataRoleConfig: false, - }); - httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['found-snapshots'] }); - - await act(async () => { - testBed = await setup({ appServicesContext: { cloud: { isCloudEnabled: true } } }); - }); - - const { component } = testBed; - component.update(); - }); - - test('should show recommended, custom and "off" options on cloud with data roles', async () => { - const { actions, find } = testBed; - - await actions.warm.enable(true); - actions.warm.showDataAllocationOptions(); - expect(find('defaultDataAllocationOption').exists()).toBeTruthy(); - expect(find('customDataAllocationOption').exists()).toBeTruthy(); - expect(find('noneDataAllocationOption').exists()).toBeTruthy(); - // We should not be showing the call-to-action for users to activate the cold tier on cloud - expect(find('cloudMissingColdTierCallout').exists()).toBeFalsy(); - // Do not show the call-to-action for users to migrate their cluster to use node roles - expect(find('cloudDataTierCallout').exists()).toBeFalsy(); - }); - - test('should show cloud notice when cold tier nodes do not exist', async () => { - const { actions, find } = testBed; - await actions.cold.enable(true); - expect(find('cloudMissingColdTierCallout').exists()).toBeTruthy(); - // Assert that other notices are not showing - expect(find('defaultAllocationNotice').exists()).toBeFalsy(); - expect(find('noNodeAttributesWarning').exists()).toBeFalsy(); - }); - }); - }); - }); - - describe('searchable snapshot', () => { - describe('on non-enterprise license', () => { - beforeEach(async () => { - httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]); - httpRequestsMockHelpers.setListNodes({ - isUsingDeprecatedDataRoleConfig: false, - nodesByAttributes: { test: ['123'] }, - nodesByRoles: { data: ['123'] }, - }); - httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['found-snapshots'] }); - - await act(async () => { - testBed = await setup({ - appServicesContext: { - license: licensingMock.createLicense({ license: { type: 'basic' } }), - }, - }); - }); - - const { component } = testBed; - component.update(); - }); - test('disable setting searchable snapshots', async () => { - const { actions } = testBed; - - expect(actions.cold.searchableSnapshotsExists()).toBeFalsy(); - expect(actions.hot.searchableSnapshotsExists()).toBeFalsy(); - - await actions.cold.enable(true); - - // Still hidden in hot - expect(actions.hot.searchableSnapshotsExists()).toBeFalsy(); - - expect(actions.cold.searchableSnapshotsExists()).toBeTruthy(); - expect(actions.cold.searchableSnapshotDisabledDueToLicense()).toBeTruthy(); - }); - }); - - describe('on cloud', () => { - describe('new policy', () => { - beforeEach(async () => { - // simulate creating a new policy - httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('')]); - httpRequestsMockHelpers.setListNodes({ - nodesByAttributes: { test: ['123'] }, - nodesByRoles: { data: ['123'] }, - isUsingDeprecatedDataRoleConfig: false, - }); - httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['found-snapshots'] }); - - await act(async () => { - testBed = await setup({ appServicesContext: { cloud: { isCloudEnabled: true } } }); - }); - - const { component } = testBed; - component.update(); - }); - test('defaults searchable snapshot to true on cloud', async () => { - const { find, actions } = testBed; - await actions.cold.enable(true); - expect( - find('searchableSnapshotField-cold.searchableSnapshotToggle').props()['aria-checked'] - ).toBe(true); - }); - }); - describe('existing policy', () => { - beforeEach(async () => { - httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]); - httpRequestsMockHelpers.setListNodes({ - isUsingDeprecatedDataRoleConfig: false, - nodesByAttributes: { test: ['123'] }, - nodesByRoles: { data_hot: ['123'] }, - }); - httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['found-snapshots'] }); - - await act(async () => { - testBed = await setup({ appServicesContext: { cloud: { isCloudEnabled: true } } }); - }); - - const { component } = testBed; - component.update(); - }); - test('correctly sets snapshot repository default to "found-snapshots"', async () => { - const { actions } = testBed; - await actions.cold.enable(true); - await actions.cold.toggleSearchableSnapshot(true); - await actions.savePolicy(); - const latestRequest = server.requests[server.requests.length - 1]; - const request = JSON.parse(JSON.parse(latestRequest.requestBody).body); - expect(request.phases.cold.actions.searchable_snapshot.snapshot_repository).toEqual( - 'found-snapshots' - ); - }); - }); - }); - }); - describe('with rollover', () => { - beforeEach(async () => { - httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]); - httpRequestsMockHelpers.setListNodes({ - isUsingDeprecatedDataRoleConfig: false, - nodesByAttributes: { test: ['123'] }, - nodesByRoles: { data: ['123'] }, - }); - httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['abc'] }); - httpRequestsMockHelpers.setLoadSnapshotPolicies([]); - - await act(async () => { - testBed = await setup(); - }); - - const { component } = testBed; - component.update(); - }); - - test('shows rollover tip on minimum age', async () => { - const { actions } = testBed; - - await actions.warm.enable(true); - await actions.cold.enable(true); - await actions.delete.enablePhase(); - - expect(actions.warm.hasRolloverTipOnMinAge()).toBeTruthy(); - expect(actions.cold.hasRolloverTipOnMinAge()).toBeTruthy(); - expect(actions.delete.hasRolloverTipOnMinAge()).toBeTruthy(); - }); - }); - - describe('without rollover', () => { - beforeEach(async () => { - httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]); - httpRequestsMockHelpers.setListNodes({ - isUsingDeprecatedDataRoleConfig: false, - nodesByAttributes: { test: ['123'] }, - nodesByRoles: { data: ['123'] }, - }); - httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['found-snapshots'] }); - httpRequestsMockHelpers.setLoadSnapshotPolicies([]); - - await act(async () => { - testBed = await setup({ - appServicesContext: { - license: licensingMock.createLicense({ license: { type: 'enterprise' } }), - }, - }); - }); - - const { component } = testBed; - component.update(); - }); - test('hides fields in hot phase', async () => { - const { actions } = testBed; - await actions.hot.toggleDefaultRollover(false); - await actions.hot.toggleRollover(false); - - expect(actions.hot.forceMergeFieldExists()).toBeFalsy(); - expect(actions.hot.shrinkExists()).toBeFalsy(); - expect(actions.hot.searchableSnapshotsExists()).toBeFalsy(); - expect(actions.hot.readonlyExists()).toBeFalsy(); - }); - - test('hiding rollover tip on minimum age', async () => { - const { actions } = testBed; - await actions.hot.toggleDefaultRollover(false); - await actions.hot.toggleRollover(false); - - await actions.warm.enable(true); - await actions.cold.enable(true); - await actions.delete.enablePhase(); - - expect(actions.warm.hasRolloverTipOnMinAge()).toBeFalsy(); - expect(actions.cold.hasRolloverTipOnMinAge()).toBeFalsy(); - expect(actions.delete.hasRolloverTipOnMinAge()).toBeFalsy(); - }); - }); - - describe('policy timeline', () => { - beforeEach(async () => { - httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]); - httpRequestsMockHelpers.setListNodes({ - nodesByRoles: {}, - nodesByAttributes: { test: ['123'] }, - isUsingDeprecatedDataRoleConfig: false, - }); - httpRequestsMockHelpers.setLoadSnapshotPolicies([]); - - await act(async () => { - testBed = await setup(); - }); - - const { component } = testBed; - component.update(); - }); - - test('showing all phases on the timeline', async () => { - const { actions } = testBed; - // This is how the default policy should look - expect(actions.timeline.hasHotPhase()).toBe(true); - expect(actions.timeline.hasWarmPhase()).toBe(false); - expect(actions.timeline.hasColdPhase()).toBe(false); - expect(actions.timeline.hasDeletePhase()).toBe(false); - - await actions.warm.enable(true); - expect(actions.timeline.hasHotPhase()).toBe(true); - expect(actions.timeline.hasWarmPhase()).toBe(true); - expect(actions.timeline.hasColdPhase()).toBe(false); - expect(actions.timeline.hasDeletePhase()).toBe(false); - - await actions.cold.enable(true); - expect(actions.timeline.hasHotPhase()).toBe(true); - expect(actions.timeline.hasWarmPhase()).toBe(true); - expect(actions.timeline.hasColdPhase()).toBe(true); - expect(actions.timeline.hasDeletePhase()).toBe(false); - - await actions.delete.enablePhase(); - expect(actions.timeline.hasHotPhase()).toBe(true); - expect(actions.timeline.hasWarmPhase()).toBe(true); - expect(actions.timeline.hasColdPhase()).toBe(true); - expect(actions.timeline.hasDeletePhase()).toBe(true); - }); - }); - - describe('policy error notifications', () => { - let runTimers: () => void; - beforeAll(() => { - jest.useFakeTimers(); - }); - - afterAll(() => { - jest.useRealTimers(); - }); - - beforeEach(async () => { - httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]); - httpRequestsMockHelpers.setListNodes({ - nodesByRoles: {}, - nodesByAttributes: { test: ['123'] }, - isUsingDeprecatedDataRoleConfig: false, - }); - httpRequestsMockHelpers.setLoadSnapshotPolicies([]); - - await act(async () => { - testBed = await setup(); - }); - - const { component } = testBed; - component.update(); - - ({ runTimers } = testBed); - }); - - test('shows phase error indicators correctly', async () => { - // This test simulates a user configuring a policy phase by phase. The flow is the following: - // 0. Start with policy with no validation issues present - // 1. Configure hot, introducing a validation error - // 2. Configure warm, introducing a validation error - // 3. Configure cold, introducing a validation error - // 4. Fix validation error in hot - // 5. Fix validation error in warm - // 6. Fix validation error in cold - // We assert against each of these progressive states. - - const { actions } = testBed; - - // 0. No validation issues - expect(actions.hasGlobalErrorCallout()).toBe(false); - expect(actions.hot.hasErrorIndicator()).toBe(false); - expect(actions.warm.hasErrorIndicator()).toBe(false); - expect(actions.cold.hasErrorIndicator()).toBe(false); - - // 1. Hot phase validation issue - await actions.hot.toggleForceMerge(true); - await actions.hot.setForcemergeSegmentsCount('-22'); - runTimers(); - expect(actions.hasGlobalErrorCallout()).toBe(true); - expect(actions.hot.hasErrorIndicator()).toBe(true); - expect(actions.warm.hasErrorIndicator()).toBe(false); - expect(actions.cold.hasErrorIndicator()).toBe(false); - - // 2. Warm phase validation issue - await actions.warm.enable(true); - await actions.warm.toggleForceMerge(true); - await actions.warm.setForcemergeSegmentsCount('-22'); - runTimers(); - expect(actions.hasGlobalErrorCallout()).toBe(true); - expect(actions.hot.hasErrorIndicator()).toBe(true); - expect(actions.warm.hasErrorIndicator()).toBe(true); - expect(actions.cold.hasErrorIndicator()).toBe(false); - - // 3. Cold phase validation issue - await actions.cold.enable(true); - await actions.cold.setReplicas('-33'); - runTimers(); - expect(actions.hasGlobalErrorCallout()).toBe(true); - expect(actions.hot.hasErrorIndicator()).toBe(true); - expect(actions.warm.hasErrorIndicator()).toBe(true); - expect(actions.cold.hasErrorIndicator()).toBe(true); - - // 4. Fix validation issue in hot - await actions.hot.setForcemergeSegmentsCount('1'); - runTimers(); - expect(actions.hasGlobalErrorCallout()).toBe(true); - expect(actions.hot.hasErrorIndicator()).toBe(false); - expect(actions.warm.hasErrorIndicator()).toBe(true); - expect(actions.cold.hasErrorIndicator()).toBe(true); - - // 5. Fix validation issue in warm - await actions.warm.setForcemergeSegmentsCount('1'); - runTimers(); - expect(actions.hasGlobalErrorCallout()).toBe(true); - expect(actions.hot.hasErrorIndicator()).toBe(false); - expect(actions.warm.hasErrorIndicator()).toBe(false); - expect(actions.cold.hasErrorIndicator()).toBe(true); - - // 6. Fix validation issue in cold - await actions.cold.setReplicas('1'); - runTimers(); - expect(actions.hasGlobalErrorCallout()).toBe(false); - expect(actions.hot.hasErrorIndicator()).toBe(false); - expect(actions.warm.hasErrorIndicator()).toBe(false); - expect(actions.cold.hasErrorIndicator()).toBe(false); - }); - - test('global error callout should show if there are any form errors', async () => { - const { actions } = testBed; - - expect(actions.hasGlobalErrorCallout()).toBe(false); - expect(actions.hot.hasErrorIndicator()).toBe(false); - expect(actions.warm.hasErrorIndicator()).toBe(false); - expect(actions.cold.hasErrorIndicator()).toBe(false); - - await actions.saveAsNewPolicy(true); - await actions.setPolicyName(''); - runTimers(); - - expect(actions.hasGlobalErrorCallout()).toBe(true); - expect(actions.hot.hasErrorIndicator()).toBe(false); - expect(actions.warm.hasErrorIndicator()).toBe(false); - expect(actions.cold.hasErrorIndicator()).toBe(false); - }); - - test('clears all error indicators if last erroring field is unmounted', async () => { - const { actions } = testBed; - - await actions.cold.enable(true); - // introduce validation error - await actions.cold.setSearchableSnapshot(''); - runTimers(); - - await actions.savePolicy(); - runTimers(); - - expect(actions.hasGlobalErrorCallout()).toBe(true); - expect(actions.hot.hasErrorIndicator()).toBe(false); - expect(actions.warm.hasErrorIndicator()).toBe(false); - expect(actions.cold.hasErrorIndicator()).toBe(true); - - // unmount the field - await actions.cold.toggleSearchableSnapshot(false); - - expect(actions.hasGlobalErrorCallout()).toBe(false); - expect(actions.hot.hasErrorIndicator()).toBe(false); - expect(actions.warm.hasErrorIndicator()).toBe(false); - expect(actions.cold.hasErrorIndicator()).toBe(false); - }); - }); -}); diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/cold_phase.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/cold_phase.test.ts new file mode 100644 index 0000000000000..dfb7411eb941f --- /dev/null +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/cold_phase.test.ts @@ -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 { act } from 'react-dom/test-utils'; +import { setupEnvironment } from '../../helpers/setup_environment'; +import { EditPolicyTestBed, setup } from '../edit_policy.helpers'; +import { getDefaultHotPhasePolicy } from '../constants'; + +describe(' cold phase', () => { + let testBed: EditPolicyTestBed; + const { server, httpRequestsMockHelpers } = setupEnvironment(); + + beforeAll(() => { + jest.useFakeTimers(); + }); + + afterAll(() => { + jest.useRealTimers(); + server.restore(); + }); + + beforeEach(async () => { + httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]); + httpRequestsMockHelpers.setListNodes({ + nodesByRoles: { data: ['node1'] }, + nodesByAttributes: { 'attribute:true': ['node1'] }, + isUsingDeprecatedDataRoleConfig: true, + }); + httpRequestsMockHelpers.setNodesDetails('attribute:true', [ + { nodeId: 'testNodeId', stats: { name: 'testNodeName', host: 'testHost' } }, + ]); + httpRequestsMockHelpers.setLoadSnapshotPolicies([]); + + await act(async () => { + testBed = await setup(); + }); + + const { component } = testBed; + component.update(); + }); + + test('shows timing only when enabled', async () => { + const { actions } = testBed; + expect(actions.cold.hasMinAgeInput()).toBeFalsy(); + await actions.cold.enable(true); + expect(actions.cold.hasMinAgeInput()).toBeTruthy(); + }); +}); diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/delete_phase.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/delete_phase.test.ts new file mode 100644 index 0000000000000..0fb4951e4a4a6 --- /dev/null +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/delete_phase.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 { + DELETE_PHASE_POLICY, + getDefaultHotPhasePolicy, + NEW_SNAPSHOT_POLICY_NAME, + SNAPSHOT_POLICY_NAME, +} from '../constants'; +import { act } from 'react-dom/test-utils'; +import { EditPolicyTestBed, setup } from '../edit_policy.helpers'; +import { API_BASE_PATH } from '../../../../common/constants'; +import { setupEnvironment } from '../../helpers/setup_environment'; + +describe(' delete phase', () => { + let testBed: EditPolicyTestBed; + const { server, httpRequestsMockHelpers } = setupEnvironment(); + + afterAll(() => { + server.restore(); + }); + + beforeEach(async () => { + httpRequestsMockHelpers.setLoadPolicies([DELETE_PHASE_POLICY]); + httpRequestsMockHelpers.setLoadSnapshotPolicies([ + SNAPSHOT_POLICY_NAME, + NEW_SNAPSHOT_POLICY_NAME, + ]); + + await act(async () => { + testBed = await setup(); + }); + + const { component } = testBed; + component.update(); + }); + + test('is hidden when disabled', async () => { + httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]); + + await act(async () => { + testBed = await setup(); + }); + + const { component, actions } = testBed; + component.update(); + + expect(actions.delete.isShown()).toBeFalsy(); + await actions.delete.enablePhase(); + expect(actions.delete.isShown()).toBeTruthy(); + }); + + test('shows timing after it was enabled', async () => { + httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]); + + await act(async () => { + testBed = await setup(); + }); + + const { component, actions } = testBed; + component.update(); + + expect(actions.delete.hasMinAgeInput()).toBeFalsy(); + await actions.delete.enablePhase(); + expect(actions.delete.hasMinAgeInput()).toBeTruthy(); + }); + + describe('wait for snapshot', () => { + test('shows snapshot policy name', () => { + expect(testBed.find('snapshotPolicyCombobox').prop('data-currentvalue')).toEqual([ + { + label: DELETE_PHASE_POLICY.policy.phases.delete?.actions.wait_for_snapshot?.policy, + }, + ]); + }); + + test('updates snapshot policy name', async () => { + const { actions } = testBed; + + await actions.setWaitForSnapshotPolicy(NEW_SNAPSHOT_POLICY_NAME); + await actions.savePolicy(); + + const expected = { + name: DELETE_PHASE_POLICY.name, + phases: { + ...DELETE_PHASE_POLICY.policy.phases, + delete: { + ...DELETE_PHASE_POLICY.policy.phases.delete, + actions: { + ...DELETE_PHASE_POLICY.policy.phases.delete?.actions, + wait_for_snapshot: { + policy: NEW_SNAPSHOT_POLICY_NAME, + }, + }, + }, + }, + }; + + const latestRequest = server.requests[server.requests.length - 1]; + expect(latestRequest.url).toBe(`${API_BASE_PATH}/policies`); + expect(latestRequest.method).toBe('POST'); + expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual(expected); + }); + + test('shows a callout when the input is not an existing policy', async () => { + const { actions } = testBed; + + await actions.setWaitForSnapshotPolicy('my_custom_policy'); + expect(testBed.find('noPoliciesCallout').exists()).toBeFalsy(); + expect(testBed.find('policiesErrorCallout').exists()).toBeFalsy(); + expect(testBed.find('customPolicyCallout').exists()).toBeTruthy(); + }); + + test('removes the action if field is empty', async () => { + const { actions } = testBed; + + await actions.setWaitForSnapshotPolicy(''); + await actions.savePolicy(); + + const expected = { + name: DELETE_PHASE_POLICY.name, + phases: { + ...DELETE_PHASE_POLICY.policy.phases, + delete: { + ...DELETE_PHASE_POLICY.policy.phases.delete, + actions: { + ...DELETE_PHASE_POLICY.policy.phases.delete?.actions, + }, + }, + }, + }; + + delete expected.phases.delete.actions.wait_for_snapshot; + + const latestRequest = server.requests[server.requests.length - 1]; + expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual(expected); + }); + + test('shows a callout when there are no snapshot policies', async () => { + // need to call setup on testBed again for it to use a newly defined snapshot policies response + httpRequestsMockHelpers.setLoadSnapshotPolicies([]); + await act(async () => { + testBed = await setup(); + }); + + testBed.component.update(); + expect(testBed.find('customPolicyCallout').exists()).toBeFalsy(); + expect(testBed.find('policiesErrorCallout').exists()).toBeFalsy(); + expect(testBed.find('noPoliciesCallout').exists()).toBeTruthy(); + }); + + test('shows a callout when there is an error loading snapshot policies', async () => { + // need to call setup on testBed again for it to use a newly defined snapshot policies response + httpRequestsMockHelpers.setLoadSnapshotPolicies([], { status: 500, body: 'error' }); + await act(async () => { + testBed = await setup(); + }); + + testBed.component.update(); + expect(testBed.find('customPolicyCallout').exists()).toBeFalsy(); + expect(testBed.find('noPoliciesCallout').exists()).toBeFalsy(); + expect(testBed.find('policiesErrorCallout').exists()).toBeTruthy(); + }); + }); +}); diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/reactive_form/node_allocation.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/node_allocation.test.ts similarity index 78% rename from x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/reactive_form/node_allocation.test.ts rename to x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/node_allocation.test.ts index b02d190d10899..13e55a1f39e2c 100644 --- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/reactive_form/node_allocation.test.ts +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/node_allocation.test.ts @@ -8,6 +8,11 @@ import { act } from 'react-dom/test-utils'; import { setupEnvironment } from '../../helpers/setup_environment'; import { EditPolicyTestBed, setup } from '../edit_policy.helpers'; +import { + POLICY_WITH_MIGRATE_OFF, + POLICY_WITH_NODE_ATTR_AND_OFF_ALLOCATION, + POLICY_WITH_NODE_ROLE_ALLOCATION, +} from '../constants'; describe(' node allocation', () => { let testBed: EditPolicyTestBed; @@ -308,7 +313,7 @@ describe(' node allocation', () => { }); describe('on cloud', () => { - describe('with deprecated data role config', () => { + describe('using legacy data role config', () => { test('should hide data tier option on cloud', async () => { httpRequestsMockHelpers.setListNodes({ nodesByAttributes: { test: ['123'] }, @@ -319,7 +324,7 @@ describe(' node allocation', () => { await act(async () => { testBed = await setup({ appServicesContext: { cloud: { isCloudEnabled: true } } }); }); - const { actions, component, exists } = testBed; + const { actions, component, exists, find } = testBed; component.update(); await actions.warm.enable(true); @@ -330,30 +335,13 @@ describe(' node allocation', () => { expect(exists('defaultDataAllocationOption')).toBeFalsy(); expect(exists('customDataAllocationOption')).toBeTruthy(); expect(exists('noneDataAllocationOption')).toBeTruthy(); - }); - - test('should ask users to migrate to node roles when on cloud using legacy data role', async () => { - httpRequestsMockHelpers.setListNodes({ - nodesByAttributes: { test: ['123'] }, - // On cloud, if using legacy config there will not be any "data_*" roles set. - nodesByRoles: { data: ['test'] }, - isUsingDeprecatedDataRoleConfig: true, - }); - await act(async () => { - testBed = await setup({ appServicesContext: { cloud: { isCloudEnabled: true } } }); - }); - const { actions, component, exists } = testBed; - - component.update(); - await actions.warm.enable(true); - expect(component.find('.euiLoadingSpinner').exists()).toBeFalsy(); - - expect(exists('cloudDataTierCallout')).toBeTruthy(); + // Show the call-to-action for users to migrate their cluster to use node roles + expect(find('cloudDataTierCallout').exists()).toBeTruthy(); }); }); - describe('with node role config', () => { - test('shows data role, custom and "off" options on cloud with data roles', async () => { + describe('using node role config', () => { + test('shows recommended, custom and "off" options on cloud with data roles', async () => { httpRequestsMockHelpers.setListNodes({ nodesByAttributes: { test: ['123'] }, nodesByRoles: { data: ['test'], data_hot: ['test'], data_warm: ['test'] }, @@ -362,7 +350,7 @@ describe(' node allocation', () => { await act(async () => { testBed = await setup({ appServicesContext: { cloud: { isCloudEnabled: true } } }); }); - const { actions, component, exists } = testBed; + const { actions, component, exists, find } = testBed; component.update(); await actions.warm.enable(true); @@ -372,8 +360,10 @@ describe(' node allocation', () => { expect(exists('defaultDataAllocationOption')).toBeTruthy(); expect(exists('customDataAllocationOption')).toBeTruthy(); expect(exists('noneDataAllocationOption')).toBeTruthy(); - // We should not be showing the call-to-action for users to activate data tiers in cloud + // We should not be showing the call-to-action for users to activate data tier in cloud expect(exists('cloudDataTierCallout')).toBeFalsy(); + // Do not show the call-to-action for users to migrate their cluster to use node roles + expect(find('cloudDataTierCallout').exists()).toBeFalsy(); }); test('shows cloud notice when cold tier nodes do not exist', async () => { @@ -398,4 +388,102 @@ describe(' node allocation', () => { }); }); }); + + describe('data allocation', () => { + beforeEach(async () => { + httpRequestsMockHelpers.setLoadPolicies([POLICY_WITH_MIGRATE_OFF]); + httpRequestsMockHelpers.setListNodes({ + nodesByRoles: {}, + nodesByAttributes: { test: ['123'] }, + isUsingDeprecatedDataRoleConfig: false, + }); + httpRequestsMockHelpers.setLoadSnapshotPolicies([]); + + await act(async () => { + testBed = await setup(); + }); + + const { component } = testBed; + component.update(); + }); + + test('setting node_attr based allocation, but not selecting node attribute', async () => { + const { actions } = testBed; + await actions.warm.setDataAllocation('node_attrs'); + await actions.savePolicy(); + const latestRequest = server.requests[server.requests.length - 1]; + const warmPhase = JSON.parse(JSON.parse(latestRequest.requestBody).body).phases.warm; + + expect(warmPhase.actions.migrate).toEqual({ enabled: false }); + }); + + describe('node roles', () => { + beforeEach(async () => { + httpRequestsMockHelpers.setLoadPolicies([POLICY_WITH_NODE_ROLE_ALLOCATION]); + httpRequestsMockHelpers.setListNodes({ + isUsingDeprecatedDataRoleConfig: false, + nodesByAttributes: { test: ['123'] }, + nodesByRoles: { data: ['123'] }, + }); + + await act(async () => { + testBed = await setup(); + }); + + const { component } = testBed; + component.update(); + }); + + test('detecting use of the recommended allocation type', () => { + const { find } = testBed; + const selectedDataAllocation = find( + 'warm-dataTierAllocationControls.dataTierSelect' + ).text(); + expect(selectedDataAllocation).toBe('Use warm nodes (recommended)'); + }); + + test('setting replicas serialization', async () => { + const { actions } = testBed; + await actions.warm.setReplicas('123'); + await actions.savePolicy(); + const latestRequest = server.requests[server.requests.length - 1]; + const warmPhaseActions = JSON.parse(JSON.parse(latestRequest.requestBody).body).phases.warm + .actions; + expect(warmPhaseActions).toMatchInlineSnapshot(` + Object { + "allocate": Object { + "number_of_replicas": 123, + }, + } + `); + }); + }); + + describe('node attr and none', () => { + beforeEach(async () => { + httpRequestsMockHelpers.setLoadPolicies([POLICY_WITH_NODE_ATTR_AND_OFF_ALLOCATION]); + httpRequestsMockHelpers.setListNodes({ + isUsingDeprecatedDataRoleConfig: false, + nodesByAttributes: { test: ['123'] }, + nodesByRoles: { data: ['123'] }, + }); + + await act(async () => { + testBed = await setup(); + }); + + const { component } = testBed; + component.update(); + }); + + test('detecting use of the custom allocation type', () => { + const { find } = testBed; + expect(find('warm-dataTierAllocationControls.dataTierSelect').text()).toBe('Custom'); + }); + test('detecting use of the "off" allocation type', () => { + const { find } = testBed; + expect(find('cold-dataTierAllocationControls.dataTierSelect').text()).toContain('Off'); + }); + }); + }); }); diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/request_flyout.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/request_flyout.test.ts new file mode 100644 index 0000000000000..6584c19c85be3 --- /dev/null +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/request_flyout.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 { act } from 'react-dom/test-utils'; +import { EditPolicyTestBed, setup } from '../edit_policy.helpers'; +import { setupEnvironment } from '../../helpers/setup_environment'; +import { getDefaultHotPhasePolicy } from '../constants'; + +describe(' request flyout', () => { + let testBed: EditPolicyTestBed; + const { server, httpRequestsMockHelpers } = setupEnvironment(); + + beforeAll(() => { + jest.useFakeTimers(); + }); + + afterAll(() => { + jest.useRealTimers(); + server.restore(); + }); + + beforeEach(async () => { + httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]); + + await act(async () => { + testBed = await setup(); + }); + + const { component } = testBed; + component.update(); + }); + + test('renders a json in flyout for a default policy', async () => { + const { find, component } = testBed; + await act(async () => { + find('requestButton').simulate('click'); + }); + component.update(); + + const json = component.find(`code`).text(); + const expected = `PUT _ilm/policy/my_policy\n${JSON.stringify( + { + policy: { + phases: { + hot: { + min_age: '0ms', + actions: { + rollover: { + max_age: '30d', + max_size: '50gb', + }, + }, + }, + }, + }, + }, + null, + 2 + )}`; + expect(json).toBe(expected); + }); +}); diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/rollover.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/rollover.test.ts new file mode 100644 index 0000000000000..e2b67efbf588d --- /dev/null +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/rollover.test.ts @@ -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 { EditPolicyTestBed, setup } from '../edit_policy.helpers'; +import { setupEnvironment } from '../../helpers/setup_environment'; +import { getDefaultHotPhasePolicy } from '../constants'; +import { act } from 'react-dom/test-utils'; +import { licensingMock } from '../../../../../licensing/public/mocks'; + +describe(' timeline', () => { + let testBed: EditPolicyTestBed; + const { server, httpRequestsMockHelpers } = setupEnvironment(); + + afterAll(() => { + server.restore(); + }); + + beforeEach(async () => { + httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]); + httpRequestsMockHelpers.setLoadSnapshotPolicies([]); + httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['abc'] }); + httpRequestsMockHelpers.setListNodes({ + nodesByRoles: {}, + nodesByAttributes: { test: ['123'] }, + isUsingDeprecatedDataRoleConfig: false, + }); + + await act(async () => { + testBed = await setup({ + appServicesContext: { + license: licensingMock.createLicense({ license: { type: 'enterprise' } }), + }, + }); + }); + + const { component } = testBed; + component.update(); + }); + + test('shows forcemerge when rollover enabled', async () => { + const { actions } = testBed; + expect(actions.hot.forceMergeFieldExists()).toBeTruthy(); + }); + test('hides forcemerge when rollover is disabled', async () => { + const { actions } = testBed; + await actions.hot.toggleDefaultRollover(false); + await actions.hot.toggleRollover(false); + expect(actions.hot.forceMergeFieldExists()).toBeFalsy(); + }); + + test('shows shrink input when rollover enabled', async () => { + const { actions } = testBed; + expect(actions.hot.shrinkExists()).toBeTruthy(); + }); + test('hides shrink input when rollover is disabled', async () => { + const { actions } = testBed; + await actions.hot.toggleDefaultRollover(false); + await actions.hot.toggleRollover(false); + expect(actions.hot.shrinkExists()).toBeFalsy(); + }); + test('shows readonly input when rollover enabled', async () => { + const { actions } = testBed; + expect(actions.hot.readonlyExists()).toBeTruthy(); + }); + test('hides readonly input when rollover is disabled', async () => { + const { actions } = testBed; + await actions.hot.toggleDefaultRollover(false); + await actions.hot.toggleRollover(false); + expect(actions.hot.readonlyExists()).toBeFalsy(); + }); + test('hides and disables searchable snapshot field', async () => { + const { actions } = testBed; + await actions.hot.toggleDefaultRollover(false); + await actions.hot.toggleRollover(false); + await actions.cold.enable(true); + + expect(actions.hot.searchableSnapshotsExists()).toBeFalsy(); + }); + + test('shows rollover tip on minimum age', async () => { + const { actions } = testBed; + + await actions.warm.enable(true); + await actions.cold.enable(true); + await actions.delete.enablePhase(); + + expect(actions.warm.hasRolloverTipOnMinAge()).toBeTruthy(); + expect(actions.cold.hasRolloverTipOnMinAge()).toBeTruthy(); + expect(actions.delete.hasRolloverTipOnMinAge()).toBeTruthy(); + }); + test('hiding rollover tip on minimum age', async () => { + const { actions } = testBed; + await actions.hot.toggleDefaultRollover(false); + await actions.hot.toggleRollover(false); + + await actions.warm.enable(true); + await actions.cold.enable(true); + await actions.delete.enablePhase(); + + expect(actions.warm.hasRolloverTipOnMinAge()).toBeFalsy(); + expect(actions.cold.hasRolloverTipOnMinAge()).toBeFalsy(); + expect(actions.delete.hasRolloverTipOnMinAge()).toBeFalsy(); + }); +}); diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/searchable_snapshots.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/searchable_snapshots.test.ts new file mode 100644 index 0000000000000..ed678a6b217ae --- /dev/null +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/searchable_snapshots.test.ts @@ -0,0 +1,163 @@ +/* + * 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 { act } from 'react-dom/test-utils'; +import { licensingMock } from '../../../../../licensing/public/mocks'; +import { setupEnvironment } from '../../helpers/setup_environment'; +import { getDefaultHotPhasePolicy } from '../constants'; +import { EditPolicyTestBed, setup } from '../edit_policy.helpers'; + +describe(' searchable snapshots', () => { + let testBed: EditPolicyTestBed; + const { server, httpRequestsMockHelpers } = setupEnvironment(); + + afterAll(() => { + server.restore(); + }); + + beforeEach(async () => { + httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]); + httpRequestsMockHelpers.setLoadSnapshotPolicies([]); + httpRequestsMockHelpers.setListNodes({ + nodesByRoles: {}, + nodesByAttributes: { test: ['123'] }, + isUsingDeprecatedDataRoleConfig: false, + }); + + await act(async () => { + testBed = await setup(); + }); + + const { component } = testBed; + component.update(); + }); + + test('enabling searchable snapshot should hide force merge, freeze and shrink in subsequent phases', async () => { + const { actions } = testBed; + + await actions.warm.enable(true); + await actions.cold.enable(true); + + expect(actions.warm.forceMergeFieldExists()).toBeTruthy(); + expect(actions.warm.shrinkExists()).toBeTruthy(); + expect(actions.cold.searchableSnapshotsExists()).toBeTruthy(); + expect(actions.cold.freezeExists()).toBeTruthy(); + + await actions.hot.setSearchableSnapshot('my-repo'); + + expect(actions.warm.forceMergeFieldExists()).toBeFalsy(); + expect(actions.warm.shrinkExists()).toBeFalsy(); + // searchable snapshot in cold is still visible + expect(actions.cold.searchableSnapshotsExists()).toBeTruthy(); + expect(actions.cold.freezeExists()).toBeFalsy(); + }); + + test('disabling rollover toggle, but enabling default rollover', async () => { + const { actions } = testBed; + await actions.hot.toggleDefaultRollover(false); + await actions.hot.toggleRollover(false); + await actions.hot.toggleDefaultRollover(true); + + expect(actions.hot.forceMergeFieldExists()).toBeTruthy(); + expect(actions.hot.shrinkExists()).toBeTruthy(); + expect(actions.hot.searchableSnapshotsExists()).toBeTruthy(); + }); + + describe('on cloud', () => { + describe('new policy', () => { + beforeEach(async () => { + // simulate creating a new policy + httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('')]); + httpRequestsMockHelpers.setListNodes({ + isUsingDeprecatedDataRoleConfig: false, + nodesByAttributes: { test: ['123'] }, + nodesByRoles: { data: ['123'] }, + }); + httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['found-snapshots'] }); + + await act(async () => { + testBed = await setup({ appServicesContext: { cloud: { isCloudEnabled: true } } }); + }); + + const { component } = testBed; + component.update(); + }); + test('defaults searchable snapshot to true on cloud', async () => { + const { find, actions } = testBed; + await actions.cold.enable(true); + expect( + find('searchableSnapshotField-cold.searchableSnapshotToggle').props()['aria-checked'] + ).toBe(true); + }); + }); + describe('existing policy', () => { + beforeEach(async () => { + httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]); + httpRequestsMockHelpers.setListNodes({ + isUsingDeprecatedDataRoleConfig: false, + nodesByAttributes: { test: ['123'] }, + nodesByRoles: { data: ['123'] }, + }); + httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['found-snapshots'] }); + + await act(async () => { + testBed = await setup({ appServicesContext: { cloud: { isCloudEnabled: true } } }); + }); + + const { component } = testBed; + component.update(); + }); + test('correctly sets snapshot repository default to "found-snapshots"', async () => { + const { actions } = testBed; + await actions.cold.enable(true); + await actions.cold.toggleSearchableSnapshot(true); + await actions.savePolicy(); + const latestRequest = server.requests[server.requests.length - 1]; + const request = JSON.parse(JSON.parse(latestRequest.requestBody).body); + expect(request.phases.cold.actions.searchable_snapshot.snapshot_repository).toEqual( + 'found-snapshots' + ); + }); + }); + }); + describe('on non-enterprise license', () => { + beforeEach(async () => { + httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]); + httpRequestsMockHelpers.setListNodes({ + isUsingDeprecatedDataRoleConfig: false, + nodesByAttributes: { test: ['123'] }, + nodesByRoles: { data: ['123'] }, + }); + httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['my-repo'] }); + + await act(async () => { + testBed = await setup({ + appServicesContext: { + license: licensingMock.createLicense({ license: { type: 'basic' } }), + }, + }); + }); + + const { component } = testBed; + component.update(); + }); + test('disable setting searchable snapshots', async () => { + const { actions } = testBed; + + expect(actions.cold.searchableSnapshotsExists()).toBeFalsy(); + expect(actions.hot.searchableSnapshotsExists()).toBeFalsy(); + + await actions.cold.enable(true); + + // Still hidden in hot + expect(actions.hot.searchableSnapshotsExists()).toBeFalsy(); + + expect(actions.cold.searchableSnapshotsExists()).toBeTruthy(); + expect(actions.cold.searchableSnapshotDisabledDueToLicense()).toBeTruthy(); + }); + }); +}); diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/timeline.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/timeline.test.ts new file mode 100644 index 0000000000000..3618bad45e4f1 --- /dev/null +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/timeline.test.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { act } from 'react-dom/test-utils'; +import { setupEnvironment } from '../../helpers/setup_environment'; +import { getDefaultHotPhasePolicy } from '../constants'; +import { EditPolicyTestBed, setup } from '../edit_policy.helpers'; + +describe(' timeline', () => { + let testBed: EditPolicyTestBed; + const { server, httpRequestsMockHelpers } = setupEnvironment(); + + afterAll(() => { + server.restore(); + }); + + beforeEach(async () => { + httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]); + httpRequestsMockHelpers.setLoadSnapshotPolicies([]); + httpRequestsMockHelpers.setListNodes({ + nodesByRoles: {}, + nodesByAttributes: { test: ['123'] }, + isUsingDeprecatedDataRoleConfig: false, + }); + + await act(async () => { + testBed = await setup(); + }); + + const { component } = testBed; + component.update(); + }); + + test('showing all phases on the timeline', async () => { + const { actions } = testBed; + // This is how the default policy should look + expect(actions.timeline.hasHotPhase()).toBe(true); + expect(actions.timeline.hasWarmPhase()).toBe(false); + expect(actions.timeline.hasColdPhase()).toBe(false); + expect(actions.timeline.hasDeletePhase()).toBe(false); + + await actions.warm.enable(true); + expect(actions.timeline.hasHotPhase()).toBe(true); + expect(actions.timeline.hasWarmPhase()).toBe(true); + expect(actions.timeline.hasColdPhase()).toBe(false); + expect(actions.timeline.hasDeletePhase()).toBe(false); + + await actions.cold.enable(true); + expect(actions.timeline.hasHotPhase()).toBe(true); + expect(actions.timeline.hasWarmPhase()).toBe(true); + expect(actions.timeline.hasColdPhase()).toBe(true); + expect(actions.timeline.hasDeletePhase()).toBe(false); + + await actions.delete.enablePhase(); + expect(actions.timeline.hasHotPhase()).toBe(true); + expect(actions.timeline.hasWarmPhase()).toBe(true); + expect(actions.timeline.hasColdPhase()).toBe(true); + expect(actions.timeline.hasDeletePhase()).toBe(true); + }); +}); diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/warm_phase.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/warm_phase.test.ts new file mode 100644 index 0000000000000..2252f8d1f5fa8 --- /dev/null +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/features/warm_phase.test.ts @@ -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 { act } from 'react-dom/test-utils'; +import { setupEnvironment } from '../../helpers/setup_environment'; +import { EditPolicyTestBed, setup } from '../edit_policy.helpers'; +import { getDefaultHotPhasePolicy } from '../constants'; + +describe(' warm phase', () => { + let testBed: EditPolicyTestBed; + const { server, httpRequestsMockHelpers } = setupEnvironment(); + + beforeAll(() => { + jest.useFakeTimers(); + }); + + afterAll(() => { + jest.useRealTimers(); + server.restore(); + }); + + beforeEach(async () => { + httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]); + httpRequestsMockHelpers.setListNodes({ + nodesByRoles: { data: ['node1'] }, + nodesByAttributes: { 'attribute:true': ['node1'] }, + isUsingDeprecatedDataRoleConfig: true, + }); + httpRequestsMockHelpers.setNodesDetails('attribute:true', [ + { nodeId: 'testNodeId', stats: { name: 'testNodeName', host: 'testHost' } }, + ]); + httpRequestsMockHelpers.setLoadSnapshotPolicies([]); + + await act(async () => { + testBed = await setup(); + }); + + const { component } = testBed; + component.update(); + }); + + test('shows timing only when enabled', async () => { + const { actions } = testBed; + expect(actions.warm.hasMinAgeInput()).toBeFalsy(); + await actions.warm.enable(true); + expect(actions.warm.hasMinAgeInput()).toBeTruthy(); + }); +}); diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/form_validation/error_indicators.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/form_validation/error_indicators.test.ts new file mode 100644 index 0000000000000..e2d937cf9c8db --- /dev/null +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/form_validation/error_indicators.test.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { act } from 'react-dom/test-utils'; +import { setupEnvironment } from '../../helpers/setup_environment'; +import { getDefaultHotPhasePolicy } from '../constants'; +import { EditPolicyTestBed, setup } from '../edit_policy.helpers'; + +describe(' error indicators', () => { + let testBed: EditPolicyTestBed; + let runTimers: () => void; + const { server, httpRequestsMockHelpers } = setupEnvironment(); + + beforeAll(() => { + jest.useFakeTimers(); + }); + + afterAll(() => { + jest.useRealTimers(); + server.restore(); + }); + + beforeEach(async () => { + httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]); + httpRequestsMockHelpers.setListNodes({ + nodesByRoles: {}, + nodesByAttributes: { test: ['123'] }, + isUsingDeprecatedDataRoleConfig: false, + }); + httpRequestsMockHelpers.setLoadSnapshotPolicies([]); + + await act(async () => { + testBed = await setup(); + }); + + const { component } = testBed; + component.update(); + + ({ runTimers } = testBed); + }); + test('shows phase error indicators correctly', async () => { + // This test simulates a user configuring a policy phase by phase. The flow is the following: + // 0. Start with policy with no validation issues present + // 1. Configure hot, introducing a validation error + // 2. Configure warm, introducing a validation error + // 3. Configure cold, introducing a validation error + // 4. Fix validation error in hot + // 5. Fix validation error in warm + // 6. Fix validation error in cold + // We assert against each of these progressive states. + + const { actions } = testBed; + + // 0. No validation issues + expect(actions.hasGlobalErrorCallout()).toBe(false); + expect(actions.hot.hasErrorIndicator()).toBe(false); + expect(actions.warm.hasErrorIndicator()).toBe(false); + expect(actions.cold.hasErrorIndicator()).toBe(false); + + // 1. Hot phase validation issue + await actions.hot.toggleForceMerge(true); + await actions.hot.setForcemergeSegmentsCount('-22'); + runTimers(); + expect(actions.hasGlobalErrorCallout()).toBe(true); + expect(actions.hot.hasErrorIndicator()).toBe(true); + expect(actions.warm.hasErrorIndicator()).toBe(false); + expect(actions.cold.hasErrorIndicator()).toBe(false); + + // 2. Warm phase validation issue + await actions.warm.enable(true); + await actions.warm.toggleForceMerge(true); + await actions.warm.setForcemergeSegmentsCount('-22'); + runTimers(); + expect(actions.hasGlobalErrorCallout()).toBe(true); + expect(actions.hot.hasErrorIndicator()).toBe(true); + expect(actions.warm.hasErrorIndicator()).toBe(true); + expect(actions.cold.hasErrorIndicator()).toBe(false); + + // 3. Cold phase validation issue + await actions.cold.enable(true); + await actions.cold.setReplicas('-33'); + runTimers(); + expect(actions.hasGlobalErrorCallout()).toBe(true); + expect(actions.hot.hasErrorIndicator()).toBe(true); + expect(actions.warm.hasErrorIndicator()).toBe(true); + expect(actions.cold.hasErrorIndicator()).toBe(true); + + // 4. Fix validation issue in hot + await actions.hot.setForcemergeSegmentsCount('1'); + runTimers(); + expect(actions.hasGlobalErrorCallout()).toBe(true); + expect(actions.hot.hasErrorIndicator()).toBe(false); + expect(actions.warm.hasErrorIndicator()).toBe(true); + expect(actions.cold.hasErrorIndicator()).toBe(true); + + // 5. Fix validation issue in warm + await actions.warm.setForcemergeSegmentsCount('1'); + runTimers(); + expect(actions.hasGlobalErrorCallout()).toBe(true); + expect(actions.hot.hasErrorIndicator()).toBe(false); + expect(actions.warm.hasErrorIndicator()).toBe(false); + expect(actions.cold.hasErrorIndicator()).toBe(true); + + // 6. Fix validation issue in cold + await actions.cold.setReplicas('1'); + runTimers(); + expect(actions.hasGlobalErrorCallout()).toBe(false); + expect(actions.hot.hasErrorIndicator()).toBe(false); + expect(actions.warm.hasErrorIndicator()).toBe(false); + expect(actions.cold.hasErrorIndicator()).toBe(false); + }); + + test('global error callout should show if there are any form errors', async () => { + const { actions } = testBed; + + expect(actions.hasGlobalErrorCallout()).toBe(false); + expect(actions.hot.hasErrorIndicator()).toBe(false); + expect(actions.warm.hasErrorIndicator()).toBe(false); + expect(actions.cold.hasErrorIndicator()).toBe(false); + + await actions.saveAsNewPolicy(true); + await actions.setPolicyName(''); + runTimers(); + + expect(actions.hasGlobalErrorCallout()).toBe(true); + expect(actions.hot.hasErrorIndicator()).toBe(false); + expect(actions.warm.hasErrorIndicator()).toBe(false); + expect(actions.cold.hasErrorIndicator()).toBe(false); + }); + + test('clears all error indicators if last erroring field is unmounted', async () => { + const { actions } = testBed; + + await actions.cold.enable(true); + // introduce validation error + await actions.cold.setSearchableSnapshot(''); + runTimers(); + + await actions.savePolicy(); + runTimers(); + + expect(actions.hasGlobalErrorCallout()).toBe(true); + expect(actions.hot.hasErrorIndicator()).toBe(false); + expect(actions.warm.hasErrorIndicator()).toBe(false); + expect(actions.cold.hasErrorIndicator()).toBe(true); + + // unmount the field + await actions.cold.toggleSearchableSnapshot(false); + + expect(actions.hasGlobalErrorCallout()).toBe(false); + expect(actions.hot.hasErrorIndicator()).toBe(false); + expect(actions.warm.hasErrorIndicator()).toBe(false); + expect(actions.cold.hasErrorIndicator()).toBe(false); + }); +}); diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/reactive_form/reactive_form.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/reactive_form/reactive_form.test.ts deleted file mode 100644 index 9c23780f1d021..0000000000000 --- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/reactive_form/reactive_form.test.ts +++ /dev/null @@ -1,143 +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 { act } from 'react-dom/test-utils'; -import { setupEnvironment } from '../../helpers/setup_environment'; -import { EditPolicyTestBed, setup } from '../edit_policy.helpers'; -import { DEFAULT_POLICY } from '../constants'; - -describe(' reactive form', () => { - let testBed: EditPolicyTestBed; - const { server, httpRequestsMockHelpers } = setupEnvironment(); - - beforeAll(() => { - jest.useFakeTimers(); - }); - - afterAll(() => { - jest.useRealTimers(); - server.restore(); - }); - - beforeEach(async () => { - httpRequestsMockHelpers.setLoadPolicies([DEFAULT_POLICY]); - httpRequestsMockHelpers.setListNodes({ - nodesByRoles: { data: ['node1'] }, - nodesByAttributes: { 'attribute:true': ['node1'] }, - isUsingDeprecatedDataRoleConfig: true, - }); - httpRequestsMockHelpers.setNodesDetails('attribute:true', [ - { nodeId: 'testNodeId', stats: { name: 'testNodeName', host: 'testHost' } }, - ]); - httpRequestsMockHelpers.setLoadSnapshotPolicies([]); - - await act(async () => { - testBed = await setup(); - }); - - const { component } = testBed; - component.update(); - }); - - describe('rollover', () => { - test('shows forcemerge when rollover enabled', async () => { - const { actions } = testBed; - expect(actions.hot.forceMergeFieldExists()).toBeTruthy(); - }); - test('hides forcemerge when rollover is disabled', async () => { - const { actions } = testBed; - await actions.hot.toggleDefaultRollover(false); - await actions.hot.toggleRollover(false); - expect(actions.hot.forceMergeFieldExists()).toBeFalsy(); - }); - - test('shows shrink input when rollover enabled', async () => { - const { actions } = testBed; - expect(actions.hot.shrinkExists()).toBeTruthy(); - }); - test('hides shrink input when rollover is disabled', async () => { - const { actions } = testBed; - await actions.hot.toggleDefaultRollover(false); - await actions.hot.toggleRollover(false); - expect(actions.hot.shrinkExists()).toBeFalsy(); - }); - test('shows readonly input when rollover enabled', async () => { - const { actions } = testBed; - expect(actions.hot.readonlyExists()).toBeTruthy(); - }); - test('hides readonly input when rollover is disabled', async () => { - const { actions } = testBed; - await actions.hot.toggleDefaultRollover(false); - await actions.hot.toggleRollover(false); - expect(actions.hot.readonlyExists()).toBeFalsy(); - }); - }); - - describe('timing', () => { - test('warm phase shows timing only when enabled', async () => { - const { actions } = testBed; - expect(actions.warm.hasMinAgeInput()).toBeFalsy(); - await actions.warm.enable(true); - expect(actions.warm.hasMinAgeInput()).toBeTruthy(); - }); - - test('cold phase shows timing only when enabled', async () => { - const { actions } = testBed; - expect(actions.cold.hasMinAgeInput()).toBeFalsy(); - await actions.cold.enable(true); - expect(actions.cold.hasMinAgeInput()).toBeTruthy(); - }); - - test('delete phase shows timing after it was enabled', async () => { - const { actions } = testBed; - expect(actions.delete.hasMinAgeInput()).toBeFalsy(); - await actions.delete.enablePhase(); - expect(actions.delete.hasMinAgeInput()).toBeTruthy(); - }); - }); - - describe('delete phase', () => { - test('is hidden when disabled', async () => { - const { actions } = testBed; - expect(actions.delete.isShown()).toBeFalsy(); - await actions.delete.enablePhase(); - expect(actions.delete.isShown()).toBeTruthy(); - }); - }); - - describe('json in flyout', () => { - test('renders a json in flyout for a default policy', async () => { - const { find, component } = testBed; - await act(async () => { - find('requestButton').simulate('click'); - }); - component.update(); - - const json = component.find(`code`).text(); - const expected = `PUT _ilm/policy/my_policy\n${JSON.stringify( - { - policy: { - phases: { - hot: { - min_age: '0ms', - actions: { - rollover: { - max_age: '30d', - max_size: '50gb', - }, - }, - }, - }, - }, - }, - null, - 2 - )}`; - expect(json).toBe(expected); - }); - }); -}); diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/serialization/policy_serialization.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/serialization/policy_serialization.test.ts new file mode 100644 index 0000000000000..61ceab1990c72 --- /dev/null +++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/serialization/policy_serialization.test.ts @@ -0,0 +1,426 @@ +/* + * 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 { act } from 'react-dom/test-utils'; +import { setupEnvironment } from '../../helpers/setup_environment'; +import { + getDefaultHotPhasePolicy, + POLICY_WITH_INCLUDE_EXCLUDE, + POLICY_WITH_KNOWN_AND_UNKNOWN_FIELDS, +} from '../constants'; +import { EditPolicyTestBed, setup } from '../edit_policy.helpers'; + +describe(' serialization', () => { + let testBed: EditPolicyTestBed; + const { server, httpRequestsMockHelpers } = setupEnvironment(); + + afterAll(() => { + server.restore(); + }); + + beforeEach(async () => { + httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]); + httpRequestsMockHelpers.setLoadSnapshotPolicies([]); + httpRequestsMockHelpers.setListNodes({ + nodesByRoles: {}, + nodesByAttributes: { test: ['123'] }, + isUsingDeprecatedDataRoleConfig: false, + }); + + await act(async () => { + testBed = await setup(); + }); + + const { component } = testBed; + component.update(); + }); + + describe('top level form', () => { + /** + * We assume that policies that populate this form are loaded directly from ES and so + * are valid according to ES. There may be settings in the policy created through the ILM + * API that the UI does not cater for, like the unfollow action. We do not want to overwrite + * the configuration for these actions in the UI. + */ + it('preserves policy settings it did not configure', async () => { + httpRequestsMockHelpers.setLoadPolicies([POLICY_WITH_KNOWN_AND_UNKNOWN_FIELDS]); + await act(async () => { + testBed = await setup(); + }); + + const { component, actions } = testBed; + component.update(); + + // Set max docs to test whether we keep the unknown fields in that object after serializing + await actions.hot.setMaxDocs('1000'); + // Remove the delete phase to ensure that we also correctly remove data + await actions.delete.disablePhase(); + await actions.savePolicy(); + + const latestRequest = server.requests[server.requests.length - 1]; + const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body); + + expect(entirePolicy).toEqual({ + foo: 'bar', // Made up value + name: 'my_policy', + phases: { + hot: { + actions: { + rollover: { + max_docs: 1000, + max_size: '50gb', + unknown_setting: 123, // Made up setting that should stay preserved + }, + }, + min_age: '0ms', + }, + warm: { + actions: { + my_unfollow_action: {}, // Made up action + set_priority: { + priority: 22, + unknown_setting: true, + }, + }, + min_age: '0d', + }, + }, + }); + }); + }); + + describe('hot phase', () => { + test('setting all values', async () => { + const { actions } = testBed; + + await actions.hot.toggleDefaultRollover(false); + await actions.hot.setMaxSize('123', 'mb'); + await actions.hot.setMaxDocs('123'); + await actions.hot.setMaxAge('123', 'h'); + await actions.hot.toggleForceMerge(true); + await actions.hot.setForcemergeSegmentsCount('123'); + await actions.hot.setBestCompression(true); + await actions.hot.toggleShrink(true); + await actions.hot.setShrink('2'); + await actions.hot.toggleReadonly(true); + await actions.hot.toggleIndexPriority(true); + await actions.hot.setIndexPriority('123'); + + await actions.savePolicy(); + const latestRequest = server.requests[server.requests.length - 1]; + const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body); + expect(entirePolicy).toMatchInlineSnapshot(` + Object { + "name": "my_policy", + "phases": Object { + "hot": Object { + "actions": Object { + "forcemerge": Object { + "index_codec": "best_compression", + "max_num_segments": 123, + }, + "readonly": Object {}, + "rollover": Object { + "max_age": "123h", + "max_docs": 123, + "max_size": "123mb", + }, + "set_priority": Object { + "priority": 123, + }, + "shrink": Object { + "number_of_shards": 2, + }, + }, + "min_age": "0ms", + }, + }, + } + `); + }); + + test('setting searchable snapshot', async () => { + const { actions } = testBed; + + await actions.hot.setSearchableSnapshot('my-repo'); + + await actions.savePolicy(); + const latestRequest = server.requests[server.requests.length - 1]; + const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body); + expect(entirePolicy.phases.hot.actions.searchable_snapshot.snapshot_repository).toBe( + 'my-repo' + ); + }); + + test('disabling rollover', async () => { + const { actions } = testBed; + await actions.hot.toggleDefaultRollover(false); + await actions.hot.toggleRollover(false); + await actions.savePolicy(); + const latestRequest = server.requests[server.requests.length - 1]; + const policy = JSON.parse(JSON.parse(latestRequest.requestBody).body); + const hotActions = policy.phases.hot.actions; + const rolloverAction = hotActions.rollover; + expect(rolloverAction).toBe(undefined); + expect(hotActions).toMatchInlineSnapshot(`Object {}`); + }); + }); + + describe('warm phase', () => { + beforeEach(async () => { + httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]); + httpRequestsMockHelpers.setListNodes({ + nodesByRoles: {}, + nodesByAttributes: { test: ['123'] }, + isUsingDeprecatedDataRoleConfig: false, + }); + httpRequestsMockHelpers.setLoadSnapshotPolicies([]); + + await act(async () => { + testBed = await setup(); + }); + + const { component } = testBed; + component.update(); + }); + + test('default values', async () => { + const { actions } = testBed; + await actions.warm.enable(true); + await actions.savePolicy(); + const latestRequest = server.requests[server.requests.length - 1]; + const warmPhase = JSON.parse(JSON.parse(latestRequest.requestBody).body).phases.warm; + expect(warmPhase).toMatchInlineSnapshot(` + Object { + "actions": Object { + "set_priority": Object { + "priority": 50, + }, + }, + "min_age": "0d", + } + `); + }); + + test('setting all values', async () => { + const { actions } = testBed; + await actions.warm.enable(true); + await actions.warm.setDataAllocation('node_attrs'); + await actions.warm.setSelectedNodeAttribute('test:123'); + await actions.warm.setReplicas('123'); + await actions.warm.toggleShrink(true); + await actions.warm.setShrink('123'); + await actions.warm.toggleForceMerge(true); + await actions.warm.setForcemergeSegmentsCount('123'); + await actions.warm.setBestCompression(true); + await actions.warm.toggleReadonly(true); + await actions.warm.setIndexPriority('123'); + await actions.savePolicy(); + const latestRequest = server.requests[server.requests.length - 1]; + const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body); + // Check shape of entire policy + expect(entirePolicy).toMatchInlineSnapshot(` + Object { + "name": "my_policy", + "phases": Object { + "hot": Object { + "actions": Object { + "rollover": Object { + "max_age": "30d", + "max_size": "50gb", + }, + }, + "min_age": "0ms", + }, + "warm": Object { + "actions": Object { + "allocate": Object { + "number_of_replicas": 123, + "require": Object { + "test": "123", + }, + }, + "forcemerge": Object { + "index_codec": "best_compression", + "max_num_segments": 123, + }, + "readonly": Object {}, + "set_priority": Object { + "priority": 123, + }, + "shrink": Object { + "number_of_shards": 123, + }, + }, + "min_age": "0d", + }, + }, + } + `); + }); + + describe('policy with include and exclude', () => { + beforeEach(async () => { + httpRequestsMockHelpers.setLoadPolicies([POLICY_WITH_INCLUDE_EXCLUDE]); + httpRequestsMockHelpers.setListNodes({ + nodesByRoles: {}, + nodesByAttributes: { test: ['123'] }, + isUsingDeprecatedDataRoleConfig: false, + }); + httpRequestsMockHelpers.setLoadSnapshotPolicies([]); + + await act(async () => { + testBed = await setup(); + }); + + const { component } = testBed; + component.update(); + }); + + test('preserves include, exclude allocation settings', async () => { + const { actions } = testBed; + await actions.warm.setDataAllocation('node_attrs'); + await actions.warm.setSelectedNodeAttribute('test:123'); + await actions.savePolicy(); + const latestRequest = server.requests[server.requests.length - 1]; + const warmPhaseAllocate = JSON.parse(JSON.parse(latestRequest.requestBody).body).phases.warm + .actions.allocate; + expect(warmPhaseAllocate).toMatchInlineSnapshot(` + Object { + "exclude": Object { + "def": "456", + }, + "include": Object { + "abc": "123", + }, + "require": Object { + "test": "123", + }, + } + `); + }); + }); + }); + + describe('cold phase', () => { + beforeEach(async () => { + httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]); + httpRequestsMockHelpers.setListNodes({ + nodesByRoles: {}, + nodesByAttributes: { test: ['123'] }, + isUsingDeprecatedDataRoleConfig: false, + }); + httpRequestsMockHelpers.setLoadSnapshotPolicies([]); + + await act(async () => { + testBed = await setup(); + }); + + const { component } = testBed; + component.update(); + }); + + test('default values', async () => { + const { actions } = testBed; + + await actions.cold.enable(true); + await actions.savePolicy(); + const latestRequest = server.requests[server.requests.length - 1]; + const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body); + expect(entirePolicy.phases.cold).toMatchInlineSnapshot(` + Object { + "actions": Object { + "set_priority": Object { + "priority": 0, + }, + }, + "min_age": "0d", + } + `); + }); + + test('setting all values, excluding searchable snapshot', async () => { + const { actions } = testBed; + + await actions.cold.enable(true); + await actions.cold.setMinAgeValue('123'); + await actions.cold.setMinAgeUnits('s'); + await actions.cold.setDataAllocation('node_attrs'); + await actions.cold.setSelectedNodeAttribute('test:123'); + await actions.cold.setReplicas('123'); + await actions.cold.setFreeze(true); + await actions.cold.setIndexPriority('123'); + + await actions.savePolicy(); + const latestRequest = server.requests[server.requests.length - 1]; + const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body); + + expect(entirePolicy).toMatchInlineSnapshot(` + Object { + "name": "my_policy", + "phases": Object { + "cold": Object { + "actions": Object { + "allocate": Object { + "number_of_replicas": 123, + "require": Object { + "test": "123", + }, + }, + "freeze": Object {}, + "set_priority": Object { + "priority": 123, + }, + }, + "min_age": "123s", + }, + "hot": Object { + "actions": Object { + "rollover": Object { + "max_age": "30d", + "max_size": "50gb", + }, + }, + "min_age": "0ms", + }, + }, + } + `); + }); + + // Setting searchable snapshot field disables setting replicas so we test this separately + test('setting searchable snapshot', async () => { + const { actions } = testBed; + await actions.cold.enable(true); + await actions.cold.setSearchableSnapshot('my-repo'); + await actions.savePolicy(); + const latestRequest2 = server.requests[server.requests.length - 1]; + const entirePolicy2 = JSON.parse(JSON.parse(latestRequest2.requestBody).body); + expect(entirePolicy2.phases.cold.actions.searchable_snapshot.snapshot_repository).toEqual( + 'my-repo' + ); + }); + }); + + test('delete phase', async () => { + const { actions } = testBed; + await actions.delete.enablePhase(); + await actions.setWaitForSnapshotPolicy('test'); + await actions.savePolicy(); + const latestRequest = server.requests[server.requests.length - 1]; + const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body); + expect(entirePolicy.phases.delete).toEqual({ + min_age: '365d', + actions: { + delete: {}, + wait_for_snapshot: { + policy: 'test', + }, + }, + }); + }); +}); diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/searchable_snapshot_field/searchable_snapshot_field.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/searchable_snapshot_field/searchable_snapshot_field.tsx index 1a78149521e63..3fc7064575555 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/searchable_snapshot_field/searchable_snapshot_field.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/searchable_snapshot_field/searchable_snapshot_field.tsx @@ -61,9 +61,6 @@ export const SearchableSnapshotField: FunctionComponent = ({ phase }) => const isColdPhase = phase === 'cold'; const isDisabledDueToLicense = !license.canUseSearchableSnapshot(); - const isDisabledInColdDueToHotPhase = isColdPhase && isUsingSearchableSnapshotInHotPhase; - - const isDisabled = isDisabledDueToLicense || isDisabledInColdDueToHotPhase; const [isFieldToggleChecked, setIsFieldToggleChecked] = useState(() => Boolean( @@ -74,10 +71,10 @@ export const SearchableSnapshotField: FunctionComponent = ({ phase }) => ); useEffect(() => { - if (isDisabled) { + if (isDisabledDueToLicense) { setIsFieldToggleChecked(false); } - }, [isDisabled]); + }, [isDisabledDueToLicense]); const renderField = () => ( @@ -254,7 +251,7 @@ export const SearchableSnapshotField: FunctionComponent = ({ phase }) => 'xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotCalloutBody', { defaultMessage: - 'Force merge, shrink, freeze and cold phase searchable snapshots are not allowed when searchable snapshots are enabled in the hot phase.', + 'Force merge, shrink and freeze actions are not allowed when searchable snapshots are enabled in this phase.', } )} data-test-subj="searchableSnapshotFieldsDisabledCallout" @@ -278,20 +275,6 @@ export const SearchableSnapshotField: FunctionComponent = ({ phase }) => )} ); - } else if (isDisabledInColdDueToHotPhase) { - infoCallout = ( - - ); } return infoCallout ? ( @@ -308,7 +291,7 @@ export const SearchableSnapshotField: FunctionComponent = ({ phase }) => data-test-subj={`searchableSnapshotField-${phase}`} switchProps={{ checked: isFieldToggleChecked, - disabled: isDisabled, + disabled: isDisabledDueToLicense, onChange: setIsFieldToggleChecked, 'data-test-subj': 'searchableSnapshotToggle', label: i18n.translate( @@ -339,7 +322,7 @@ export const SearchableSnapshotField: FunctionComponent = ({ phase }) => fieldNotices={renderInfoCallout()} fullWidth > - {isDisabled ?
: renderField} + {isDisabledDueToLicense ?
: renderField} ); }; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/services/api_errors.ts b/x-pack/plugins/index_lifecycle_management/public/application/services/api_errors.ts index 54ef91457b1f9..fc37b62e30eb2 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/services/api_errors.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/services/api_errors.ts @@ -11,7 +11,10 @@ import { fatalErrors, toasts } from './notification'; function createToastConfig(error: IHttpFetchError, errorTitle: string) { if (error && error.body) { // Error body shape is defined by the API. - const { error: errorString, statusCode, message } = error.body; + const { error: errorString, statusCode, message: errorMessage, attributes } = error.body; + const message = attributes?.causes?.length + ? attributes.causes[attributes.causes.length - 1] + : errorMessage; return { title: errorTitle, diff --git a/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx b/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx index fc69c914deb68..b7ff23cdb6e35 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx @@ -10,7 +10,7 @@ import { render } from 'react-dom'; import { Ast } from '@kbn/interpreter/common'; import { I18nProvider } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import type { +import { SuggestionRequest, Visualization, VisualizationSuggestion, @@ -37,6 +37,10 @@ export interface DatatableVisualizationState { sorting?: SortingState; } +const visualizationLabel = i18n.translate('xpack.lens.datatable.label', { + defaultMessage: 'Table', +}); + export const datatableVisualization: Visualization = { id: 'lnsDatatable', @@ -44,8 +48,9 @@ export const datatableVisualization: Visualization { id: 'lnsDatatable', icon: LensIconChartDatatable, - label: i18n.translate('xpack.lens.datatable.label', { - defaultMessage: 'Data table', + label: visualizationLabel, + groupLabel: i18n.translate('xpack.lens.datatable.groupLabel', { + defaultMessage: 'Tabular and single value', }), }, ], @@ -68,9 +73,7 @@ export const datatableVisualization: Visualization getDescription() { return { icon: LensIconChartDatatable, - label: i18n.translate('xpack.lens.datatable.label', { - defaultMessage: 'Data table', - }), + label: visualizationLabel, }; }, diff --git a/x-pack/plugins/lens/public/drag_drop/drag_drop.test.tsx b/x-pack/plugins/lens/public/drag_drop/drag_drop.test.tsx index 2fc5efaa28b83..dd1e351b824fe 100644 --- a/x-pack/plugins/lens/public/drag_drop/drag_drop.test.tsx +++ b/x-pack/plugins/lens/public/drag_drop/drag_drop.test.tsx @@ -76,6 +76,20 @@ describe('DragDrop', () => { expect(preventDefault).not.toBeCalled(); }); + test('removes selection on mouse down before dragging', async () => { + const removeAllRanges = jest.fn(); + global.getSelection = jest.fn(() => (({ removeAllRanges } as unknown) as Selection)); + const component = mount( + + + + ); + + component.find('[data-test-subj="lnsDragDrop"]').simulate('mousedown'); + expect(global.getSelection).toBeCalled(); + expect(removeAllRanges).toBeCalled(); + }); + test('dragstart sets dragging in the context and calls it with proper params', async () => { const setDragging = jest.fn(); diff --git a/x-pack/plugins/lens/public/drag_drop/drag_drop.tsx b/x-pack/plugins/lens/public/drag_drop/drag_drop.tsx index 76e44c29eaed5..a376c962a7a1c 100644 --- a/x-pack/plugins/lens/public/drag_drop/drag_drop.tsx +++ b/x-pack/plugins/lens/public/drag_drop/drag_drop.tsx @@ -202,6 +202,13 @@ export const DragDrop = (props: BaseProps) => { return ; }; +const removeSelectionBeforeDragging = () => { + const selection = window.getSelection(); + if (selection) { + selection.removeAllRanges(); + } +}; + const DragInner = memo(function DragInner({ dataTestSubj, className, @@ -366,6 +373,7 @@ const DragInner = memo(function DragInner({ draggable: true, onDragEnd: dragEnd, onDragStart: dragStart, + onMouseDown: removeSelectionBeforeDragging, })}
); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx index 66f944e9f9998..3d499b7b7b45a 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx @@ -72,6 +72,7 @@ describe('ConfigPanel', () => { icon: 'empty', id: 'testVis', label: 'TEST1', + groupLabel: 'testVisGroup', }, ], }; @@ -85,6 +86,7 @@ describe('ConfigPanel', () => { icon: 'empty', id: 'testVis2', label: 'TEST2', + groupLabel: 'testVis2Group', }, ], }; diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.test.tsx index 52726afcffe8d..5c27958aa1786 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.test.tsx @@ -82,6 +82,7 @@ describe('LayerPanel', () => { icon: 'empty', id: 'testVis', label: 'TEST1', + groupLabel: 'testVisGroup', }, ], }; @@ -94,6 +95,7 @@ describe('LayerPanel', () => { icon: 'empty', id: 'testVis2', label: 'TEST2', + groupLabel: 'testVis2Group', }, ], }; diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx index 108e4aa84418f..31c4d357685c2 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx @@ -7,6 +7,19 @@ import React, { ReactElement } from 'react'; import { ReactWrapper } from 'enzyme'; + +// Tests are executed in a jsdom environment who does not have sizing methods, +// thus the AutoSizer will always compute a 0x0 size space +// Mock the AutoSizer inside EuiSelectable (Chart Switch) and return some dimensions > 0 +jest.mock('react-virtualized-auto-sizer', () => { + return function (props: { + children: (dimensions: { width: number; height: number }) => React.ReactNode; + }) { + const { children, ...otherProps } = props; + return
{children({ width: 100, height: 100 })}
; + }; +}); + import { EuiPanel, EuiToolTip } from '@elastic/eui'; import { mountWithIntl as mount } from '@kbn/test/jest'; import { EditorFrame } from './editor_frame'; @@ -83,6 +96,7 @@ describe('editor_frame', () => { icon: 'empty', id: 'testVis', label: 'TEST1', + groupLabel: 'testVisGroup', }, ], }; @@ -94,6 +108,7 @@ describe('editor_frame', () => { icon: 'empty', id: 'testVis2', label: 'TEST2', + groupLabel: 'testVis2Group', }, ], }; @@ -1372,6 +1387,7 @@ describe('editor_frame', () => { icon: 'empty', id: 'testVis3', label: 'TEST3', + groupLabel: 'testVis3Group', }, ], getSuggestions: () => [ diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.scss b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.scss index 0a4f7b0debf22..9f4b60b6d3c67 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.scss +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.scss @@ -18,5 +18,5 @@ img.lnsChartSwitch__chartIcon { // stylelint-disable-line selector-no-qualifying } .lnsChartSwitch__search { - width: 4 * $euiSizeXXL; + width: 7 * $euiSizeXXL; } \ No newline at end of file diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.test.tsx index d2c140d385f87..46e287297828d 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.test.tsx @@ -12,7 +12,19 @@ import { createMockFramePublicAPI, createMockDatasource, } from '../../mocks'; -import { EuiKeyPadMenuItem } from '@elastic/eui'; + +// Tests are executed in a jsdom environment who does not have sizing methods, +// thus the AutoSizer will always compute a 0x0 size space +// Mock the AutoSizer inside EuiSelectable (Chart Switch) and return some dimensions > 0 +jest.mock('react-virtualized-auto-sizer', () => { + return function (props: { + children: (dimensions: { width: number; height: number }) => React.ReactNode; + }) { + const { children } = props; + return
{children({ width: 100, height: 100 })}
; + }; +}); + import { mountWithIntl as mount } from '@kbn/test/jest'; import { Visualization, FramePublicAPI, DatasourcePublicAPI } from '../../../types'; import { Action } from '../state_management'; @@ -30,6 +42,7 @@ describe('chart_switch', () => { icon: 'empty', id, label: `Label ${id}`, + groupLabel: `${id}Group`, }, ], initialize: jest.fn((_frame, state?: unknown) => { @@ -70,16 +83,19 @@ describe('chart_switch', () => { icon: 'empty', id: 'subvisC1', label: 'C1', + groupLabel: 'visCGroup', }, { icon: 'empty', id: 'subvisC2', label: 'C2', + groupLabel: 'visCGroup', }, { icon: 'empty', id: 'subvisC3', label: 'C3', + groupLabel: 'visCGroup', }, ], getVisualizationTypeId: jest.fn((state) => state.type), @@ -166,10 +182,7 @@ describe('chart_switch', () => { function getMenuItem(subType: string, component: ReactWrapper) { showFlyout(component); - return component - .find(EuiKeyPadMenuItem) - .find(`[data-test-subj="lnsChartSwitchPopover_${subType}"]`) - .first(); + return component.find(`[data-test-subj="lnsChartSwitchPopover_${subType}"]`).first(); } it('should use suggested state if there is a suggestion from the target visualization', () => { @@ -281,7 +294,12 @@ describe('chart_switch', () => { /> ); - expect(getMenuItem('visB', component).prop('betaBadgeIconType')).toEqual('alert'); + expect( + getMenuItem('visB', component) + .find('[data-test-subj="lnsChartSwitchPopoverAlert_visB"]') + .first() + .props().type + ).toEqual('alert'); }); it('should indicate data loss if not all layers will be used', () => { @@ -301,7 +319,12 @@ describe('chart_switch', () => { /> ); - expect(getMenuItem('visB', component).prop('betaBadgeIconType')).toEqual('alert'); + expect( + getMenuItem('visB', component) + .find('[data-test-subj="lnsChartSwitchPopoverAlert_visB"]') + .first() + .props().type + ).toEqual('alert'); }); it('should support multi-layer suggestions without data loss', () => { @@ -344,7 +367,9 @@ describe('chart_switch', () => { /> ); - expect(getMenuItem('visB', component).prop('betaBadgeIconType')).toBeUndefined(); + expect( + getMenuItem('visB', component).find('[data-test-subj="lnsChartSwitchPopoverAlert_visB"]') + ).toHaveLength(0); }); it('should indicate data loss if no data will be used', () => { @@ -365,7 +390,12 @@ describe('chart_switch', () => { /> ); - expect(getMenuItem('visB', component).prop('betaBadgeIconType')).toEqual('alert'); + expect( + getMenuItem('visB', component) + .find('[data-test-subj="lnsChartSwitchPopoverAlert_visB"]') + .first() + .props().type + ).toEqual('alert'); }); it('should not indicate data loss if there is no data', () => { @@ -387,7 +417,9 @@ describe('chart_switch', () => { /> ); - expect(getMenuItem('visB', component).prop('betaBadgeIconType')).toBeUndefined(); + expect( + getMenuItem('visB', component).find('[data-test-subj="lnsChartSwitchPopoverAlert_visB"]') + ).toHaveLength(0); }); it('should not show a warning when the subvisualization is the same', () => { @@ -411,7 +443,11 @@ describe('chart_switch', () => { /> ); - expect(getMenuItem('subvisC2', component).prop('betaBadgeIconType')).not.toBeDefined(); + expect( + getMenuItem('subvisC2', component).find( + '[data-test-subj="lnsChartSwitchPopoverAlert_subvisC2"]' + ) + ).toHaveLength(0); }); it('should get suggestions when switching subvisualization', () => { diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.tsx index 218ceb8206080..ef8c0798bb91e 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/chart_switch.tsx @@ -11,17 +11,15 @@ import { EuiIcon, EuiPopover, EuiPopoverTitle, - EuiKeyPadMenu, - EuiKeyPadMenuItem, - EuiFieldSearch, EuiFlexGroup, EuiFlexItem, - EuiSelectableMessage, + EuiSelectable, + EuiIconTip, + EuiSelectableOption, } from '@elastic/eui'; -import { flatten } from 'lodash'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { Visualization, FramePublicAPI, Datasource } from '../../../types'; +import { Visualization, FramePublicAPI, Datasource, VisualizationType } from '../../../types'; import { Action } from '../state_management'; import { getSuggestions, switchToSuggestion, Suggestion } from '../suggestion_helpers'; import { trackUiEvent } from '../../../lens_ui_telemetry'; @@ -54,6 +52,8 @@ interface Props { >; } +type SelectableEntry = EuiSelectableOption<{ value: string }>; + function VisualizationSummary(props: Props) { const visualization = props.visualizationMap[props.visualizationId || '']; @@ -79,6 +79,23 @@ function VisualizationSummary(props: Props) { ); } +const MAX_LIST_HEIGHT = 380; +const ENTRY_HEIGHT = 32; + +function computeListHeight(list: SelectableEntry[], maxHeight: number): number { + if (list.length === 0) { + return 0; + } + return Math.min(list.length * ENTRY_HEIGHT, maxHeight); +} + +function getCurrentVisualizationId( + activeVisualization: Visualization, + visualizationState: unknown +) { + return activeVisualization.getVisualizationTypeId(visualizationState); +} + export const ChartSwitch = memo(function ChartSwitch(props: Props) { const [flyoutOpen, setFlyoutOpen] = useState(false); @@ -189,28 +206,112 @@ export const ChartSwitch = memo(function ChartSwitch(props: Props) { const [searchTerm, setSearchTerm] = useState(''); - const visualizationTypes = useMemo( - () => - flyoutOpen && - flatten( - Object.values(props.visualizationMap).map((v) => - v.visualizationTypes.map((t) => ({ - visualizationId: v.id, - ...t, - icon: t.icon, - })) - ) - ) - .filter( - (visualizationType) => - visualizationType.label.toLowerCase().includes(searchTerm.toLowerCase()) || - (visualizationType.fullLabel && - visualizationType.fullLabel.toLowerCase().includes(searchTerm.toLowerCase())) - ) - .map((visualizationType) => ({ - ...visualizationType, - selection: getSelection(visualizationType.visualizationId, visualizationType.id), - })), + const { visualizationTypes, visualizationsLookup } = useMemo( + () => { + if (!flyoutOpen) { + return { visualizationTypes: [], visualizationsLookup: {} }; + } + const subVisualizationId = getCurrentVisualizationId( + props.visualizationMap[props.visualizationId || ''], + props.visualizationState + ); + const lowercasedSearchTerm = searchTerm.toLowerCase(); + // reorganize visualizations in groups + const grouped: Record< + string, + Array< + VisualizationType & { + visualizationId: string; + selection: VisualizationSelection; + } + > + > = {}; + // Will need it later on to quickly pick up the metadata from it + const lookup: Record< + string, + VisualizationType & { + visualizationId: string; + selection: VisualizationSelection; + } + > = {}; + Object.entries(props.visualizationMap).forEach(([visualizationId, v]) => { + for (const visualizationType of v.visualizationTypes) { + const isSearchMatch = + visualizationType.label.toLowerCase().includes(lowercasedSearchTerm) || + visualizationType.fullLabel?.toLowerCase().includes(lowercasedSearchTerm); + if (isSearchMatch) { + grouped[visualizationType.groupLabel] = grouped[visualizationType.groupLabel] || []; + const visualizationEntry = { + ...visualizationType, + visualizationId, + selection: getSelection(visualizationId, visualizationType.id), + }; + grouped[visualizationType.groupLabel].push(visualizationEntry); + lookup[`${visualizationId}:${visualizationType.id}`] = visualizationEntry; + } + } + }); + + return { + visualizationTypes: Object.keys(grouped) + .sort() + .flatMap((group): SelectableEntry[] => { + const visualizations = grouped[group]; + if (visualizations.length === 0) { + return []; + } + return [ + { + key: group, + label: group, + isGroupLabel: true, + 'aria-label': group, + 'data-test-subj': `lnsChartSwitchPopover_${group}`, + } as SelectableEntry, + ].concat( + visualizations + // alphabetical order within each group + .sort((a, b) => { + return (a.fullLabel || a.label).localeCompare(b.fullLabel || b.label); + }) + .map( + (v): SelectableEntry => ({ + 'aria-label': v.fullLabel || v.label, + isGroupLabel: false, + key: `${v.visualizationId}:${v.id}`, + value: `${v.visualizationId}:${v.id}`, + 'data-test-subj': `lnsChartSwitchPopover_${v.id}`, + label: v.fullLabel || v.label, + prepend: ( + + ), + append: + v.selection.dataLoss !== 'nothing' ? ( + + ) : null, + // Apparently checked: null is not valid for TS + ...(subVisualizationId === v.id && { checked: 'on' }), + }) + ) + ); + }), + visualizationsLookup: lookup, + }; + }, // eslint-disable-next-line react-hooks/exhaustive-deps [ flyoutOpen, @@ -222,89 +323,77 @@ export const ChartSwitch = memo(function ChartSwitch(props: Props) { ] ); - const popover = ( - setFlyoutOpen(!flyoutOpen)} - data-test-subj="lnsChartSwitchPopover" - fontWeight="bold" - > - - - } - isOpen={flyoutOpen} - closePopover={() => setFlyoutOpen(false)} - anchorPosition="downLeft" - > - - - - {i18n.translate('xpack.lens.configPanel.chartType', { - defaultMessage: 'Chart type', - })} - - - setSearchTerm(e.target.value)} - /> - - - - - {(visualizationTypes || []).map((v) => ( - {v.label}} - title={v.fullLabel} - role="menuitem" - data-test-subj={`lnsChartSwitchPopover_${v.id}`} - onClick={() => commitSelection(v.selection)} - betaBadgeLabel={ - v.selection.dataLoss !== 'nothing' - ? i18n.translate('xpack.lens.chartSwitch.dataLossLabel', { - defaultMessage: 'Data loss', - }) - : undefined - } - betaBadgeTooltipContent={ - v.selection.dataLoss !== 'nothing' - ? i18n.translate('xpack.lens.chartSwitch.dataLossDescription', { - defaultMessage: 'Switching to this chart will lose some of the configuration', - }) - : undefined - } - betaBadgeIconType={v.selection.dataLoss !== 'nothing' ? 'alert' : undefined} + return ( +
+ setFlyoutOpen(!flyoutOpen)} + data-test-subj="lnsChartSwitchPopover" + fontWeight="bold" > - - - ))} - - {searchTerm && (visualizationTypes || []).length === 0 && ( - - {searchTerm}, - }} - /> - - )} - + + + } + isOpen={flyoutOpen} + closePopover={() => setFlyoutOpen(false)} + anchorPosition="downLeft" + > + + + + {i18n.translate('xpack.lens.configPanel.chartType', { + defaultMessage: 'Chart type', + })} + + + + setSearchTerm(value), + }} + options={visualizationTypes} + onChange={(newOptions) => { + const chosenType = newOptions.find(({ checked }) => checked === 'on')!; + if (!chosenType) { + return; + } + const id = chosenType.value!; + commitSelection(visualizationsLookup[id].selection); + }} + noMatchesMessage={ + {searchTerm}, + }} + /> + } + > + {(list, search) => ( + <> + {search} + {list} + + )} + + +
); - - return
{popover}
; }); function getTopSuggestion( diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx index af5411dd4d3b0..486c6f120d4a8 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx @@ -515,7 +515,7 @@ export const InnerVisualizationWrapper = ({

{localState.expandError ? ( -

visibleErrorMessage

+

{visibleErrorMessage}

) : null} } diff --git a/x-pack/plugins/lens/public/editor_frame_service/mocks.tsx b/x-pack/plugins/lens/public/editor_frame_service/mocks.tsx index db3b29bb74d31..7f256dc588c25 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/mocks.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/mocks.tsx @@ -29,6 +29,7 @@ export function createMockVisualization(): jest.Mocked { icon: 'empty', id: 'TEST_VIS', label: 'TEST', + groupLabel: 'TEST_VISGroup', }, ], getVisualizationTypeId: jest.fn((_state) => 'empty'), diff --git a/x-pack/plugins/lens/public/metric_visualization/visualization.tsx b/x-pack/plugins/lens/public/metric_visualization/visualization.tsx index 91516b7b7319b..34b9e4d2b2526 100644 --- a/x-pack/plugins/lens/public/metric_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/metric_visualization/visualization.tsx @@ -52,6 +52,9 @@ export const metricVisualization: Visualization = { label: i18n.translate('xpack.lens.metric.label', { defaultMessage: 'Metric', }), + groupLabel: i18n.translate('xpack.lens.metric.groupLabel', { + defaultMessage: 'Tabular and single value', + }), }, ], diff --git a/x-pack/plugins/lens/public/pie_visualization/constants.ts b/x-pack/plugins/lens/public/pie_visualization/constants.ts index 37d67597b8784..9a2f39e7d34a5 100644 --- a/x-pack/plugins/lens/public/pie_visualization/constants.ts +++ b/x-pack/plugins/lens/public/pie_visualization/constants.ts @@ -10,24 +10,33 @@ import { LensIconChartDonut } from '../assets/chart_donut'; import { LensIconChartPie } from '../assets/chart_pie'; import { LensIconChartTreemap } from '../assets/chart_treemap'; +const groupLabel = i18n.translate('xpack.lens.pie.groupLabel', { + defaultMessage: 'Proportion', +}); + export const CHART_NAMES = { donut: { icon: LensIconChartDonut, label: i18n.translate('xpack.lens.pie.donutLabel', { defaultMessage: 'Donut', }), + groupLabel, }, pie: { icon: LensIconChartPie, label: i18n.translate('xpack.lens.pie.pielabel', { defaultMessage: 'Pie', }), + + groupLabel, }, treemap: { icon: LensIconChartTreemap, label: i18n.translate('xpack.lens.pie.treemaplabel', { defaultMessage: 'Treemap', }), + + groupLabel, }, }; diff --git a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx index 404ac99db9df7..4d6eac6a87e48 100644 --- a/x-pack/plugins/lens/public/pie_visualization/render_function.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/render_function.tsx @@ -172,7 +172,6 @@ export function PieComponent( fontFamily: chartTheme.barSeriesStyle?.displayValue?.fontFamily, outerSizeRatio: 1, specialFirstInnermostSector: true, - clockwiseSectors: false, minFontSize: 10, maxFontSize: 16, // Labels are added outside the outer ring when the slice is too small diff --git a/x-pack/plugins/lens/public/pie_visualization/visualization.tsx b/x-pack/plugins/lens/public/pie_visualization/visualization.tsx index 683acc49859b6..00d0158364e45 100644 --- a/x-pack/plugins/lens/public/pie_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/visualization.tsx @@ -45,16 +45,19 @@ export const getPieVisualization = ({ id: 'donut', icon: CHART_NAMES.donut.icon, label: CHART_NAMES.donut.label, + groupLabel: CHART_NAMES.donut.groupLabel, }, { id: 'pie', icon: CHART_NAMES.pie.icon, label: CHART_NAMES.pie.label, + groupLabel: CHART_NAMES.pie.groupLabel, }, { id: 'treemap', icon: CHART_NAMES.treemap.icon, label: CHART_NAMES.treemap.label, + groupLabel: CHART_NAMES.treemap.groupLabel, }, ], diff --git a/x-pack/plugins/lens/public/types.ts b/x-pack/plugins/lens/public/types.ts index 6ac2d98994be3..fd0c6aff27351 100644 --- a/x-pack/plugins/lens/public/types.ts +++ b/x-pack/plugins/lens/public/types.ts @@ -516,6 +516,10 @@ export interface VisualizationType { * Optional label used in chart type search if chart switcher is expanded and for tooltips */ fullLabel?: string; + /** + * The group the visualization belongs to + */ + groupLabel: string; } export interface Visualization { diff --git a/x-pack/plugins/lens/public/xy_visualization/__snapshots__/expression.test.tsx.snap b/x-pack/plugins/lens/public/xy_visualization/__snapshots__/expression.test.tsx.snap index 9a32f1c331152..a2047b7bae669 100644 --- a/x-pack/plugins/lens/public/xy_visualization/__snapshots__/expression.test.tsx.snap +++ b/x-pack/plugins/lens/public/xy_visualization/__snapshots__/expression.test.tsx.snap @@ -26,13 +26,6 @@ exports[`xy_expression XYChart component it renders area 1`] = ` "headerFormatter": [Function], } } - xDomain={ - Object { - "max": undefined, - "min": undefined, - "minInterval": 50, - } - } /> { }); }); - test('it does not use date range if the x is not a time scale', () => { + test('it has xDomain undefined if the x is not a time scale or a histogram', () => { const { data, args } = sampleArgs(); const component = shallow( @@ -571,15 +571,10 @@ describe('xy_expression', () => { /> ); const xDomain = component.find(Settings).prop('xDomain'); - expect(xDomain).toEqual( - expect.objectContaining({ - min: undefined, - max: undefined, - }) - ); + expect(xDomain).toEqual(undefined); }); - test('it uses min interval if passed in', () => { + test('it uses min interval if interval is passed in and visualization is histogram', () => { const { data, args } = sampleArgs(); const component = shallow( @@ -589,7 +584,9 @@ describe('xy_expression', () => { data={data} args={{ ...args, - layers: [{ ...args.layers[0], seriesType: 'line', xScaleType: 'linear' }], + layers: [ + { ...args.layers[0], seriesType: 'line', xScaleType: 'linear', isHistogram: true }, + ], }} /> ); diff --git a/x-pack/plugins/lens/public/xy_visualization/expression.tsx b/x-pack/plugins/lens/public/xy_visualization/expression.tsx index eda08715b394e..c5e7b0af9654f 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression.tsx @@ -388,11 +388,15 @@ export function XYChart({ const isTimeViz = data.dateRange && filteredLayers.every((l) => l.xScaleType === 'time'); const isHistogramViz = filteredLayers.every((l) => l.isHistogram); - const xDomain = { - min: isTimeViz ? data.dateRange?.fromDate.getTime() : undefined, - max: isTimeViz ? data.dateRange?.toDate.getTime() : undefined, - minInterval, - }; + const xDomain = isTimeViz + ? { + min: data.dateRange?.fromDate.getTime(), + max: data.dateRange?.toDate.getTime(), + minInterval, + } + : isHistogramViz + ? { minInterval } + : undefined; const getYAxesTitles = ( axisSeries: Array<{ layer: string; accessor: string }>, diff --git a/x-pack/plugins/lens/public/xy_visualization/types.ts b/x-pack/plugins/lens/public/xy_visualization/types.ts index da290b225e164..126be41e7b129 100644 --- a/x-pack/plugins/lens/public/xy_visualization/types.ts +++ b/x-pack/plugins/lens/public/xy_visualization/types.ts @@ -431,14 +431,22 @@ export interface XYState { } export type State = XYState; +const groupLabelForBar = i18n.translate('xpack.lens.xyVisualization.barGroupLabel', { + defaultMessage: 'Bar', +}); + +const groupLabelForLineAndArea = i18n.translate('xpack.lens.xyVisualization.lineGroupLabel', { + defaultMessage: 'Line and area', +}); export const visualizationTypes: VisualizationType[] = [ { id: 'bar', icon: LensIconChartBar, label: i18n.translate('xpack.lens.xyVisualization.barLabel', { - defaultMessage: 'Bar', + defaultMessage: 'Bar vertical', }), + groupLabel: groupLabelForBar, }, { id: 'bar_horizontal', @@ -447,22 +455,25 @@ export const visualizationTypes: VisualizationType[] = [ defaultMessage: 'H. Bar', }), fullLabel: i18n.translate('xpack.lens.xyVisualization.barHorizontalFullLabel', { - defaultMessage: 'Horizontal bar', + defaultMessage: 'Bar horizontal', }), + groupLabel: groupLabelForBar, }, { id: 'bar_stacked', icon: LensIconChartBarStacked, label: i18n.translate('xpack.lens.xyVisualization.stackedBarLabel', { - defaultMessage: 'Stacked bar', + defaultMessage: 'Bar vertical stacked', }), + groupLabel: groupLabelForBar, }, { id: 'bar_percentage_stacked', icon: LensIconChartBarPercentage, label: i18n.translate('xpack.lens.xyVisualization.stackedPercentageBarLabel', { - defaultMessage: 'Percentage bar', + defaultMessage: 'Bar vertical percentage', }), + groupLabel: groupLabelForBar, }, { id: 'bar_horizontal_stacked', @@ -471,8 +482,9 @@ export const visualizationTypes: VisualizationType[] = [ defaultMessage: 'H. Stacked bar', }), fullLabel: i18n.translate('xpack.lens.xyVisualization.stackedBarHorizontalFullLabel', { - defaultMessage: 'Horizontal stacked bar', + defaultMessage: 'Bar horizontal stacked', }), + groupLabel: groupLabelForBar, }, { id: 'bar_horizontal_percentage_stacked', @@ -483,9 +495,10 @@ export const visualizationTypes: VisualizationType[] = [ fullLabel: i18n.translate( 'xpack.lens.xyVisualization.stackedPercentageBarHorizontalFullLabel', { - defaultMessage: 'Horizontal percentage bar', + defaultMessage: 'Bar horizontal percentage', } ), + groupLabel: groupLabelForBar, }, { id: 'area', @@ -493,20 +506,23 @@ export const visualizationTypes: VisualizationType[] = [ label: i18n.translate('xpack.lens.xyVisualization.areaLabel', { defaultMessage: 'Area', }), + groupLabel: groupLabelForLineAndArea, }, { id: 'area_stacked', icon: LensIconChartAreaStacked, label: i18n.translate('xpack.lens.xyVisualization.stackedAreaLabel', { - defaultMessage: 'Stacked area', + defaultMessage: 'Area stacked', }), + groupLabel: groupLabelForLineAndArea, }, { id: 'area_percentage_stacked', icon: LensIconChartAreaPercentage, label: i18n.translate('xpack.lens.xyVisualization.stackedPercentageAreaLabel', { - defaultMessage: 'Percentage area', + defaultMessage: 'Area percentage', }), + groupLabel: groupLabelForLineAndArea, }, { id: 'line', @@ -514,5 +530,6 @@ export const visualizationTypes: VisualizationType[] = [ label: i18n.translate('xpack.lens.xyVisualization.lineLabel', { defaultMessage: 'Line', }), + groupLabel: groupLabelForLineAndArea, }, ]; diff --git a/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts b/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts index c244fa7fdfc89..319879d511a1e 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts +++ b/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts @@ -62,7 +62,7 @@ describe('xy_visualization', () => { const desc = xyVisualization.getDescription(mixedState()); expect(desc.icon).toEqual(LensIconChartBar); - expect(desc.label).toEqual('Bar'); + expect(desc.label).toEqual('Bar vertical'); }); it('should show mixed horizontal bar chart when multiple horizontal bar types', () => { @@ -70,23 +70,23 @@ describe('xy_visualization', () => { mixedState('bar_horizontal', 'bar_horizontal_stacked') ); - expect(desc.label).toEqual('Mixed H. bar'); + expect(desc.label).toEqual('Mixed bar horizontal'); }); it('should show bar chart when bar only', () => { const desc = xyVisualization.getDescription(mixedState('bar_horizontal', 'bar_horizontal')); - expect(desc.label).toEqual('H. Bar'); + expect(desc.label).toEqual('Bar horizontal'); }); it('should show the chart description if not mixed', () => { expect(xyVisualization.getDescription(mixedState('area')).label).toEqual('Area'); expect(xyVisualization.getDescription(mixedState('line')).label).toEqual('Line'); expect(xyVisualization.getDescription(mixedState('area_stacked')).label).toEqual( - 'Stacked area' + 'Area stacked' ); expect(xyVisualization.getDescription(mixedState('bar_horizontal_stacked')).label).toEqual( - 'H. Stacked bar' + 'Bar horizontal stacked' ); }); }); diff --git a/x-pack/plugins/lens/public/xy_visualization/visualization.tsx b/x-pack/plugins/lens/public/xy_visualization/visualization.tsx index 1ee4b2e050f3e..f03115aaca21b 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/visualization.tsx @@ -58,7 +58,7 @@ function getDescription(state?: State) { return { icon: LensIconChartBarHorizontal, label: i18n.translate('xpack.lens.xyVisualization.mixedBarHorizontalLabel', { - defaultMessage: 'Mixed H. bar', + defaultMessage: 'Mixed bar horizontal', }), }; } @@ -74,7 +74,7 @@ function getDescription(state?: State) { return { icon: visualizationType.icon, - label: visualizationType.label, + label: visualizationType.fullLabel || visualizationType.label, }; } diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_suggestions.test.ts b/x-pack/plugins/lens/public/xy_visualization/xy_suggestions.test.ts index 9ab5f446066f0..277ca4467aeda 100644 --- a/x-pack/plugins/lens/public/xy_visualization/xy_suggestions.test.ts +++ b/x-pack/plugins/lens/public/xy_visualization/xy_suggestions.test.ts @@ -484,7 +484,7 @@ describe('xy_suggestions', () => { }); expect(rest).toHaveLength(visualizationTypes.length - 1); - expect(suggestion.title).toEqual('Stacked bar'); + expect(suggestion.title).toEqual('Bar vertical stacked'); expect(suggestion.state).toEqual( expect.objectContaining({ layers: [ diff --git a/x-pack/plugins/ml/common/index.ts b/x-pack/plugins/ml/common/index.ts index c049b68990d2d..ac21954118e50 100644 --- a/x-pack/plugins/ml/common/index.ts +++ b/x-pack/plugins/ml/common/index.ts @@ -6,6 +6,7 @@ */ export { HitsTotalRelation, SearchResponse7, HITS_TOTAL_RELATION } from './types/es_client'; +export { ChartData } from './types/field_histograms'; export { ANOMALY_SEVERITY, ANOMALY_THRESHOLD, SEVERITY_COLORS } from './constants/anomalies'; export { getSeverityColor, getSeverityType } from './util/anomaly_utils'; export { composeValidators, patternValidator } from './util/validators'; diff --git a/x-pack/plugins/ml/common/types/field_histograms.ts b/x-pack/plugins/ml/common/types/field_histograms.ts new file mode 100644 index 0000000000000..22b0195a579ac --- /dev/null +++ b/x-pack/plugins/ml/common/types/field_histograms.ts @@ -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. + */ + +export interface NumericDataItem { + key: number; + key_as_string?: string | number; + doc_count: number; +} + +export interface NumericChartData { + data: NumericDataItem[]; + id: string; + interval: number; + stats: [number, number]; + type: 'numeric'; +} + +export const isNumericChartData = (arg: any): arg is NumericChartData => { + return ( + typeof arg === 'object' && + arg.hasOwnProperty('data') && + arg.hasOwnProperty('id') && + arg.hasOwnProperty('interval') && + arg.hasOwnProperty('stats') && + arg.hasOwnProperty('type') && + arg.type === 'numeric' + ); +}; + +export interface OrdinalDataItem { + key: string; + key_as_string?: string; + doc_count: number; +} + +export interface OrdinalChartData { + cardinality: number; + data: OrdinalDataItem[]; + id: string; + type: 'ordinal' | 'boolean'; +} + +export const isOrdinalChartData = (arg: any): arg is OrdinalChartData => { + return ( + typeof arg === 'object' && + arg.hasOwnProperty('data') && + arg.hasOwnProperty('cardinality') && + arg.hasOwnProperty('id') && + arg.hasOwnProperty('type') && + (arg.type === 'ordinal' || arg.type === 'boolean') + ); +}; + +export interface UnsupportedChartData { + id: string; + type: 'unsupported'; +} + +export const isUnsupportedChartData = (arg: any): arg is UnsupportedChartData => { + return typeof arg === 'object' && arg.hasOwnProperty('type') && arg.type === 'unsupported'; +}; + +export type ChartDataItem = NumericDataItem | OrdinalDataItem; +export type ChartData = NumericChartData | OrdinalChartData | UnsupportedChartData; diff --git a/x-pack/plugins/ml/public/application/components/data_grid/column_chart.tsx b/x-pack/plugins/ml/public/application/components/data_grid/column_chart.tsx index 102ccc560ba93..3800256927d54 100644 --- a/x-pack/plugins/ml/public/application/components/data_grid/column_chart.tsx +++ b/x-pack/plugins/ml/public/application/components/data_grid/column_chart.tsx @@ -13,7 +13,9 @@ import { EuiDataGridColumn } from '@elastic/eui'; import './column_chart.scss'; -import { isUnsupportedChartData, useColumnChart, ChartData } from './use_column_chart'; +import { isUnsupportedChartData, ChartData } from '../../../../common/types/field_histograms'; + +import { useColumnChart } from './use_column_chart'; interface Props { chartData: ChartData; diff --git a/x-pack/plugins/ml/public/application/components/data_grid/index.ts b/x-pack/plugins/ml/public/application/components/data_grid/index.ts index a3f1995736624..be37e381d1bae 100644 --- a/x-pack/plugins/ml/public/application/components/data_grid/index.ts +++ b/x-pack/plugins/ml/public/application/components/data_grid/index.ts @@ -16,7 +16,7 @@ export { useRenderCellValue, getProcessedFields, } from './common'; -export { getFieldType, ChartData } from './use_column_chart'; +export { getFieldType } from './use_column_chart'; export { useDataGrid } from './use_data_grid'; export { DataGrid } from './data_grid'; export { diff --git a/x-pack/plugins/ml/public/application/components/data_grid/types.ts b/x-pack/plugins/ml/public/application/components/data_grid/types.ts index 77c7bdb385469..2fb47a59284a3 100644 --- a/x-pack/plugins/ml/public/application/components/data_grid/types.ts +++ b/x-pack/plugins/ml/public/application/components/data_grid/types.ts @@ -11,10 +11,10 @@ import { EuiDataGridPaginationProps, EuiDataGridSorting, EuiDataGridColumn } fro import { Dictionary } from '../../../../common/types/common'; import { HitsTotalRelation } from '../../../../common/types/es_client'; +import { ChartData } from '../../../../common/types/field_histograms'; import { INDEX_STATUS } from '../../data_frame_analytics/common/analytics'; -import { ChartData } from './use_column_chart'; import { FeatureImportanceBaseline } from '../../../../common/types/feature_importance'; export type ColumnId = string; diff --git a/x-pack/plugins/ml/public/application/components/data_grid/use_column_chart.test.tsx b/x-pack/plugins/ml/public/application/components/data_grid/use_column_chart.test.tsx index 0154d43a06865..631c214dd751c 100644 --- a/x-pack/plugins/ml/public/application/components/data_grid/use_column_chart.test.tsx +++ b/x-pack/plugins/ml/public/application/components/data_grid/use_column_chart.test.tsx @@ -13,17 +13,15 @@ import '@testing-library/jest-dom/extend-expect'; import { KBN_FIELD_TYPES } from '../../../../../../../src/plugins/data/public'; import { - getFieldType, - getLegendText, - getXScaleType, isNumericChartData, isOrdinalChartData, isUnsupportedChartData, - useColumnChart, NumericChartData, OrdinalChartData, UnsupportedChartData, -} from './use_column_chart'; +} from '../../../../common/types/field_histograms'; + +import { getFieldType, getLegendText, getXScaleType, useColumnChart } from './use_column_chart'; describe('getFieldType()', () => { it('should return the Kibana field type for a given EUI data grid schema', () => { diff --git a/x-pack/plugins/ml/public/application/components/data_grid/use_column_chart.tsx b/x-pack/plugins/ml/public/application/components/data_grid/use_column_chart.tsx index fcb8a20f558fd..4764a1674df2f 100644 --- a/x-pack/plugins/ml/public/application/components/data_grid/use_column_chart.tsx +++ b/x-pack/plugins/ml/public/application/components/data_grid/use_column_chart.tsx @@ -17,6 +17,15 @@ import { i18n } from '@kbn/i18n'; import { KBN_FIELD_TYPES } from '../../../../../../../src/plugins/data/public'; +import { + isNumericChartData, + isOrdinalChartData, + ChartData, + ChartDataItem, + NumericDataItem, + OrdinalDataItem, +} from '../../../../common/types/field_histograms'; + import { NON_AGGREGATABLE } from './common'; export const hoveredRow$ = new BehaviorSubject(null); @@ -66,68 +75,6 @@ export const getFieldType = (schema: EuiDataGridColumn['schema']): KBN_FIELD_TYP return fieldType; }; -interface NumericDataItem { - key: number; - key_as_string?: string | number; - doc_count: number; -} - -export interface NumericChartData { - data: NumericDataItem[]; - id: string; - interval: number; - stats: [number, number]; - type: 'numeric'; -} - -export const isNumericChartData = (arg: any): arg is NumericChartData => { - return ( - typeof arg === 'object' && - arg.hasOwnProperty('data') && - arg.hasOwnProperty('id') && - arg.hasOwnProperty('interval') && - arg.hasOwnProperty('stats') && - arg.hasOwnProperty('type') && - arg.type === 'numeric' - ); -}; - -export interface OrdinalDataItem { - key: string; - key_as_string?: string; - doc_count: number; -} - -export interface OrdinalChartData { - cardinality: number; - data: OrdinalDataItem[]; - id: string; - type: 'ordinal' | 'boolean'; -} - -export const isOrdinalChartData = (arg: any): arg is OrdinalChartData => { - return ( - typeof arg === 'object' && - arg.hasOwnProperty('data') && - arg.hasOwnProperty('cardinality') && - arg.hasOwnProperty('id') && - arg.hasOwnProperty('type') && - (arg.type === 'ordinal' || arg.type === 'boolean') - ); -}; - -export interface UnsupportedChartData { - id: string; - type: 'unsupported'; -} - -export const isUnsupportedChartData = (arg: any): arg is UnsupportedChartData => { - return typeof arg === 'object' && arg.hasOwnProperty('type') && arg.type === 'unsupported'; -}; - -export type ChartDataItem = NumericDataItem | OrdinalDataItem; -export type ChartData = NumericChartData | OrdinalChartData | UnsupportedChartData; - type LegendText = string | JSX.Element; export const getLegendText = ( chartData: ChartData, diff --git a/x-pack/plugins/ml/public/application/components/data_grid/use_data_grid.tsx b/x-pack/plugins/ml/public/application/components/data_grid/use_data_grid.tsx index 4129f3a01bce9..228ee86a7f800 100644 --- a/x-pack/plugins/ml/public/application/components/data_grid/use_data_grid.tsx +++ b/x-pack/plugins/ml/public/application/components/data_grid/use_data_grid.tsx @@ -10,6 +10,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { EuiDataGridSorting, EuiDataGridColumn } from '@elastic/eui'; import { HITS_TOTAL_RELATION } from '../../../../common/types/es_client'; +import { ChartData } from '../../../../common/types/field_histograms'; import { INDEX_STATUS } from '../../data_frame_analytics/common'; @@ -26,7 +27,6 @@ import { RowCountRelation, UseDataGridReturnType, } from './types'; -import { ChartData } from './use_column_chart'; export const useDataGrid = ( columns: EuiDataGridColumn[], diff --git a/x-pack/plugins/ml/public/application/datavisualizer/stats_table/components/field_data_row/boolean_content_preview.tsx b/x-pack/plugins/ml/public/application/datavisualizer/stats_table/components/field_data_row/boolean_content_preview.tsx index 17b2e04256098..70adbbe85bc58 100644 --- a/x-pack/plugins/ml/public/application/datavisualizer/stats_table/components/field_data_row/boolean_content_preview.tsx +++ b/x-pack/plugins/ml/public/application/datavisualizer/stats_table/components/field_data_row/boolean_content_preview.tsx @@ -7,10 +7,10 @@ import React, { FC, useMemo } from 'react'; import { EuiDataGridColumn } from '@elastic/eui'; +import { OrdinalChartData } from '../../../../../../common/types/field_histograms'; +import { ColumnChart } from '../../../../components/data_grid/column_chart'; import { FieldDataRowProps } from '../../types'; import { getTFPercentage } from '../../utils'; -import { ColumnChart } from '../../../../components/data_grid/column_chart'; -import { OrdinalChartData } from '../../../../components/data_grid/use_column_chart'; export const BooleanContentPreview: FC = ({ config }) => { const chartData = useMemo(() => { diff --git a/x-pack/plugins/ml/public/application/datavisualizer/stats_table/components/field_data_row/top_values_preview.tsx b/x-pack/plugins/ml/public/application/datavisualizer/stats_table/components/field_data_row/top_values_preview.tsx index 122663b304024..07a2eae95c890 100644 --- a/x-pack/plugins/ml/public/application/datavisualizer/stats_table/components/field_data_row/top_values_preview.tsx +++ b/x-pack/plugins/ml/public/application/datavisualizer/stats_table/components/field_data_row/top_values_preview.tsx @@ -7,10 +7,9 @@ import React, { FC } from 'react'; import { EuiDataGridColumn } from '@elastic/eui'; -import type { FieldDataRowProps } from '../../types/field_data_row'; +import { ChartData, OrdinalDataItem } from '../../../../../../common/types/field_histograms'; import { ColumnChart } from '../../../../components/data_grid/column_chart'; -import { ChartData } from '../../../../components/data_grid'; -import { OrdinalDataItem } from '../../../../components/data_grid/use_column_chart'; +import type { FieldDataRowProps } from '../../types/field_data_row'; export const TopValuesPreview: FC = ({ config }) => { const { stats } = config; diff --git a/x-pack/plugins/ml/server/models/data_visualizer/data_visualizer.ts b/x-pack/plugins/ml/server/models/data_visualizer/data_visualizer.ts index 69ebfe5f0bc11..4db8295d93997 100644 --- a/x-pack/plugins/ml/server/models/data_visualizer/data_visualizer.ts +++ b/x-pack/plugins/ml/server/models/data_visualizer/data_visualizer.ts @@ -16,7 +16,7 @@ import { buildSamplerAggregation, getSamplerAggregationsResponsePath, } from '../../lib/query_utils'; -import { AggCardinality } from '../../../common/types/fields'; +import { AggCardinality, RuntimeMappings } from '../../../common/types/fields'; import { getDatafeedAggregations } from '../../../common/util/datafeed_utils'; import { Datafeed } from '../../../common/types/anomaly_detection_jobs'; import { isPopulatedObject } from '../../../common/util/object_utils'; @@ -183,7 +183,8 @@ const getAggIntervals = async ( indexPatternTitle: string, query: any, fields: HistogramField[], - samplerShardSize: number + samplerShardSize: number, + runtimeMappings?: RuntimeMappings ): Promise => { const numericColumns = fields.filter((field) => { return field.type === KBN_FIELD_TYPES.NUMBER || field.type === KBN_FIELD_TYPES.DATE; @@ -210,6 +211,7 @@ const getAggIntervals = async ( query, aggs: buildSamplerAggregation(minMaxAggs, samplerShardSize), size: 0, + ...(runtimeMappings !== undefined ? { runtime_mappings: runtimeMappings } : {}), }, }); @@ -240,7 +242,8 @@ export const getHistogramsForFields = async ( indexPatternTitle: string, query: any, fields: HistogramField[], - samplerShardSize: number + samplerShardSize: number, + runtimeMappings?: RuntimeMappings ) => { const { asCurrentUser } = client; const aggIntervals = await getAggIntervals( @@ -248,7 +251,8 @@ export const getHistogramsForFields = async ( indexPatternTitle, query, fields, - samplerShardSize + samplerShardSize, + runtimeMappings ); const chartDataAggs = fields.reduce((aggs, field) => { @@ -293,6 +297,7 @@ export const getHistogramsForFields = async ( query, aggs: buildSamplerAggregation(chartDataAggs, samplerShardSize), size: 0, + ...(runtimeMappings !== undefined ? { runtime_mappings: runtimeMappings } : {}), }, }); @@ -607,7 +612,7 @@ export class DataVisualizer { // Value count aggregation faster way of checking if field exists than using // filter aggregation with exists query. const aggs: Aggs = datafeedAggregations !== undefined ? { ...datafeedAggregations } : {}; - const runtimeMappings: any = {}; + const runtimeMappings: { runtime_mappings?: RuntimeMappings } = {}; aggregatableFields.forEach((field, i) => { const safeFieldName = getSafeAggregationName(field, i); diff --git a/x-pack/plugins/security/.eslintrc.json b/x-pack/plugins/security/.eslintrc.json new file mode 100644 index 0000000000000..2b63a9259d220 --- /dev/null +++ b/x-pack/plugins/security/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "rules": { + "@typescript-eslint/consistent-type-imports": 1 + } +} diff --git a/x-pack/plugins/security/common/licensing/index.mock.ts b/x-pack/plugins/security/common/licensing/index.mock.ts index fec78d018a38b..319faa1a5b344 100644 --- a/x-pack/plugins/security/common/licensing/index.mock.ts +++ b/x-pack/plugins/security/common/licensing/index.mock.ts @@ -6,7 +6,9 @@ */ import { of } from 'rxjs'; -import { SecurityLicense, SecurityLicenseFeatures } from '.'; + +import type { SecurityLicenseFeatures } from './license_features'; +import type { SecurityLicense } from './license_service'; export const licenseMock = { create: (features?: Partial): jest.Mocked => ({ diff --git a/x-pack/plugins/security/common/licensing/license_service.test.ts b/x-pack/plugins/security/common/licensing/license_service.test.ts index 2daf4efbc99b9..cdc80c1a038f1 100644 --- a/x-pack/plugins/security/common/licensing/license_service.test.ts +++ b/x-pack/plugins/security/common/licensing/license_service.test.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { of, BehaviorSubject } from 'rxjs'; +import { BehaviorSubject, of } from 'rxjs'; + import { licenseMock } from '../../../licensing/common/licensing.mock'; import { SecurityLicenseService } from './license_service'; diff --git a/x-pack/plugins/security/common/licensing/license_service.ts b/x-pack/plugins/security/common/licensing/license_service.ts index 106581f8b61c9..7bebf65b48205 100644 --- a/x-pack/plugins/security/common/licensing/license_service.ts +++ b/x-pack/plugins/security/common/licensing/license_service.ts @@ -5,10 +5,11 @@ * 2.0. */ -import { Observable, Subscription } from 'rxjs'; +import type { Observable, Subscription } from 'rxjs'; import { map } from 'rxjs/operators'; -import { ILicense, LicenseType } from '../../../licensing/common/types'; -import { SecurityLicenseFeatures } from './license_features'; + +import type { ILicense, LicenseType } from '../../../licensing/common/types'; +import type { SecurityLicenseFeatures } from './license_features'; export interface SecurityLicense { isLicenseAvailable(): boolean; diff --git a/x-pack/plugins/security/common/login_state.ts b/x-pack/plugins/security/common/login_state.ts index a156a782e10a4..fe2c6380db3ee 100644 --- a/x-pack/plugins/security/common/login_state.ts +++ b/x-pack/plugins/security/common/login_state.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { LoginLayout } from './licensing'; +import type { LoginLayout } from './licensing'; export interface LoginSelectorProvider { type: string; diff --git a/x-pack/plugins/security/common/model/authenticated_user.mock.ts b/x-pack/plugins/security/common/model/authenticated_user.mock.ts index 7357b7d49ac7f..3715245b37e61 100644 --- a/x-pack/plugins/security/common/model/authenticated_user.mock.ts +++ b/x-pack/plugins/security/common/model/authenticated_user.mock.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { AuthenticatedUser } from './authenticated_user'; +import type { AuthenticatedUser } from './authenticated_user'; export function mockAuthenticatedUser(user: Partial = {}) { return { diff --git a/x-pack/plugins/security/common/model/authenticated_user.test.ts b/x-pack/plugins/security/common/model/authenticated_user.test.ts index 4d2b6f71b4bfb..86a976daf7bf6 100644 --- a/x-pack/plugins/security/common/model/authenticated_user.test.ts +++ b/x-pack/plugins/security/common/model/authenticated_user.test.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { AuthenticatedUser, canUserChangePassword } from './authenticated_user'; +import type { AuthenticatedUser } from './authenticated_user'; +import { canUserChangePassword } from './authenticated_user'; describe('#canUserChangePassword', () => { ['reserved', 'native'].forEach((realm) => { diff --git a/x-pack/plugins/security/common/model/authenticated_user.ts b/x-pack/plugins/security/common/model/authenticated_user.ts index 590a191db85c1..d9fabc25df5ed 100644 --- a/x-pack/plugins/security/common/model/authenticated_user.ts +++ b/x-pack/plugins/security/common/model/authenticated_user.ts @@ -5,7 +5,8 @@ * 2.0. */ -import type { AuthenticationProvider, User } from '.'; +import type { AuthenticationProvider } from './authentication_provider'; +import type { User } from './user'; const REALMS_ELIGIBLE_FOR_PASSWORD_CHANGE = ['reserved', 'native']; diff --git a/x-pack/plugins/security/common/model/role.test.ts b/x-pack/plugins/security/common/model/role.test.ts index da386b74fae8c..0d08c60ff7115 100644 --- a/x-pack/plugins/security/common/model/role.test.ts +++ b/x-pack/plugins/security/common/model/role.test.ts @@ -5,15 +5,15 @@ * 2.0. */ +import type { Role } from '../../common/model'; import { - Role, - isRoleEnabled, - isRoleReserved, + copyRole, + getExtendedRoleDeprecationNotice, isRoleDeprecated, + isRoleEnabled, isRoleReadOnly, - copyRole, + isRoleReserved, prepareRoleClone, - getExtendedRoleDeprecationNotice, } from '../../common/model'; describe('role', () => { diff --git a/x-pack/plugins/security/common/model/role.ts b/x-pack/plugins/security/common/model/role.ts index 4e86494771a76..31ff3cc484b8f 100644 --- a/x-pack/plugins/security/common/model/role.ts +++ b/x-pack/plugins/security/common/model/role.ts @@ -6,8 +6,10 @@ */ import { cloneDeep } from 'lodash'; + import { i18n } from '@kbn/i18n'; -import { FeaturesPrivileges } from './features_privileges'; + +import type { FeaturesPrivileges } from './features_privileges'; export interface RoleIndexPrivilege { names: string[]; diff --git a/x-pack/plugins/security/common/model/user.test.ts b/x-pack/plugins/security/common/model/user.test.ts index 8822b82dd25b5..1f04456fbecf8 100644 --- a/x-pack/plugins/security/common/model/user.test.ts +++ b/x-pack/plugins/security/common/model/user.test.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { getUserDisplayName, User } from './user'; +import type { User } from './user'; +import { getUserDisplayName } from './user'; describe('#getUserDisplayName', () => { it(`uses the full name when available`, () => { diff --git a/x-pack/plugins/security/common/parse_next.ts b/x-pack/plugins/security/common/parse_next.ts index 1485f85ab8fcb..bf7bb3b070736 100644 --- a/x-pack/plugins/security/common/parse_next.ts +++ b/x-pack/plugins/security/common/parse_next.ts @@ -6,6 +6,7 @@ */ import { parse } from 'url'; + import { NEXT_URL_QUERY_STRING_PARAMETER } from './constants'; import { isInternalURL } from './is_internal_url'; diff --git a/x-pack/plugins/security/public/account_management/account_management_app.test.ts b/x-pack/plugins/security/public/account_management/account_management_app.test.ts index 5e9494ec203e9..2dfc7fac90a29 100644 --- a/x-pack/plugins/security/public/account_management/account_management_app.test.ts +++ b/x-pack/plugins/security/public/account_management/account_management_app.test.ts @@ -7,12 +7,13 @@ jest.mock('./account_management_page'); -import { AppMount, AppNavLinkStatus } from 'src/core/public'; -import { UserAPIClient } from '../management'; -import { accountManagementApp } from './account_management_app'; +import type { AppMount } from 'src/core/public'; +import { AppNavLinkStatus } from 'src/core/public'; +import { coreMock, scopedHistoryMock } from 'src/core/public/mocks'; -import { coreMock, scopedHistoryMock } from '../../../../../src/core/public/mocks'; +import { UserAPIClient } from '../management'; import { securityMock } from '../mocks'; +import { accountManagementApp } from './account_management_app'; describe('accountManagementApp', () => { it('properly registers application', () => { diff --git a/x-pack/plugins/security/public/account_management/account_management_app.ts b/x-pack/plugins/security/public/account_management/account_management_app.ts index fd43609d9c3c2..e94f8862f1e59 100644 --- a/x-pack/plugins/security/public/account_management/account_management_app.ts +++ b/x-pack/plugins/security/public/account_management/account_management_app.ts @@ -6,13 +6,10 @@ */ import { i18n } from '@kbn/i18n'; -import { - ApplicationSetup, - AppMountParameters, - AppNavLinkStatus, - StartServicesAccessor, -} from '../../../../../src/core/public'; -import { AuthenticationServiceSetup } from '../authentication'; +import type { ApplicationSetup, AppMountParameters, StartServicesAccessor } from 'src/core/public'; + +import { AppNavLinkStatus } from '../../../../../src/core/public'; +import type { AuthenticationServiceSetup } from '../authentication'; interface CreateDeps { application: ApplicationSetup; diff --git a/x-pack/plugins/security/public/account_management/account_management_page.test.tsx b/x-pack/plugins/security/public/account_management/account_management_page.test.tsx index a439de9dff279..d45ba91bb35fb 100644 --- a/x-pack/plugins/security/public/account_management/account_management_page.test.tsx +++ b/x-pack/plugins/security/public/account_management/account_management_page.test.tsx @@ -5,15 +5,17 @@ * 2.0. */ -import React from 'react'; import { act } from '@testing-library/react'; +import React from 'react'; + import { mountWithIntl, nextTick } from '@kbn/test/jest'; -import { AuthenticatedUser } from '../../common/model'; -import { AccountManagementPage } from './account_management_page'; import { coreMock } from 'src/core/public/mocks'; + +import type { AuthenticatedUser } from '../../common/model'; import { mockAuthenticatedUser } from '../../common/model/authenticated_user.mock'; -import { securityMock } from '../mocks'; import { userAPIClientMock } from '../management/users/index.mock'; +import { securityMock } from '../mocks'; +import { AccountManagementPage } from './account_management_page'; interface Options { withFullName?: boolean; diff --git a/x-pack/plugins/security/public/account_management/account_management_page.tsx b/x-pack/plugins/security/public/account_management/account_management_page.tsx index 6bf34f7dc2f29..c8fe80e254a46 100644 --- a/x-pack/plugins/security/public/account_management/account_management_page.tsx +++ b/x-pack/plugins/security/public/account_management/account_management_page.tsx @@ -5,14 +5,17 @@ * 2.0. */ +import { EuiPage, EuiPageBody, EuiPanel, EuiSpacer, EuiText } from '@elastic/eui'; import React, { useEffect, useState } from 'react'; import ReactDOM from 'react-dom'; -import { EuiPage, EuiPageBody, EuiPanel, EuiSpacer, EuiText } from '@elastic/eui'; + import type { PublicMethodsOf } from '@kbn/utility-types'; -import { CoreStart, NotificationsStart } from 'src/core/public'; -import { getUserDisplayName, AuthenticatedUser } from '../../common/model'; -import { AuthenticationServiceSetup } from '../authentication'; -import { UserAPIClient } from '../management'; +import type { CoreStart, NotificationsStart } from 'src/core/public'; + +import type { AuthenticatedUser } from '../../common/model'; +import { getUserDisplayName } from '../../common/model'; +import type { AuthenticationServiceSetup } from '../authentication'; +import type { UserAPIClient } from '../management'; import { ChangePassword } from './change_password'; import { PersonalInfo } from './personal_info'; diff --git a/x-pack/plugins/security/public/account_management/change_password/change_password.tsx b/x-pack/plugins/security/public/account_management/change_password/change_password.tsx index 4e252c343dc56..90d63d8b43bc7 100644 --- a/x-pack/plugins/security/public/account_management/change_password/change_password.tsx +++ b/x-pack/plugins/security/public/account_management/change_password/change_password.tsx @@ -5,13 +5,16 @@ * 2.0. */ -import React, { Component } from 'react'; import { EuiDescribedFormGroup } from '@elastic/eui'; +import React, { Component } from 'react'; + import { FormattedMessage } from '@kbn/i18n/react'; import type { PublicMethodsOf } from '@kbn/utility-types'; -import { NotificationsSetup } from 'src/core/public'; -import { AuthenticatedUser, canUserChangePassword } from '../../../common/model'; -import { UserAPIClient } from '../../management/users'; +import type { NotificationsSetup } from 'src/core/public'; + +import type { AuthenticatedUser } from '../../../common/model'; +import { canUserChangePassword } from '../../../common/model'; +import type { UserAPIClient } from '../../management/users'; import { ChangePasswordForm } from '../../management/users/components/change_password_form'; interface Props { diff --git a/x-pack/plugins/security/public/account_management/personal_info/personal_info.tsx b/x-pack/plugins/security/public/account_management/personal_info/personal_info.tsx index ebfdb52bdf2cf..e9de2b8a69bfa 100644 --- a/x-pack/plugins/security/public/account_management/personal_info/personal_info.tsx +++ b/x-pack/plugins/security/public/account_management/personal_info/personal_info.tsx @@ -5,10 +5,12 @@ * 2.0. */ -import React from 'react'; import { EuiDescribedFormGroup, EuiFormRow, EuiText } from '@elastic/eui'; +import React from 'react'; + import { FormattedMessage } from '@kbn/i18n/react'; -import { AuthenticatedUser } from '../../../common/model'; + +import type { AuthenticatedUser } from '../../../common/model'; interface Props { user: AuthenticatedUser; diff --git a/x-pack/plugins/security/public/authentication/access_agreement/access_agreement_app.test.ts b/x-pack/plugins/security/public/authentication/access_agreement/access_agreement_app.test.ts index 56e51dda39f1a..fc3565adf5caf 100644 --- a/x-pack/plugins/security/public/authentication/access_agreement/access_agreement_app.test.ts +++ b/x-pack/plugins/security/public/authentication/access_agreement/access_agreement_app.test.ts @@ -7,10 +7,10 @@ jest.mock('./access_agreement_page'); -import { AppMount } from 'src/core/public'; -import { accessAgreementApp } from './access_agreement_app'; +import type { AppMount } from 'src/core/public'; +import { coreMock, scopedHistoryMock } from 'src/core/public/mocks'; -import { coreMock, scopedHistoryMock } from '../../../../../../src/core/public/mocks'; +import { accessAgreementApp } from './access_agreement_app'; describe('accessAgreementApp', () => { it('properly registers application', () => { diff --git a/x-pack/plugins/security/public/authentication/access_agreement/access_agreement_app.ts b/x-pack/plugins/security/public/authentication/access_agreement/access_agreement_app.ts index f1466dbd95348..27da278b8fa89 100644 --- a/x-pack/plugins/security/public/authentication/access_agreement/access_agreement_app.ts +++ b/x-pack/plugins/security/public/authentication/access_agreement/access_agreement_app.ts @@ -6,7 +6,7 @@ */ import { i18n } from '@kbn/i18n'; -import { StartServicesAccessor, ApplicationSetup, AppMountParameters } from 'src/core/public'; +import type { ApplicationSetup, AppMountParameters, StartServicesAccessor } from 'src/core/public'; interface CreateDeps { application: ApplicationSetup; diff --git a/x-pack/plugins/security/public/authentication/access_agreement/access_agreement_page.test.tsx b/x-pack/plugins/security/public/authentication/access_agreement/access_agreement_page.test.tsx index 396747a93cd08..f6fcf36a12ee6 100644 --- a/x-pack/plugins/security/public/authentication/access_agreement/access_agreement_page.test.tsx +++ b/x-pack/plugins/security/public/authentication/access_agreement/access_agreement_page.test.tsx @@ -5,13 +5,14 @@ * 2.0. */ -import React from 'react'; -import ReactMarkdown from 'react-markdown'; import { EuiLoadingContent } from '@elastic/eui'; import { act } from '@testing-library/react'; -import { mountWithIntl, nextTick } from '@kbn/test/jest'; -import { findTestSubject } from '@kbn/test/jest'; -import { coreMock } from '../../../../../../src/core/public/mocks'; +import React from 'react'; +import ReactMarkdown from 'react-markdown'; + +import { findTestSubject, mountWithIntl, nextTick } from '@kbn/test/jest'; +import { coreMock } from 'src/core/public/mocks'; + import { AccessAgreementPage } from './access_agreement_page'; describe('AccessAgreementPage', () => { diff --git a/x-pack/plugins/security/public/authentication/access_agreement/access_agreement_page.tsx b/x-pack/plugins/security/public/authentication/access_agreement/access_agreement_page.tsx index 856dcf56b1d14..78f36bb460f47 100644 --- a/x-pack/plugins/security/public/authentication/access_agreement/access_agreement_page.tsx +++ b/x-pack/plugins/security/public/authentication/access_agreement/access_agreement_page.tsx @@ -7,21 +7,23 @@ import './access_agreement_page.scss'; -import React, { FormEvent, MouseEvent, useCallback, useEffect, useState } from 'react'; -import ReactDOM from 'react-dom'; -import ReactMarkdown from 'react-markdown'; import { EuiButton, - EuiPanel, EuiFlexGroup, EuiFlexItem, EuiLoadingContent, + EuiPanel, EuiSpacer, EuiText, } from '@elastic/eui'; +import type { FormEvent, MouseEvent } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; +import ReactDOM from 'react-dom'; +import ReactMarkdown from 'react-markdown'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { CoreStart, FatalErrorsStart, HttpStart, NotificationsStart } from 'src/core/public'; +import type { CoreStart, FatalErrorsStart, HttpStart, NotificationsStart } from 'src/core/public'; import { parseNext } from '../../../common/parse_next'; import { AuthenticationStatePage } from '../components'; diff --git a/x-pack/plugins/security/public/authentication/authentication_service.ts b/x-pack/plugins/security/public/authentication/authentication_service.ts index 1d677391961ea..4f0f69ac68886 100644 --- a/x-pack/plugins/security/public/authentication/authentication_service.ts +++ b/x-pack/plugins/security/public/authentication/authentication_service.ts @@ -5,21 +5,22 @@ * 2.0. */ -import { +import type { ApplicationSetup, - StartServicesAccessor, - HttpSetup, FatalErrorsSetup, + HttpSetup, + StartServicesAccessor, } from 'src/core/public'; -import { AuthenticatedUser } from '../../common/model'; -import { ConfigType } from '../config'; -import { PluginStartDependencies } from '../plugin'; + +import type { AuthenticatedUser } from '../../common/model'; +import type { ConfigType } from '../config'; +import type { PluginStartDependencies } from '../plugin'; import { accessAgreementApp } from './access_agreement'; +import { captureURLApp } from './capture_url'; +import { loggedOutApp } from './logged_out'; import { loginApp } from './login'; import { logoutApp } from './logout'; -import { loggedOutApp } from './logged_out'; import { overwrittenSessionApp } from './overwritten_session'; -import { captureURLApp } from './capture_url'; interface SetupParams { application: ApplicationSetup; diff --git a/x-pack/plugins/security/public/authentication/capture_url/capture_url_app.test.ts b/x-pack/plugins/security/public/authentication/capture_url/capture_url_app.test.ts index 87d6edcb8e8c7..bf68d9f7a6e5e 100644 --- a/x-pack/plugins/security/public/authentication/capture_url/capture_url_app.test.ts +++ b/x-pack/plugins/security/public/authentication/capture_url/capture_url_app.test.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { AppMount, ScopedHistory } from 'src/core/public'; -import { captureURLApp } from './capture_url_app'; +import type { AppMount, ScopedHistory } from 'src/core/public'; +import { coreMock, scopedHistoryMock } from 'src/core/public/mocks'; -import { coreMock, scopedHistoryMock } from '../../../../../../src/core/public/mocks'; +import { captureURLApp } from './capture_url_app'; describe('captureURLApp', () => { beforeAll(() => { diff --git a/x-pack/plugins/security/public/authentication/capture_url/capture_url_app.ts b/x-pack/plugins/security/public/authentication/capture_url/capture_url_app.ts index 464c89f2a9e30..7797ce4e62102 100644 --- a/x-pack/plugins/security/public/authentication/capture_url/capture_url_app.ts +++ b/x-pack/plugins/security/public/authentication/capture_url/capture_url_app.ts @@ -6,7 +6,8 @@ */ import { parse } from 'url'; -import { ApplicationSetup, FatalErrorsSetup, HttpSetup } from 'src/core/public'; + +import type { ApplicationSetup, FatalErrorsSetup, HttpSetup } from 'src/core/public'; interface CreateDeps { application: ApplicationSetup; diff --git a/x-pack/plugins/security/public/authentication/components/authentication_state_page/authentication_state_page.test.tsx b/x-pack/plugins/security/public/authentication/components/authentication_state_page/authentication_state_page.test.tsx index 8caefdb2af237..eba918e072110 100644 --- a/x-pack/plugins/security/public/authentication/components/authentication_state_page/authentication_state_page.test.tsx +++ b/x-pack/plugins/security/public/authentication/components/authentication_state_page/authentication_state_page.test.tsx @@ -5,9 +5,11 @@ * 2.0. */ +import React from 'react'; + import { shallowWithIntl } from '@kbn/test/jest'; + import { AuthenticationStatePage } from './authentication_state_page'; -import React from 'react'; describe('AuthenticationStatePage', () => { it('renders', () => { diff --git a/x-pack/plugins/security/public/authentication/index.mock.ts b/x-pack/plugins/security/public/authentication/index.mock.ts index ac8bf9dfe9687..47c9dad012eae 100644 --- a/x-pack/plugins/security/public/authentication/index.mock.ts +++ b/x-pack/plugins/security/public/authentication/index.mock.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { AuthenticationServiceSetup } from './authentication_service'; +import type { AuthenticationServiceSetup } from './authentication_service'; export const authenticationMock = { createSetup: (): jest.Mocked => ({ diff --git a/x-pack/plugins/security/public/authentication/logged_out/logged_out_app.test.ts b/x-pack/plugins/security/public/authentication/logged_out/logged_out_app.test.ts index 94ee1542c2570..6c6071e9af7ee 100644 --- a/x-pack/plugins/security/public/authentication/logged_out/logged_out_app.test.ts +++ b/x-pack/plugins/security/public/authentication/logged_out/logged_out_app.test.ts @@ -7,10 +7,10 @@ jest.mock('./logged_out_page'); -import { AppMount } from 'src/core/public'; -import { loggedOutApp } from './logged_out_app'; +import type { AppMount } from 'src/core/public'; +import { coreMock, scopedHistoryMock } from 'src/core/public/mocks'; -import { coreMock, scopedHistoryMock } from '../../../../../../src/core/public/mocks'; +import { loggedOutApp } from './logged_out_app'; describe('loggedOutApp', () => { it('properly registers application', () => { diff --git a/x-pack/plugins/security/public/authentication/logged_out/logged_out_app.ts b/x-pack/plugins/security/public/authentication/logged_out/logged_out_app.ts index 4514c2bc3146f..962524de6d1f0 100644 --- a/x-pack/plugins/security/public/authentication/logged_out/logged_out_app.ts +++ b/x-pack/plugins/security/public/authentication/logged_out/logged_out_app.ts @@ -6,11 +6,11 @@ */ import { i18n } from '@kbn/i18n'; -import { - StartServicesAccessor, +import type { ApplicationSetup, AppMountParameters, HttpSetup, + StartServicesAccessor, } from 'src/core/public'; interface CreateDeps { diff --git a/x-pack/plugins/security/public/authentication/logged_out/logged_out_page.test.tsx b/x-pack/plugins/security/public/authentication/logged_out/logged_out_page.test.tsx index c8078190ccc23..8647edd2ba06a 100644 --- a/x-pack/plugins/security/public/authentication/logged_out/logged_out_page.test.tsx +++ b/x-pack/plugins/security/public/authentication/logged_out/logged_out_page.test.tsx @@ -5,12 +5,13 @@ * 2.0. */ -import React from 'react'; import { EuiButton } from '@elastic/eui'; +import React from 'react'; + import { mountWithIntl } from '@kbn/test/jest'; -import { LoggedOutPage } from './logged_out_page'; +import { coreMock } from 'src/core/public/mocks'; -import { coreMock } from '../../../../../../src/core/public/mocks'; +import { LoggedOutPage } from './logged_out_page'; describe('LoggedOutPage', () => { beforeAll(() => { diff --git a/x-pack/plugins/security/public/authentication/logged_out/logged_out_page.tsx b/x-pack/plugins/security/public/authentication/logged_out/logged_out_page.tsx index 9190c58a57c5e..477a41e248858 100644 --- a/x-pack/plugins/security/public/authentication/logged_out/logged_out_page.tsx +++ b/x-pack/plugins/security/public/authentication/logged_out/logged_out_page.tsx @@ -5,11 +5,13 @@ * 2.0. */ +import { EuiButton } from '@elastic/eui'; import React from 'react'; import ReactDOM from 'react-dom'; -import { EuiButton } from '@elastic/eui'; + import { FormattedMessage } from '@kbn/i18n/react'; -import { CoreStart, IBasePath } from 'src/core/public'; +import type { CoreStart, IBasePath } from 'src/core/public'; + import { parseNext } from '../../../common/parse_next'; import { AuthenticationStatePage } from '../components'; diff --git a/x-pack/plugins/security/public/authentication/login/components/disabled_login_form/disabled_login_form.test.tsx b/x-pack/plugins/security/public/authentication/login/components/disabled_login_form/disabled_login_form.test.tsx index d280d24c9f9ae..a347ebd0a3317 100644 --- a/x-pack/plugins/security/public/authentication/login/components/disabled_login_form/disabled_login_form.test.tsx +++ b/x-pack/plugins/security/public/authentication/login/components/disabled_login_form/disabled_login_form.test.tsx @@ -7,6 +7,7 @@ import { shallow } from 'enzyme'; import React from 'react'; + import { DisabledLoginForm } from './disabled_login_form'; describe('DisabledLoginForm', () => { diff --git a/x-pack/plugins/security/public/authentication/login/components/disabled_login_form/disabled_login_form.tsx b/x-pack/plugins/security/public/authentication/login/components/disabled_login_form/disabled_login_form.tsx index 723f7b2d2f50b..56913ef684cc4 100644 --- a/x-pack/plugins/security/public/authentication/login/components/disabled_login_form/disabled_login_form.tsx +++ b/x-pack/plugins/security/public/authentication/login/components/disabled_login_form/disabled_login_form.tsx @@ -6,7 +6,8 @@ */ import { EuiPanel, EuiText } from '@elastic/eui'; -import React, { ReactNode } from 'react'; +import type { ReactNode } from 'react'; +import React from 'react'; interface Props { title: ReactNode; diff --git a/x-pack/plugins/security/public/authentication/login/components/login_form/login_form.test.tsx b/x-pack/plugins/security/public/authentication/login/components/login_form/login_form.test.tsx index a29e307cf7807..f58150d4580b8 100644 --- a/x-pack/plugins/security/public/authentication/login/components/login_form/login_form.test.tsx +++ b/x-pack/plugins/security/public/authentication/login/components/login_form/login_form.test.tsx @@ -5,16 +5,16 @@ * 2.0. */ +import { EuiButton, EuiCallOut, EuiIcon } from '@elastic/eui'; +import { act } from '@testing-library/react'; +import type { ReactWrapper } from 'enzyme'; import React from 'react'; import ReactMarkdown from 'react-markdown'; -import { act } from '@testing-library/react'; -import { EuiButton, EuiCallOut, EuiIcon } from '@elastic/eui'; -import { mountWithIntl, nextTick, shallowWithIntl } from '@kbn/test/jest'; -import { findTestSubject } from '@kbn/test/jest'; -import { LoginForm, PageMode } from './login_form'; -import { coreMock } from '../../../../../../../../src/core/public/mocks'; -import { ReactWrapper } from 'enzyme'; +import { findTestSubject, mountWithIntl, nextTick, shallowWithIntl } from '@kbn/test/jest'; +import { coreMock } from 'src/core/public/mocks'; + +import { LoginForm, PageMode } from './login_form'; function expectPageMode(wrapper: ReactWrapper, mode: PageMode) { const assertions: Array<[string, boolean]> = diff --git a/x-pack/plugins/security/public/authentication/login/components/login_form/login_form.tsx b/x-pack/plugins/security/public/authentication/login/components/login_form/login_form.tsx index d621e0c3ebd09..ca573ada36d22 100644 --- a/x-pack/plugins/security/public/authentication/login/components/login_form/login_form.tsx +++ b/x-pack/plugins/security/public/authentication/login/components/login_form/login_form.tsx @@ -7,29 +7,32 @@ import './login_form.scss'; -import React, { ChangeEvent, Component, FormEvent, Fragment, MouseEvent } from 'react'; -import ReactMarkdown from 'react-markdown'; import { EuiButton, - EuiIcon, + EuiButtonEmpty, EuiCallOut, EuiFieldPassword, EuiFieldText, + EuiFlexGroup, + EuiFlexItem, EuiFormRow, + EuiHorizontalRule, + EuiIcon, + EuiLink, + EuiLoadingSpinner, EuiPanel, EuiSpacer, EuiText, - EuiButtonEmpty, - EuiFlexGroup, - EuiFlexItem, EuiTitle, - EuiLoadingSpinner, - EuiLink, - EuiHorizontalRule, } from '@elastic/eui'; +import type { ChangeEvent, FormEvent, MouseEvent } from 'react'; +import React, { Component, Fragment } from 'react'; +import ReactMarkdown from 'react-markdown'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { HttpStart, IHttpFetchError, NotificationsStart } from 'src/core/public'; +import type { HttpStart, IHttpFetchError, NotificationsStart } from 'src/core/public'; + import type { LoginSelector, LoginSelectorProvider } from '../../../../../common/login_state'; import { LoginValidator } from './validate_login'; diff --git a/x-pack/plugins/security/public/authentication/login/components/login_form/validate_login.test.ts b/x-pack/plugins/security/public/authentication/login/components/login_form/validate_login.test.ts index ad1e487201d46..a4aa810c30e14 100644 --- a/x-pack/plugins/security/public/authentication/login/components/login_form/validate_login.test.ts +++ b/x-pack/plugins/security/public/authentication/login/components/login_form/validate_login.test.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { LoginValidator, LoginValidationResult } from './validate_login'; +import type { LoginValidationResult } from './validate_login'; +import { LoginValidator } from './validate_login'; function expectValid(result: LoginValidationResult) { expect(result.isInvalid).toBe(false); diff --git a/x-pack/plugins/security/public/authentication/login/login_app.test.ts b/x-pack/plugins/security/public/authentication/login/login_app.test.ts index 183132e147bcd..2ee759c99f740 100644 --- a/x-pack/plugins/security/public/authentication/login/login_app.test.ts +++ b/x-pack/plugins/security/public/authentication/login/login_app.test.ts @@ -7,10 +7,10 @@ jest.mock('./login_page'); -import { AppMount } from 'src/core/public'; -import { loginApp } from './login_app'; +import type { AppMount } from 'src/core/public'; +import { coreMock, scopedHistoryMock } from 'src/core/public/mocks'; -import { coreMock, scopedHistoryMock } from '../../../../../../src/core/public/mocks'; +import { loginApp } from './login_app'; describe('loginApp', () => { it('properly registers application', () => { diff --git a/x-pack/plugins/security/public/authentication/login/login_app.ts b/x-pack/plugins/security/public/authentication/login/login_app.ts index ccdaeb0feaaa5..21937e937ccf1 100644 --- a/x-pack/plugins/security/public/authentication/login/login_app.ts +++ b/x-pack/plugins/security/public/authentication/login/login_app.ts @@ -6,13 +6,14 @@ */ import { i18n } from '@kbn/i18n'; -import { - StartServicesAccessor, - AppMountParameters, +import type { ApplicationSetup, + AppMountParameters, HttpSetup, + StartServicesAccessor, } from 'src/core/public'; -import { ConfigType } from '../../config'; + +import type { ConfigType } from '../../config'; interface CreateDeps { application: ApplicationSetup; diff --git a/x-pack/plugins/security/public/authentication/login/login_page.test.tsx b/x-pack/plugins/security/public/authentication/login/login_page.test.tsx index 247fad2c8e441..a9596aff3bf0e 100644 --- a/x-pack/plugins/security/public/authentication/login/login_page.test.tsx +++ b/x-pack/plugins/security/public/authentication/login/login_page.test.tsx @@ -5,15 +5,17 @@ * 2.0. */ -import React from 'react'; -import { shallow } from 'enzyme'; import { act } from '@testing-library/react'; +import { shallow } from 'enzyme'; +import React from 'react'; + import { nextTick } from '@kbn/test/jest'; +import { coreMock } from 'src/core/public/mocks'; + import { AUTH_PROVIDER_HINT_QUERY_STRING_PARAMETER } from '../../../common/constants'; -import { LoginState } from '../../../common/login_state'; -import { LoginPage } from './login_page'; -import { coreMock } from '../../../../../../src/core/public/mocks'; +import type { LoginState } from '../../../common/login_state'; import { DisabledLoginForm, LoginForm } from './components'; +import { LoginPage } from './login_page'; const createLoginState = (options?: Partial) => { return { diff --git a/x-pack/plugins/security/public/authentication/login/login_page.tsx b/x-pack/plugins/security/public/authentication/login/login_page.tsx index 7dec637bbe577..562adec7918d3 100644 --- a/x-pack/plugins/security/public/authentication/login/login_page.tsx +++ b/x-pack/plugins/security/public/authentication/login/login_page.tsx @@ -7,21 +7,23 @@ import './login_page.scss'; +import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiSpacer, EuiTitle } from '@elastic/eui'; +import classNames from 'classnames'; import React, { Component } from 'react'; import ReactDOM from 'react-dom'; -import classNames from 'classnames'; import { BehaviorSubject } from 'rxjs'; import { parse } from 'url'; -import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiSpacer, EuiTitle } from '@elastic/eui'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { CoreStart, FatalErrorsStart, HttpStart, NotificationsStart } from 'src/core/public'; +import type { CoreStart, FatalErrorsStart, HttpStart, NotificationsStart } from 'src/core/public'; + import { AUTH_PROVIDER_HINT_QUERY_STRING_PARAMETER, LOGOUT_REASON_QUERY_STRING_PARAMETER, } from '../../../common/constants'; -import { LoginState } from '../../../common/login_state'; -import { LoginForm, DisabledLoginForm } from './components'; +import type { LoginState } from '../../../common/login_state'; +import { DisabledLoginForm, LoginForm } from './components'; interface Props { http: HttpStart; diff --git a/x-pack/plugins/security/public/authentication/logout/logout_app.test.ts b/x-pack/plugins/security/public/authentication/logout/logout_app.test.ts index 4b1dd087e5a65..8fcccdf916e93 100644 --- a/x-pack/plugins/security/public/authentication/logout/logout_app.test.ts +++ b/x-pack/plugins/security/public/authentication/logout/logout_app.test.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { AppMount } from 'src/core/public'; -import { logoutApp } from './logout_app'; +import type { AppMount } from 'src/core/public'; +import { coreMock, scopedHistoryMock } from 'src/core/public/mocks'; -import { coreMock, scopedHistoryMock } from '../../../../../../src/core/public/mocks'; +import { logoutApp } from './logout_app'; describe('logoutApp', () => { beforeAll(() => { diff --git a/x-pack/plugins/security/public/authentication/logout/logout_app.ts b/x-pack/plugins/security/public/authentication/logout/logout_app.ts index a9ab7b631d0d7..84fc510e96ced 100644 --- a/x-pack/plugins/security/public/authentication/logout/logout_app.ts +++ b/x-pack/plugins/security/public/authentication/logout/logout_app.ts @@ -6,7 +6,7 @@ */ import { i18n } from '@kbn/i18n'; -import { CoreSetup, HttpSetup } from 'src/core/public'; +import type { CoreSetup, HttpSetup } from 'src/core/public'; interface CreateDeps { application: CoreSetup['application']; diff --git a/x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_app.test.ts b/x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_app.test.ts index 211d9dd4f956b..9ea6293612968 100644 --- a/x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_app.test.ts +++ b/x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_app.test.ts @@ -7,11 +7,11 @@ jest.mock('./overwritten_session_page'); -import { AppMount } from 'src/core/public'; -import { overwrittenSessionApp } from './overwritten_session_app'; +import type { AppMount } from 'src/core/public'; +import { coreMock, scopedHistoryMock } from 'src/core/public/mocks'; -import { coreMock, scopedHistoryMock } from '../../../../../../src/core/public/mocks'; import { securityMock } from '../../mocks'; +import { overwrittenSessionApp } from './overwritten_session_app'; describe('overwrittenSessionApp', () => { it('properly registers application', () => { diff --git a/x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_app.ts b/x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_app.ts index b4d3e5da4eab0..715d732cd47e7 100644 --- a/x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_app.ts +++ b/x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_app.ts @@ -6,8 +6,9 @@ */ import { i18n } from '@kbn/i18n'; -import { StartServicesAccessor, ApplicationSetup, AppMountParameters } from 'src/core/public'; -import { AuthenticationServiceSetup } from '../authentication_service'; +import type { ApplicationSetup, AppMountParameters, StartServicesAccessor } from 'src/core/public'; + +import type { AuthenticationServiceSetup } from '../authentication_service'; interface CreateDeps { application: ApplicationSetup; diff --git a/x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_page.test.tsx b/x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_page.test.tsx index 962157431d6fe..42915e841b3a7 100644 --- a/x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_page.test.tsx +++ b/x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_page.test.tsx @@ -5,16 +5,17 @@ * 2.0. */ -import React from 'react'; import { EuiButton } from '@elastic/eui'; import { act } from '@testing-library/react'; +import React from 'react'; + import { mountWithIntl, nextTick } from '@kbn/test/jest'; -import { OverwrittenSessionPage } from './overwritten_session_page'; +import { coreMock } from 'src/core/public/mocks'; -import { coreMock } from '../../../../../../src/core/public/mocks'; -import { authenticationMock } from '../index.mock'; import { mockAuthenticatedUser } from '../../../common/model/authenticated_user.mock'; import { AuthenticationStatePage } from '../components/authentication_state_page'; +import { authenticationMock } from '../index.mock'; +import { OverwrittenSessionPage } from './overwritten_session_page'; describe('OverwrittenSessionPage', () => { beforeAll(() => { diff --git a/x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_page.tsx b/x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_page.tsx index c7127a69a38fb..4d9d62bb7c65f 100644 --- a/x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_page.tsx +++ b/x-pack/plugins/security/public/authentication/overwritten_session/overwritten_session_page.tsx @@ -5,13 +5,15 @@ * 2.0. */ +import { EuiButton } from '@elastic/eui'; import React, { useEffect, useState } from 'react'; import ReactDOM from 'react-dom'; -import { EuiButton } from '@elastic/eui'; + import { FormattedMessage } from '@kbn/i18n/react'; -import { CoreStart, IBasePath } from 'src/core/public'; +import type { CoreStart, IBasePath } from 'src/core/public'; + import { parseNext } from '../../../common/parse_next'; -import { AuthenticationServiceSetup } from '../authentication_service'; +import type { AuthenticationServiceSetup } from '../authentication_service'; import { AuthenticationStatePage } from '../components'; interface Props { diff --git a/x-pack/plugins/security/public/components/breadcrumb.tsx b/x-pack/plugins/security/public/components/breadcrumb.tsx index e713aecf46fd5..4462e2bce6abc 100644 --- a/x-pack/plugins/security/public/components/breadcrumb.tsx +++ b/x-pack/plugins/security/public/components/breadcrumb.tsx @@ -5,8 +5,10 @@ * 2.0. */ -import React, { createContext, useEffect, useRef, useContext, FunctionComponent } from 'react'; -import { EuiBreadcrumb } from '@elastic/eui'; +import type { EuiBreadcrumb } from '@elastic/eui'; +import type { FunctionComponent } from 'react'; +import React, { createContext, useContext, useEffect, useRef } from 'react'; + import { useKibana } from '../../../../../src/plugins/kibana_react/public'; interface BreadcrumbsContext { diff --git a/x-pack/plugins/security/public/components/confirm_modal.tsx b/x-pack/plugins/security/public/components/confirm_modal.tsx index 3802ee368d735..80c2008642d04 100644 --- a/x-pack/plugins/security/public/components/confirm_modal.tsx +++ b/x-pack/plugins/security/public/components/confirm_modal.tsx @@ -5,10 +5,9 @@ * 2.0. */ -import React, { FunctionComponent } from 'react'; +import type { EuiButtonProps, EuiModalProps } from '@elastic/eui'; import { EuiButton, - EuiButtonProps, EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, @@ -17,8 +16,10 @@ import { EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, - EuiModalProps, } from '@elastic/eui'; +import type { FunctionComponent } from 'react'; +import React from 'react'; + import { FormattedMessage } from '@kbn/i18n/react'; export interface ConfirmModalProps extends Omit { diff --git a/x-pack/plugins/security/public/components/doc_link.tsx b/x-pack/plugins/security/public/components/doc_link.tsx index 569fe559ea1f1..b19883f6e58d7 100644 --- a/x-pack/plugins/security/public/components/doc_link.tsx +++ b/x-pack/plugins/security/public/components/doc_link.tsx @@ -5,10 +5,13 @@ * 2.0. */ -import React, { useCallback, FunctionComponent } from 'react'; import { EuiLink } from '@elastic/eui'; +import type { FunctionComponent } from 'react'; +import React, { useCallback } from 'react'; + +import type { CoreStart } from 'src/core/public'; + import { useKibana } from '../../../../../src/plugins/kibana_react/public'; -import { CoreStart } from '../../../../../src/core/public'; export type DocLinks = CoreStart['docLinks']['links']; export type GetDocLinkFunction = (app: string, doc: string) => string; diff --git a/x-pack/plugins/security/public/components/form_flyout.tsx b/x-pack/plugins/security/public/components/form_flyout.tsx index ba440befba0be..2af210b339320 100644 --- a/x-pack/plugins/security/public/components/form_flyout.tsx +++ b/x-pack/plugins/security/public/components/form_flyout.tsx @@ -5,22 +5,24 @@ * 2.0. */ -import React, { useEffect, FunctionComponent, RefObject } from 'react'; -import { FormattedMessage } from '@kbn/i18n/react'; +import type { EuiButtonProps, EuiFlyoutProps } from '@elastic/eui'; import { - EuiTitle, + EuiButton, + EuiButtonEmpty, + EuiFlexGroup, + EuiFlexItem, EuiFlyout, - EuiFlyoutProps, - EuiFlyoutHeader, EuiFlyoutBody, EuiFlyoutFooter, - EuiFlexGroup, - EuiFlexItem, - EuiButton, - EuiButtonProps, - EuiButtonEmpty, + EuiFlyoutHeader, EuiPortal, + EuiTitle, } from '@elastic/eui'; +import type { FunctionComponent, RefObject } from 'react'; +import React, { useEffect } from 'react'; + +import { FormattedMessage } from '@kbn/i18n/react'; + import { useHtmlId } from './use_html_id'; export interface FormFlyoutProps extends Omit { diff --git a/x-pack/plugins/security/public/components/use_current_user.ts b/x-pack/plugins/security/public/components/use_current_user.ts index e4fd021245b08..103952d7d34ef 100644 --- a/x-pack/plugins/security/public/components/use_current_user.ts +++ b/x-pack/plugins/security/public/components/use_current_user.ts @@ -5,9 +5,10 @@ * 2.0. */ -import useAsync from 'react-use/lib/useAsync'; import constate from 'constate'; -import { AuthenticationServiceSetup } from '../authentication'; +import useAsync from 'react-use/lib/useAsync'; + +import type { AuthenticationServiceSetup } from '../authentication'; export interface AuthenticationProviderProps { authc: AuthenticationServiceSetup; diff --git a/x-pack/plugins/security/public/components/use_form.ts b/x-pack/plugins/security/public/components/use_form.ts index 8be332466ee29..2b42fda5ba561 100644 --- a/x-pack/plugins/security/public/components/use_form.ts +++ b/x-pack/plugins/security/public/components/use_form.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { ChangeEventHandler, FocusEventHandler, ReactEventHandler, useState } from 'react'; -import { get, set, cloneDeep, cloneDeepWith } from 'lodash'; +import { cloneDeep, cloneDeepWith, get, set } from 'lodash'; +import type { ChangeEventHandler, FocusEventHandler, ReactEventHandler } from 'react'; +import { useState } from 'react'; import useAsyncFn from 'react-use/lib/useAsyncFn'; export type FormReturnTuple = [FormState, FormProps]; diff --git a/x-pack/plugins/security/public/components/use_html_id.ts b/x-pack/plugins/security/public/components/use_html_id.ts index d31e01c822b89..97f56becbbdd6 100644 --- a/x-pack/plugins/security/public/components/use_html_id.ts +++ b/x-pack/plugins/security/public/components/use_html_id.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { useMemo } from 'react'; import { htmlIdGenerator } from '@elastic/eui'; +import { useMemo } from 'react'; /** * Generates an ID that can be used for HTML elements. diff --git a/x-pack/plugins/security/public/index.ts b/x-pack/plugins/security/public/index.ts index 5d508fb9e9a43..df074ab616369 100644 --- a/x-pack/plugins/security/public/index.ts +++ b/x-pack/plugins/security/public/index.ts @@ -5,14 +5,10 @@ * 2.0. */ -import { PluginInitializer, PluginInitializerContext } from 'src/core/public'; -import { - SecurityPlugin, - SecurityPluginSetup, - SecurityPluginStart, - PluginSetupDependencies, - PluginStartDependencies, -} from './plugin'; +import type { PluginInitializer, PluginInitializerContext } from 'src/core/public'; + +import type { PluginSetupDependencies, PluginStartDependencies } from './plugin'; +import { SecurityPlugin, SecurityPluginSetup, SecurityPluginStart } from './plugin'; export { SecurityPluginSetup, SecurityPluginStart }; export { AuthenticatedUser } from '../common/model'; diff --git a/x-pack/plugins/security/public/management/api_keys/api_keys_api_client.test.ts b/x-pack/plugins/security/public/management/api_keys/api_keys_api_client.test.ts index 1d1fc2b1afc2d..8c79ee5bb0be5 100644 --- a/x-pack/plugins/security/public/management/api_keys/api_keys_api_client.test.ts +++ b/x-pack/plugins/security/public/management/api_keys/api_keys_api_client.test.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { APIKeysAPIClient } from './api_keys_api_client'; +import { httpServiceMock } from 'src/core/public/mocks'; -import { httpServiceMock } from '../../../../../../src/core/public/mocks'; +import { APIKeysAPIClient } from './api_keys_api_client'; describe('APIKeysAPIClient', () => { it('checkPrivileges() queries correct endpoint', async () => { diff --git a/x-pack/plugins/security/public/management/api_keys/api_keys_api_client.ts b/x-pack/plugins/security/public/management/api_keys/api_keys_api_client.ts index 52ec2eb68082e..318837f091327 100644 --- a/x-pack/plugins/security/public/management/api_keys/api_keys_api_client.ts +++ b/x-pack/plugins/security/public/management/api_keys/api_keys_api_client.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { HttpStart } from 'src/core/public'; -import { ApiKey, ApiKeyToInvalidate } from '../../../common/model'; +import type { HttpStart } from 'src/core/public'; + +import type { ApiKey, ApiKeyToInvalidate } from '../../../common/model'; interface CheckPrivilegesResponse { areApiKeysEnabled: boolean; diff --git a/x-pack/plugins/security/public/management/api_keys/api_keys_grid/api_keys_grid_page.test.tsx b/x-pack/plugins/security/public/management/api_keys/api_keys_grid/api_keys_grid_page.test.tsx index b1e71322e4d3c..ff9fbad5c05b5 100644 --- a/x-pack/plugins/security/public/management/api_keys/api_keys_grid/api_keys_grid_page.test.tsx +++ b/x-pack/plugins/security/public/management/api_keys/api_keys_grid/api_keys_grid_page.test.tsx @@ -5,20 +5,20 @@ * 2.0. */ -import { mountWithIntl } from '@kbn/test/jest'; -import React from 'react'; -import { ReactWrapper } from 'enzyme'; import { EuiCallOut } from '@elastic/eui'; +import type { ReactWrapper } from 'enzyme'; +import React from 'react'; + +import { mountWithIntl } from '@kbn/test/jest'; import type { PublicMethodsOf } from '@kbn/utility-types'; +import { coreMock } from 'src/core/public/mocks'; +import { KibanaContextProvider } from 'src/plugins/kibana_react/public'; -import { KibanaContextProvider } from '../../../../../../../src/plugins/kibana_react/public'; +import type { APIKeysAPIClient } from '../api_keys_api_client'; +import { apiKeysAPIClientMock } from '../index.mock'; +import { APIKeysGridPage } from './api_keys_grid_page'; import { NotEnabled } from './not_enabled'; import { PermissionDenied } from './permission_denied'; -import { APIKeysAPIClient } from '../api_keys_api_client'; -import { APIKeysGridPage } from './api_keys_grid_page'; - -import { coreMock } from '../../../../../../../src/core/public/mocks'; -import { apiKeysAPIClientMock } from '../index.mock'; const mock500 = () => ({ body: { error: 'Internal Server Error', message: '', statusCode: 500 } }); diff --git a/x-pack/plugins/security/public/management/api_keys/api_keys_grid/api_keys_grid_page.tsx b/x-pack/plugins/security/public/management/api_keys/api_keys_grid/api_keys_grid_page.tsx index 8992e75389fd8..62ca51be2ede8 100644 --- a/x-pack/plugins/security/public/management/api_keys/api_keys_grid/api_keys_grid_page.tsx +++ b/x-pack/plugins/security/public/management/api_keys/api_keys_grid/api_keys_grid_page.tsx @@ -5,10 +5,9 @@ * 2.0. */ -import React, { Component } from 'react'; +import type { EuiBasicTableColumn, EuiInMemoryTableProps } from '@elastic/eui'; import { EuiBadge, - EuiBasicTableColumn, EuiButton, EuiButtonIcon, EuiCallOut, @@ -23,20 +22,22 @@ import { EuiText, EuiTitle, EuiToolTip, - EuiInMemoryTableProps, } from '@elastic/eui'; +import moment from 'moment-timezone'; +import React, { Component } from 'react'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import type { PublicMethodsOf } from '@kbn/utility-types'; -import moment from 'moment-timezone'; import type { NotificationsStart } from 'src/core/public'; + import { SectionLoading } from '../../../../../../../src/plugins/es_ui_shared/public'; -import { ApiKey, ApiKeyToInvalidate } from '../../../../common/model'; -import { APIKeysAPIClient } from '../api_keys_api_client'; -import { PermissionDenied } from './permission_denied'; +import type { ApiKey, ApiKeyToInvalidate } from '../../../../common/model'; +import type { APIKeysAPIClient } from '../api_keys_api_client'; import { EmptyPrompt } from './empty_prompt'; -import { NotEnabled } from './not_enabled'; import { InvalidateProvider } from './invalidate_provider'; +import { NotEnabled } from './not_enabled'; +import { PermissionDenied } from './permission_denied'; interface Props { notifications: NotificationsStart; diff --git a/x-pack/plugins/security/public/management/api_keys/api_keys_grid/empty_prompt/empty_prompt.tsx b/x-pack/plugins/security/public/management/api_keys/api_keys_grid/empty_prompt/empty_prompt.tsx index 627717a20ee0b..0987f43a3d14d 100644 --- a/x-pack/plugins/security/public/management/api_keys/api_keys_grid/empty_prompt/empty_prompt.tsx +++ b/x-pack/plugins/security/public/management/api_keys/api_keys_grid/empty_prompt/empty_prompt.tsx @@ -5,10 +5,11 @@ * 2.0. */ +import { EuiButton, EuiEmptyPrompt, EuiLink } from '@elastic/eui'; import React, { Fragment } from 'react'; -import { EuiEmptyPrompt, EuiButton, EuiLink } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; + import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public'; interface Props { diff --git a/x-pack/plugins/security/public/management/api_keys/api_keys_grid/invalidate_provider/invalidate_provider.tsx b/x-pack/plugins/security/public/management/api_keys/api_keys_grid/invalidate_provider/invalidate_provider.tsx index 232847b63cb1a..a68534db4fd85 100644 --- a/x-pack/plugins/security/public/management/api_keys/api_keys_grid/invalidate_provider/invalidate_provider.tsx +++ b/x-pack/plugins/security/public/management/api_keys/api_keys_grid/invalidate_provider/invalidate_provider.tsx @@ -5,13 +5,15 @@ * 2.0. */ -import React, { Fragment, useRef, useState } from 'react'; import { EuiConfirmModal } from '@elastic/eui'; -import type { PublicMethodsOf } from '@kbn/utility-types'; +import React, { Fragment, useRef, useState } from 'react'; + import { i18n } from '@kbn/i18n'; -import { NotificationsStart } from 'src/core/public'; -import { ApiKeyToInvalidate } from '../../../../../common/model'; -import { APIKeysAPIClient } from '../../api_keys_api_client'; +import type { PublicMethodsOf } from '@kbn/utility-types'; +import type { NotificationsStart } from 'src/core/public'; + +import type { ApiKeyToInvalidate } from '../../../../../common/model'; +import type { APIKeysAPIClient } from '../../api_keys_api_client'; interface Props { isAdmin: boolean; diff --git a/x-pack/plugins/security/public/management/api_keys/api_keys_grid/not_enabled/not_enabled.tsx b/x-pack/plugins/security/public/management/api_keys/api_keys_grid/not_enabled/not_enabled.tsx index 5da06d514bb24..cd74c0de4dfcf 100644 --- a/x-pack/plugins/security/public/management/api_keys/api_keys_grid/not_enabled/not_enabled.tsx +++ b/x-pack/plugins/security/public/management/api_keys/api_keys_grid/not_enabled/not_enabled.tsx @@ -5,9 +5,11 @@ * 2.0. */ -import React from 'react'; import { EuiCallOut, EuiLink } from '@elastic/eui'; +import React from 'react'; + import { FormattedMessage } from '@kbn/i18n/react'; + import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public'; export const NotEnabled: React.FunctionComponent = () => { diff --git a/x-pack/plugins/security/public/management/api_keys/api_keys_grid/permission_denied/permission_denied.tsx b/x-pack/plugins/security/public/management/api_keys/api_keys_grid/permission_denied/permission_denied.tsx index 9d94ab117fbce..de97de0516e20 100644 --- a/x-pack/plugins/security/public/management/api_keys/api_keys_grid/permission_denied/permission_denied.tsx +++ b/x-pack/plugins/security/public/management/api_keys/api_keys_grid/permission_denied/permission_denied.tsx @@ -6,9 +6,10 @@ */ import { EuiEmptyPrompt, EuiFlexGroup, EuiPageContent } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; import React from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; + export const PermissionDenied = () => ( diff --git a/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.test.tsx b/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.test.tsx index 1606dc7af7c5b..bada8c5c7ce4c 100644 --- a/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.test.tsx +++ b/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.test.tsx @@ -8,8 +8,9 @@ jest.mock('./api_keys_grid', () => ({ APIKeysGridPage: (props: any) => `Page: ${JSON.stringify(props)}`, })); +import { coreMock, scopedHistoryMock } from 'src/core/public/mocks'; + import { apiKeysManagementApp } from './api_keys_management_app'; -import { coreMock, scopedHistoryMock } from '../../../../../../src/core/public/mocks'; describe('apiKeysManagementApp', () => { it('create() returns proper management app descriptor', () => { diff --git a/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.tsx b/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.tsx index 45d00ecec124d..8fa52ba7e2edd 100644 --- a/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.tsx +++ b/x-pack/plugins/security/public/management/api_keys/api_keys_management_app.tsx @@ -7,11 +7,13 @@ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; + import { i18n } from '@kbn/i18n'; -import { StartServicesAccessor } from 'src/core/public'; -import { RegisterManagementAppArgs } from '../../../../../../src/plugins/management/public'; +import type { StartServicesAccessor } from 'src/core/public'; +import type { RegisterManagementAppArgs } from 'src/plugins/management/public'; + import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; -import { PluginStartDependencies } from '../../plugin'; +import type { PluginStartDependencies } from '../../plugin'; interface CreateParams { getStartServices: StartServicesAccessor; diff --git a/x-pack/plugins/security/public/management/badges/deprecated_badge.tsx b/x-pack/plugins/security/public/management/badges/deprecated_badge.tsx index c60bd5f8b1b39..471f4f1f9b31b 100644 --- a/x-pack/plugins/security/public/management/badges/deprecated_badge.tsx +++ b/x-pack/plugins/security/public/management/badges/deprecated_badge.tsx @@ -5,9 +5,12 @@ * 2.0. */ +import type { EuiToolTipProps } from '@elastic/eui'; +import { EuiBadge } from '@elastic/eui'; import React from 'react'; + import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiBadge, EuiToolTipProps } from '@elastic/eui'; + import { OptionalToolTip } from './optional_tooltip'; interface Props { diff --git a/x-pack/plugins/security/public/management/badges/disabled_badge.tsx b/x-pack/plugins/security/public/management/badges/disabled_badge.tsx index f9612e9d2bb30..133baa3a6b2f1 100644 --- a/x-pack/plugins/security/public/management/badges/disabled_badge.tsx +++ b/x-pack/plugins/security/public/management/badges/disabled_badge.tsx @@ -5,9 +5,12 @@ * 2.0. */ +import type { EuiToolTipProps } from '@elastic/eui'; +import { EuiBadge } from '@elastic/eui'; import React from 'react'; + import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiBadge, EuiToolTipProps } from '@elastic/eui'; + import { OptionalToolTip } from './optional_tooltip'; interface Props { diff --git a/x-pack/plugins/security/public/management/badges/enabled_badge.tsx b/x-pack/plugins/security/public/management/badges/enabled_badge.tsx index 0f7f74a7b38f8..f55914997c72e 100644 --- a/x-pack/plugins/security/public/management/badges/enabled_badge.tsx +++ b/x-pack/plugins/security/public/management/badges/enabled_badge.tsx @@ -5,9 +5,12 @@ * 2.0. */ +import type { EuiToolTipProps } from '@elastic/eui'; +import { EuiBadge } from '@elastic/eui'; import React from 'react'; + import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiBadge, EuiToolTipProps } from '@elastic/eui'; + import { OptionalToolTip } from './optional_tooltip'; interface Props { diff --git a/x-pack/plugins/security/public/management/badges/optional_tooltip.tsx b/x-pack/plugins/security/public/management/badges/optional_tooltip.tsx index 060560587eac2..9e53e50a45910 100644 --- a/x-pack/plugins/security/public/management/badges/optional_tooltip.tsx +++ b/x-pack/plugins/security/public/management/badges/optional_tooltip.tsx @@ -5,8 +5,10 @@ * 2.0. */ -import React, { ReactElement } from 'react'; -import { EuiToolTipProps, EuiToolTip } from '@elastic/eui'; +import type { EuiToolTipProps } from '@elastic/eui'; +import { EuiToolTip } from '@elastic/eui'; +import type { ReactElement } from 'react'; +import React from 'react'; interface Props { children: ReactElement; diff --git a/x-pack/plugins/security/public/management/badges/reserved_badge.tsx b/x-pack/plugins/security/public/management/badges/reserved_badge.tsx index 5b09f88c6151d..9ad0c718a5612 100644 --- a/x-pack/plugins/security/public/management/badges/reserved_badge.tsx +++ b/x-pack/plugins/security/public/management/badges/reserved_badge.tsx @@ -5,9 +5,12 @@ * 2.0. */ +import type { EuiToolTipProps } from '@elastic/eui'; +import { EuiBadge } from '@elastic/eui'; import React from 'react'; + import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiBadge, EuiToolTipProps } from '@elastic/eui'; + import { OptionalToolTip } from './optional_tooltip'; interface Props { diff --git a/x-pack/plugins/security/public/management/management_service.test.ts b/x-pack/plugins/security/public/management/management_service.test.ts index 9b316993a37f0..694f3cc3880a2 100644 --- a/x-pack/plugins/security/public/management/management_service.test.ts +++ b/x-pack/plugins/security/public/management/management_service.test.ts @@ -6,22 +6,23 @@ */ import { BehaviorSubject } from 'rxjs'; -import { + +import { coreMock } from 'src/core/public/mocks'; +import type { + DefinedSections, ManagementApp, ManagementSetup, - DefinedSections, -} from '../../../../../src/plugins/management/public'; -import { createManagementSectionMock } from '../../../../../src/plugins/management/public/mocks'; -import { SecurityLicenseFeatures } from '../../common/licensing/license_features'; -import { ManagementService } from './management_service'; -import { usersManagementApp } from './users'; +} from 'src/plugins/management/public'; +import { createManagementSectionMock } from 'src/plugins/management/public/mocks'; -import { coreMock } from '../../../../../src/core/public/mocks'; import { licenseMock } from '../../common/licensing/index.mock'; +import type { SecurityLicenseFeatures } from '../../common/licensing/license_features'; import { securityMock } from '../mocks'; -import { rolesManagementApp } from './roles'; import { apiKeysManagementApp } from './api_keys'; +import { ManagementService } from './management_service'; import { roleMappingsManagementApp } from './role_mappings'; +import { rolesManagementApp } from './roles'; +import { usersManagementApp } from './users'; const mockSection = createManagementSectionMock(); diff --git a/x-pack/plugins/security/public/management/management_service.ts b/x-pack/plugins/security/public/management/management_service.ts index 2600e15ad1359..7809a45db1660 100644 --- a/x-pack/plugins/security/public/management/management_service.ts +++ b/x-pack/plugins/security/public/management/management_service.ts @@ -5,16 +5,18 @@ * 2.0. */ -import { Subscription } from 'rxjs'; -import { StartServicesAccessor, FatalErrorsSetup, Capabilities } from 'src/core/public'; -import { +import type { Subscription } from 'rxjs'; + +import type { Capabilities, FatalErrorsSetup, StartServicesAccessor } from 'src/core/public'; +import type { ManagementApp, - ManagementSetup, ManagementSection, -} from '../../../../../src/plugins/management/public'; -import { SecurityLicense } from '../../common/licensing'; -import { AuthenticationServiceSetup } from '../authentication'; -import { PluginStartDependencies } from '../plugin'; + ManagementSetup, +} from 'src/plugins/management/public'; + +import type { SecurityLicense } from '../../common/licensing'; +import type { AuthenticationServiceSetup } from '../authentication'; +import type { PluginStartDependencies } from '../plugin'; import { apiKeysManagementApp } from './api_keys'; import { roleMappingsManagementApp } from './role_mappings'; import { rolesManagementApp } from './roles'; diff --git a/x-pack/plugins/security/public/management/role_combo_box/role_combo_box.test.tsx b/x-pack/plugins/security/public/management/role_combo_box/role_combo_box.test.tsx index 06a76cbf0b43e..3abcc07042e82 100644 --- a/x-pack/plugins/security/public/management/role_combo_box/role_combo_box.test.tsx +++ b/x-pack/plugins/security/public/management/role_combo_box/role_combo_box.test.tsx @@ -6,8 +6,10 @@ */ import React from 'react'; + import { shallowWithIntl } from '@kbn/test/jest'; -import { RoleComboBox } from '.'; + +import { RoleComboBox } from './role_combo_box'; describe('RoleComboBox', () => { it('renders roles grouped by custom, user, admin, system and deprecated roles with correct color', () => { diff --git a/x-pack/plugins/security/public/management/role_combo_box/role_combo_box.tsx b/x-pack/plugins/security/public/management/role_combo_box/role_combo_box.tsx index 84a02c6ab10ed..f894d59ce30c0 100644 --- a/x-pack/plugins/security/public/management/role_combo_box/role_combo_box.tsx +++ b/x-pack/plugins/security/public/management/role_combo_box/role_combo_box.tsx @@ -5,24 +5,15 @@ * 2.0. */ +import type { EuiComboBoxOptionOption, EuiComboBoxProps } from '@elastic/eui'; +import { EuiBadge, EuiComboBox, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React from 'react'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { - EuiBadge, - EuiComboBox, - EuiComboBoxProps, - EuiComboBoxOptionOption, - EuiFlexGroup, - EuiFlexItem, -} from '@elastic/eui'; -import { - Role, - isRoleSystem, - isRoleAdmin, - isRoleReserved, - isRoleDeprecated, -} from '../../../common/model'; + +import type { Role } from '../../../common/model'; +import { isRoleAdmin, isRoleDeprecated, isRoleReserved, isRoleSystem } from '../../../common/model'; interface Props extends Omit< diff --git a/x-pack/plugins/security/public/management/role_mappings/components/delete_provider/delete_provider.test.tsx b/x-pack/plugins/security/public/management/role_mappings/components/delete_provider/delete_provider.test.tsx index b2c7859404c96..17a6fb0bb84b3 100644 --- a/x-pack/plugins/security/public/management/role_mappings/components/delete_provider/delete_provider.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/components/delete_provider/delete_provider.test.tsx @@ -5,16 +5,16 @@ * 2.0. */ -import React from 'react'; import { EuiConfirmModal } from '@elastic/eui'; import { act } from '@testing-library/react'; -import { mountWithIntl, nextTick } from '@kbn/test/jest'; -import { findTestSubject } from '@kbn/test/jest'; -import { RoleMapping } from '../../../../../common/model'; -import { DeleteProvider } from '.'; +import React from 'react'; + +import { findTestSubject, mountWithIntl, nextTick } from '@kbn/test/jest'; +import { coreMock } from 'src/core/public/mocks'; +import type { RoleMapping } from '../../../../../common/model'; import { roleMappingsAPIClientMock } from '../../index.mock'; -import { coreMock } from '../../../../../../../../src/core/public/mocks'; +import { DeleteProvider } from './delete_provider'; describe('DeleteProvider', () => { beforeEach(() => { diff --git a/x-pack/plugins/security/public/management/role_mappings/components/delete_provider/delete_provider.tsx b/x-pack/plugins/security/public/management/role_mappings/components/delete_provider/delete_provider.tsx index 680a4a40a7d9a..f9194860ddded 100644 --- a/x-pack/plugins/security/public/management/role_mappings/components/delete_provider/delete_provider.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/components/delete_provider/delete_provider.tsx @@ -5,13 +5,16 @@ * 2.0. */ -import React, { Fragment, useRef, useState, ReactElement } from 'react'; import { EuiConfirmModal } from '@elastic/eui'; +import type { ReactElement } from 'react'; +import React, { Fragment, useRef, useState } from 'react'; + import { i18n } from '@kbn/i18n'; import type { PublicMethodsOf } from '@kbn/utility-types'; -import { NotificationsStart } from 'src/core/public'; -import { RoleMapping } from '../../../../../common/model'; -import { RoleMappingsAPIClient } from '../../role_mappings_api_client'; +import type { NotificationsStart } from 'src/core/public'; + +import type { RoleMapping } from '../../../../../common/model'; +import type { RoleMappingsAPIClient } from '../../role_mappings_api_client'; interface Props { roleMappingsAPI: PublicMethodsOf; diff --git a/x-pack/plugins/security/public/management/role_mappings/components/no_compatible_realms/no_compatible_realms.tsx b/x-pack/plugins/security/public/management/role_mappings/components/no_compatible_realms/no_compatible_realms.tsx index c71ac9443d0e0..facf543601d7d 100644 --- a/x-pack/plugins/security/public/management/role_mappings/components/no_compatible_realms/no_compatible_realms.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/components/no_compatible_realms/no_compatible_realms.tsx @@ -5,9 +5,11 @@ * 2.0. */ -import React from 'react'; import { EuiCallOut, EuiLink } from '@elastic/eui'; +import React from 'react'; + import { FormattedMessage } from '@kbn/i18n/react'; + import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public'; export const NoCompatibleRealms: React.FunctionComponent = () => { diff --git a/x-pack/plugins/security/public/management/role_mappings/components/permission_denied/permission_denied.tsx b/x-pack/plugins/security/public/management/role_mappings/components/permission_denied/permission_denied.tsx index 51001bb88731a..65af6482a0b82 100644 --- a/x-pack/plugins/security/public/management/role_mappings/components/permission_denied/permission_denied.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/components/permission_denied/permission_denied.tsx @@ -6,9 +6,10 @@ */ import { EuiEmptyPrompt, EuiFlexGroup, EuiPageContent } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; import React from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; + export const PermissionDenied = () => ( diff --git a/x-pack/plugins/security/public/management/role_mappings/components/section_loading/section_loading.test.tsx b/x-pack/plugins/security/public/management/role_mappings/components/section_loading/section_loading.test.tsx index 5c06640ed1aff..e3e5929428164 100644 --- a/x-pack/plugins/security/public/management/role_mappings/components/section_loading/section_loading.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/components/section_loading/section_loading.test.tsx @@ -6,8 +6,10 @@ */ import React from 'react'; + import { shallowWithIntl } from '@kbn/test/jest'; -import { SectionLoading } from '.'; + +import { SectionLoading } from './section_loading'; describe('SectionLoading', () => { it('renders the default loading message', () => { diff --git a/x-pack/plugins/security/public/management/role_mappings/components/section_loading/section_loading.tsx b/x-pack/plugins/security/public/management/role_mappings/components/section_loading/section_loading.tsx index e3c3c4c074b29..3624f098ea65d 100644 --- a/x-pack/plugins/security/public/management/role_mappings/components/section_loading/section_loading.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/components/section_loading/section_loading.tsx @@ -5,8 +5,9 @@ * 2.0. */ -import React from 'react'; import { EuiEmptyPrompt, EuiLoadingSpinner, EuiText } from '@elastic/eui'; +import React from 'react'; + import { FormattedMessage } from '@kbn/i18n/react'; interface Props { diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/edit_role_mapping_page.test.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/edit_role_mapping_page.test.tsx index 28dc316d2d588..c0486ee7d0d82 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/edit_role_mapping_page.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/edit_role_mapping_page.test.tsx @@ -5,28 +5,27 @@ * 2.0. */ -import React from 'react'; -import type { PublicMethodsOf } from '@kbn/utility-types'; -import { mountWithIntl, nextTick } from '@kbn/test/jest'; -import { findTestSubject } from '@kbn/test/jest'; - // brace/ace uses the Worker class, which is not currently provided by JSDOM. // This is not required for the tests to pass, but it rather suppresses lengthy // warnings in the console which adds unnecessary noise to the test output. import '@kbn/test/target/jest/utils/stub_web_worker'; -import { EditRoleMappingPage } from '.'; -import { NoCompatibleRealms, SectionLoading, PermissionDenied } from '../components'; -import { VisualRuleEditor } from './rule_editor_panel/visual_rule_editor'; -import { JSONRuleEditor } from './rule_editor_panel/json_rule_editor'; -import { RolesAPIClient } from '../../roles'; -import { Role } from '../../../../common/model'; -import { KibanaContextProvider } from '../../../../../../../src/plugins/kibana_react/public'; +import React from 'react'; -import { coreMock, scopedHistoryMock } from '../../../../../../../src/core/public/mocks'; -import { roleMappingsAPIClientMock } from '../role_mappings_api_client.mock'; -import { rolesAPIClientMock } from '../../roles/roles_api_client.mock'; +import { findTestSubject, mountWithIntl, nextTick } from '@kbn/test/jest'; +import type { PublicMethodsOf } from '@kbn/utility-types'; +import { coreMock, scopedHistoryMock } from 'src/core/public/mocks'; +import { KibanaContextProvider } from 'src/plugins/kibana_react/public'; + +import type { Role } from '../../../../common/model'; import { RoleComboBox } from '../../role_combo_box'; +import type { RolesAPIClient } from '../../roles'; +import { rolesAPIClientMock } from '../../roles/roles_api_client.mock'; +import { NoCompatibleRealms, PermissionDenied, SectionLoading } from '../components'; +import { roleMappingsAPIClientMock } from '../role_mappings_api_client.mock'; +import { EditRoleMappingPage } from './edit_role_mapping_page'; +import { JSONRuleEditor } from './rule_editor_panel/json_rule_editor'; +import { VisualRuleEditor } from './rule_editor_panel/visual_rule_editor'; describe('EditRoleMappingPage', () => { const history = scopedHistoryMock.create(); diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/edit_role_mapping_page.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/edit_role_mapping_page.tsx index 73e231de3e05d..4f238f819f320 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/edit_role_mapping_page.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/edit_role_mapping_page.tsx @@ -5,35 +5,37 @@ * 2.0. */ -import React, { Component, Fragment } from 'react'; import { + EuiButton, + EuiButtonEmpty, + EuiFlexGroup, + EuiFlexItem, EuiForm, + EuiLink, EuiPageContent, EuiSpacer, EuiText, EuiTitle, - EuiFlexGroup, - EuiFlexItem, - EuiButtonEmpty, - EuiButton, - EuiLink, } from '@elastic/eui'; +import React, { Component, Fragment } from 'react'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import type { PublicMethodsOf } from '@kbn/utility-types'; -import type { NotificationsStart, ScopedHistory, DocLinksStart } from 'src/core/public'; -import { RoleMapping } from '../../../../common/model'; -import { RuleEditorPanel } from './rule_editor_panel'; +import type { DocLinksStart, NotificationsStart, ScopedHistory } from 'src/core/public'; + +import type { RoleMapping } from '../../../../common/model'; +import type { RolesAPIClient } from '../../roles'; import { + DeleteProvider, NoCompatibleRealms, PermissionDenied, - DeleteProvider, SectionLoading, } from '../components'; -import { RolesAPIClient } from '../../roles'; -import { validateRoleMappingForSave } from './services/role_mapping_validation'; +import type { RoleMappingsAPIClient } from '../role_mappings_api_client'; import { MappingInfoPanel } from './mapping_info_panel'; -import { RoleMappingsAPIClient } from '../role_mappings_api_client'; +import { RuleEditorPanel } from './rule_editor_panel'; +import { validateRoleMappingForSave } from './services/role_mapping_validation'; interface State { loadState: 'loading' | 'permissionDenied' | 'ready' | 'saveInProgress'; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/mapping_info_panel/mapping_info_panel.test.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/mapping_info_panel/mapping_info_panel.test.tsx index 8f1f57a123000..3e18437a52ece 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/mapping_info_panel/mapping_info_panel.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/mapping_info_panel/mapping_info_panel.test.tsx @@ -6,17 +6,17 @@ */ import React from 'react'; + +import { findTestSubject, mountWithIntl } from '@kbn/test/jest'; import type { PublicMethodsOf } from '@kbn/utility-types'; -import { mountWithIntl } from '@kbn/test/jest'; -import { findTestSubject } from '@kbn/test/jest'; -import { Role, RoleMapping } from '../../../../../common/model'; -import { RolesAPIClient } from '../../../roles'; -import { RoleSelector } from '../role_selector'; -import { RoleTemplateEditor } from '../role_selector/role_template_editor'; -import { MappingInfoPanel } from '.'; +import { coreMock } from 'src/core/public/mocks'; +import type { Role, RoleMapping } from '../../../../../common/model'; +import type { RolesAPIClient } from '../../../roles'; import { rolesAPIClientMock } from '../../../roles/roles_api_client.mock'; -import { coreMock } from '../../../../../../../../src/core/public/mocks'; +import { RoleSelector } from '../role_selector'; +import { RoleTemplateEditor } from '../role_selector/role_template_editor'; +import { MappingInfoPanel } from './mapping_info_panel'; describe('MappingInfoPanel', () => { let rolesAPI: PublicMethodsOf; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/mapping_info_panel/mapping_info_panel.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/mapping_info_panel/mapping_info_panel.tsx index 228047b7bb776..3eb935e152f33 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/mapping_info_panel/mapping_info_panel.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/mapping_info_panel/mapping_info_panel.tsx @@ -5,31 +5,34 @@ * 2.0. */ -import React, { Component, ChangeEvent, Fragment } from 'react'; import { - EuiPanel, - EuiTitle, - EuiText, - EuiSpacer, EuiDescribedFormGroup, - EuiFormRow, EuiFieldText, - EuiLink, + EuiFormRow, EuiIcon, + EuiLink, + EuiPanel, + EuiSpacer, EuiSwitch, + EuiText, + EuiTitle, } from '@elastic/eui'; +import type { ChangeEvent } from 'react'; +import React, { Component, Fragment } from 'react'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import type { PublicMethodsOf } from '@kbn/utility-types'; import type { DocLinksStart } from 'src/core/public'; -import { RoleMapping } from '../../../../../common/model'; -import { RolesAPIClient } from '../../../roles'; + +import type { RoleMapping } from '../../../../../common/model'; +import type { RolesAPIClient } from '../../../roles'; +import { RoleSelector } from '../role_selector'; import { validateRoleMappingName, validateRoleMappingRoles, validateRoleMappingRoleTemplates, } from '../services/role_mapping_validation'; -import { RoleSelector } from '../role_selector'; interface Props { roleMapping: RoleMapping; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/add_role_template_button.test.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/add_role_template_button.test.tsx index 0688b9d307e61..a82b089f6630e 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/add_role_template_button.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/add_role_template_button.test.tsx @@ -6,7 +6,9 @@ */ import React from 'react'; -import { shallowWithIntl, mountWithIntl } from '@kbn/test/jest'; + +import { mountWithIntl, shallowWithIntl } from '@kbn/test/jest'; + import { AddRoleTemplateButton } from './add_role_template_button'; describe('AddRoleTemplateButton', () => { diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/add_role_template_button.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/add_role_template_button.tsx index 4e439b0f27721..c1649d437007f 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/add_role_template_button.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/add_role_template_button.tsx @@ -5,8 +5,9 @@ * 2.0. */ -import React from 'react'; import { EuiButtonEmpty, EuiCallOut } from '@elastic/eui'; +import React from 'react'; + import { FormattedMessage } from '@kbn/i18n/react'; interface Props { diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_selector.test.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_selector.test.tsx index 4b4e91f0a622c..367fdaadca96e 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_selector.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_selector.test.tsx @@ -5,17 +5,18 @@ * 2.0. */ -import React from 'react'; -import { mountWithIntl } from '@kbn/test/jest'; -import { findTestSubject } from '@kbn/test/jest'; import { EuiComboBox } from '@elastic/eui'; +import React from 'react'; + +import { findTestSubject, mountWithIntl } from '@kbn/test/jest'; import type { PublicMethodsOf } from '@kbn/utility-types'; + +import type { Role, RoleMapping } from '../../../../../common/model'; +import type { RolesAPIClient } from '../../../roles'; +import { rolesAPIClientMock } from '../../../roles/roles_api_client.mock'; +import { AddRoleTemplateButton } from './add_role_template_button'; import { RoleSelector } from './role_selector'; -import { Role, RoleMapping } from '../../../../../common/model'; import { RoleTemplateEditor } from './role_template_editor'; -import { AddRoleTemplateButton } from './add_role_template_button'; -import { RolesAPIClient } from '../../../roles'; -import { rolesAPIClientMock } from '../../../roles/roles_api_client.mock'; describe('RoleSelector', () => { let rolesAPI: PublicMethodsOf; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_selector.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_selector.tsx index b28b6f4ecac0c..e40edd880af09 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_selector.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_selector.tsx @@ -5,16 +5,19 @@ * 2.0. */ +import { EuiFormRow, EuiHorizontalRule } from '@elastic/eui'; import React, { Fragment } from 'react'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiFormRow, EuiHorizontalRule } from '@elastic/eui'; import type { PublicMethodsOf } from '@kbn/utility-types'; -import { RoleMapping, Role, isRoleDeprecated } from '../../../../../common/model'; -import { RolesAPIClient } from '../../../roles'; + +import type { Role, RoleMapping } from '../../../../../common/model'; +import { isRoleDeprecated } from '../../../../../common/model'; +import { RoleComboBox } from '../../../role_combo_box'; +import type { RolesAPIClient } from '../../../roles'; import { AddRoleTemplateButton } from './add_role_template_button'; import { RoleTemplateEditor } from './role_template_editor'; -import { RoleComboBox } from '../../../role_combo_box'; interface Props { rolesAPIClient: PublicMethodsOf; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_template_editor.test.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_template_editor.test.tsx index c402e7eb27da4..a4a388e20e66b 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_template_editor.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_template_editor.test.tsx @@ -6,9 +6,10 @@ */ import React from 'react'; -import { mountWithIntl } from '@kbn/test/jest'; + +import { findTestSubject, mountWithIntl } from '@kbn/test/jest'; + import { RoleTemplateEditor } from './role_template_editor'; -import { findTestSubject } from '@kbn/test/jest'; describe('RoleTemplateEditor', () => { it('allows inline templates to be edited', () => { diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_template_editor.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_template_editor.tsx index a619e505b5523..3ae3a2c3132f0 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_template_editor.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_template_editor.tsx @@ -5,25 +5,27 @@ * 2.0. */ -import React, { Fragment } from 'react'; -import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButtonEmpty, + EuiCallOut, + EuiFieldText, EuiFlexGroup, EuiFlexItem, EuiFormRow, - EuiFieldText, - EuiCallOut, - EuiText, - EuiSwitch, EuiSpacer, + EuiSwitch, + EuiText, } from '@elastic/eui'; +import React, { Fragment } from 'react'; + import { i18n } from '@kbn/i18n'; -import { RoleTemplate } from '../../../../../common/model'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import type { RoleTemplate } from '../../../../../common/model'; import { isInlineRoleTemplate, - isStoredRoleTemplate, isInvalidRoleTemplate, + isStoredRoleTemplate, } from '../services/role_template_type'; import { RoleTemplateTypeSelect } from './role_template_type_select'; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_template_type_select.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_template_type_select.tsx index 99dca8f0831b8..648d3cb7a8111 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_template_type_select.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/role_selector/role_template_type_select.tsx @@ -5,10 +5,12 @@ * 2.0. */ +import { EuiComboBox } from '@elastic/eui'; import React from 'react'; + import { i18n } from '@kbn/i18n'; -import { EuiComboBox } from '@elastic/eui'; -import { RoleTemplate } from '../../../../../common/model'; + +import type { RoleTemplate } from '../../../../../common/model'; import { isInlineRoleTemplate, isStoredRoleTemplate } from '../services/role_template_type'; const templateTypeOptions = [ diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/add_rule_button.test.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/add_rule_button.test.tsx index 451ffd551edcc..399d2fc2d2c91 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/add_rule_button.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/add_rule_button.test.tsx @@ -6,10 +6,11 @@ */ import React from 'react'; + +import { findTestSubject, mountWithIntl } from '@kbn/test/jest'; + +import { AllRule, FieldRule } from '../../model'; import { AddRuleButton } from './add_rule_button'; -import { mountWithIntl } from '@kbn/test/jest'; -import { findTestSubject } from '@kbn/test/jest'; -import { FieldRule, AllRule } from '../../model'; describe('AddRuleButton', () => { it('allows a field rule to be created', () => { diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/add_rule_button.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/add_rule_button.tsx index 4497ba8fc85a6..dae00d4416a1d 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/add_rule_button.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/add_rule_button.tsx @@ -5,10 +5,13 @@ * 2.0. */ +import { EuiButtonEmpty, EuiContextMenuItem, EuiContextMenuPanel, EuiPopover } from '@elastic/eui'; import React, { useState } from 'react'; -import { EuiButtonEmpty, EuiPopover, EuiContextMenuPanel, EuiContextMenuItem } from '@elastic/eui'; + import { FormattedMessage } from '@kbn/i18n/react'; -import { Rule, FieldRule, AllRule } from '../../model'; + +import type { Rule } from '../../model'; +import { AllRule, FieldRule } from '../../model'; interface Props { onClick: (newRule: Rule) => void; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/field_rule_editor.test.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/field_rule_editor.test.tsx index 97616066ea58a..c81f3cc9da595 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/field_rule_editor.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/field_rule_editor.test.tsx @@ -5,12 +5,13 @@ * 2.0. */ +import type { ReactWrapper } from 'enzyme'; import React from 'react'; -import { FieldRuleEditor } from './field_rule_editor'; -import { mountWithIntl } from '@kbn/test/jest'; + +import { findTestSubject, mountWithIntl } from '@kbn/test/jest'; + import { FieldRule } from '../../model'; -import { findTestSubject } from '@kbn/test/jest'; -import { ReactWrapper } from 'enzyme'; +import { FieldRuleEditor } from './field_rule_editor'; function assertField(wrapper: ReactWrapper, index: number, field: string) { const isFirst = index === 0; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/field_rule_editor.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/field_rule_editor.tsx index e2f1a1c65c99c..2e510c9596a51 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/field_rule_editor.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/field_rule_editor.tsx @@ -5,21 +5,25 @@ * 2.0. */ -import React, { Component, ChangeEvent } from 'react'; import { EuiButtonIcon, + EuiComboBox, EuiExpression, + EuiFieldNumber, + EuiFieldText, EuiFlexGroup, EuiFlexItem, EuiFormRow, - EuiFieldText, - EuiComboBox, - EuiSelect, - EuiFieldNumber, EuiIcon, + EuiSelect, } from '@elastic/eui'; +import type { ChangeEvent } from 'react'; +import React, { Component } from 'react'; + import { i18n } from '@kbn/i18n'; -import { FieldRule, FieldRuleValue } from '../../model'; + +import type { FieldRuleValue } from '../../model'; +import { FieldRule } from '../../model'; interface Props { rule: FieldRule; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/json_rule_editor.test.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/json_rule_editor.test.tsx index 5662c8217ef34..a4c000d324636 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/json_rule_editor.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/json_rule_editor.test.tsx @@ -7,21 +7,21 @@ import 'brace'; import 'brace/mode/json'; - // brace/ace uses the Worker class, which is not currently provided by JSDOM. // This is not required for the tests to pass, but it rather suppresses lengthy // warnings in the console which adds unnecessary noise to the test output. import '@kbn/test/target/jest/utils/stub_web_worker'; +import { EuiCodeEditor } from '@elastic/eui'; import React from 'react'; import { act } from 'react-dom/test-utils'; + import { mountWithIntl } from '@kbn/test/jest'; -import { JSONRuleEditor } from './json_rule_editor'; -import { EuiCodeEditor } from '@elastic/eui'; -import { KibanaContextProvider } from '../../../../../../../../src/plugins/kibana_react/public'; -import { AllRule, AnyRule, FieldRule, ExceptAnyRule, ExceptAllRule } from '../../model'; +import { coreMock } from 'src/core/public/mocks'; +import { KibanaContextProvider } from 'src/plugins/kibana_react/public'; -import { coreMock } from '../../../../../../../../src/core/public/mocks'; +import { AllRule, AnyRule, ExceptAllRule, ExceptAnyRule, FieldRule } from '../../model'; +import { JSONRuleEditor } from './json_rule_editor'; describe('JSONRuleEditor', () => { const renderView = (props: React.ComponentProps) => { diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/json_rule_editor.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/json_rule_editor.tsx index 49ec193b36e7d..ecbc71f295a94 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/json_rule_editor.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/json_rule_editor.tsx @@ -5,15 +5,18 @@ * 2.0. */ -import React, { useState, Fragment } from 'react'; - import 'brace/mode/json'; import 'brace/theme/github'; -import { EuiCodeEditor, EuiFormRow, EuiButton, EuiSpacer, EuiLink, EuiText } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; + +import { EuiButton, EuiCodeEditor, EuiFormRow, EuiLink, EuiSpacer, EuiText } from '@elastic/eui'; +import React, { Fragment, useState } from 'react'; + import { i18n } from '@kbn/i18n'; -import { Rule, RuleBuilderError, generateRulesFromRaw } from '../../model'; +import { FormattedMessage } from '@kbn/i18n/react'; + import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public'; +import type { Rule } from '../../model'; +import { generateRulesFromRaw, RuleBuilderError } from '../../model'; interface Props { rules: Rule | null; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_editor_panel.test.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_editor_panel.test.tsx index 4435aa9baa17e..01b4c0a0eab6d 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_editor_panel.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_editor_panel.test.tsx @@ -5,22 +5,22 @@ * 2.0. */ -import React from 'react'; -import { mountWithIntl, findTestSubject } from '@kbn/test/jest'; -import { RuleEditorPanel } from '.'; -import { VisualRuleEditor } from './visual_rule_editor'; -import { JSONRuleEditor } from './json_rule_editor'; - // brace/ace uses the Worker class, which is not currently provided by JSDOM. // This is not required for the tests to pass, but it rather suppresses lengthy // warnings in the console which adds unnecessary noise to the test output. import '@kbn/test/target/jest/utils/stub_web_worker'; -import { AllRule, FieldRule } from '../../model'; import { EuiErrorBoundary } from '@elastic/eui'; -import { KibanaContextProvider } from '../../../../../../../../src/plugins/kibana_react/public'; +import React from 'react'; + +import { findTestSubject, mountWithIntl } from '@kbn/test/jest'; +import { coreMock } from 'src/core/public/mocks'; +import { KibanaContextProvider } from 'src/plugins/kibana_react/public'; -import { coreMock } from '../../../../../../../../src/core/public/mocks'; +import { AllRule, FieldRule } from '../../model'; +import { JSONRuleEditor } from './json_rule_editor'; +import { RuleEditorPanel } from './rule_editor_panel'; +import { VisualRuleEditor } from './visual_rule_editor'; describe('RuleEditorPanel', () => { const renderView = (props: Omit, 'docLinks'>) => { diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_editor_panel.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_editor_panel.tsx index d027a1aeb7e1f..c8cd79fc5d7a6 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_editor_panel.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_editor_panel.tsx @@ -5,30 +5,33 @@ * 2.0. */ -import React, { Component, Fragment } from 'react'; import { - EuiSpacer, - EuiConfirmModal, EuiCallOut, + EuiConfirmModal, EuiErrorBoundary, - EuiIcon, - EuiLink, EuiFlexGroup, EuiFlexItem, - EuiText, EuiFormRow, + EuiIcon, + EuiLink, EuiPanel, + EuiSpacer, + EuiText, EuiTitle, } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; +import React, { Component, Fragment } from 'react'; + import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import type { DocLinksStart } from 'src/core/public'; -import { RoleMapping } from '../../../../../common/model'; -import { VisualRuleEditor } from './visual_rule_editor'; -import { JSONRuleEditor } from './json_rule_editor'; + +import type { RoleMapping } from '../../../../../common/model'; +import type { Rule } from '../../model'; +import { generateRulesFromRaw } from '../../model'; import { VISUAL_MAX_RULE_DEPTH } from '../services/role_mapping_constants'; -import { Rule, generateRulesFromRaw } from '../../model'; import { validateRoleMappingRules } from '../services/role_mapping_validation'; +import { JSONRuleEditor } from './json_rule_editor'; +import { VisualRuleEditor } from './visual_rule_editor'; interface Props { rawRules: RoleMapping['rules']; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_group_editor.test.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_group_editor.test.tsx index 3ef7aa48bb21c..8915bef293bc2 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_group_editor.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_group_editor.test.tsx @@ -5,14 +5,15 @@ * 2.0. */ +import { EuiContextMenuItem } from '@elastic/eui'; import React from 'react'; -import { RuleGroupEditor } from './rule_group_editor'; -import { shallowWithIntl, mountWithIntl, nextTick } from '@kbn/test/jest'; -import { AllRule, FieldRule, AnyRule, ExceptAnyRule } from '../../model'; -import { FieldRuleEditor } from './field_rule_editor'; + +import { findTestSubject, mountWithIntl, nextTick, shallowWithIntl } from '@kbn/test/jest'; + +import { AllRule, AnyRule, ExceptAnyRule, FieldRule } from '../../model'; import { AddRuleButton } from './add_rule_button'; -import { EuiContextMenuItem } from '@elastic/eui'; -import { findTestSubject } from '@kbn/test/jest'; +import { FieldRuleEditor } from './field_rule_editor'; +import { RuleGroupEditor } from './rule_group_editor'; describe('RuleGroupEditor', () => { it('renders an empty group', () => { diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_group_editor.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_group_editor.tsx index 107b439062497..b9ab88861bfda 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_group_editor.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_group_editor.tsx @@ -7,20 +7,22 @@ import './rule_group_editor.scss'; -import React, { Component, Fragment } from 'react'; import { - EuiPanel, + EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, - EuiButtonEmpty, + EuiPanel, } from '@elastic/eui'; +import React, { Component, Fragment } from 'react'; + import { FormattedMessage } from '@kbn/i18n/react'; + +import type { FieldRule, Rule, RuleGroup } from '../../model'; +import { isRuleGroup } from '../services/is_rule_group'; import { AddRuleButton } from './add_rule_button'; -import { RuleGroupTitle } from './rule_group_title'; import { FieldRuleEditor } from './field_rule_editor'; -import { RuleGroup, Rule, FieldRule } from '../../model'; -import { isRuleGroup } from '../services/is_rule_group'; +import { RuleGroupTitle } from './rule_group_title'; interface Props { rule: RuleGroup; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_group_title.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_group_title.tsx index 478e8d87abf95..8285797c39e9a 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_group_title.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/rule_group_title.tsx @@ -5,17 +5,20 @@ * 2.0. */ -import React, { useState } from 'react'; import { - EuiPopover, - EuiContextMenuPanel, + EuiConfirmModal, EuiContextMenuItem, - EuiLink, + EuiContextMenuPanel, EuiIcon, - EuiConfirmModal, + EuiLink, + EuiPopover, } from '@elastic/eui'; +import React, { useState } from 'react'; + import { FormattedMessage } from '@kbn/i18n/react'; -import { RuleGroup, AllRule, AnyRule, ExceptAllRule, ExceptAnyRule, FieldRule } from '../../model'; + +import type { RuleGroup } from '../../model'; +import { AllRule, AnyRule, ExceptAllRule, ExceptAnyRule, FieldRule } from '../../model'; interface Props { rule: RuleGroup; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/visual_rule_editor.test.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/visual_rule_editor.test.tsx index cdff8abc2ba55..fc48e2e1c8c9e 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/visual_rule_editor.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/visual_rule_editor.test.tsx @@ -6,12 +6,13 @@ */ import React from 'react'; -import { mountWithIntl } from '@kbn/test/jest'; -import { VisualRuleEditor } from './visual_rule_editor'; -import { findTestSubject } from '@kbn/test/jest'; -import { AnyRule, AllRule, FieldRule, ExceptAnyRule, ExceptAllRule } from '../../model'; -import { RuleGroupEditor } from './rule_group_editor'; + +import { findTestSubject, mountWithIntl } from '@kbn/test/jest'; + +import { AllRule, AnyRule, ExceptAllRule, ExceptAnyRule, FieldRule } from '../../model'; import { FieldRuleEditor } from './field_rule_editor'; +import { RuleGroupEditor } from './rule_group_editor'; +import { VisualRuleEditor } from './visual_rule_editor'; describe('VisualRuleEditor', () => { it('renders an empty prompt when no rules are defined', () => { diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/visual_rule_editor.tsx b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/visual_rule_editor.tsx index 3c0d5d89e06c5..ca418ac3749e5 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/visual_rule_editor.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/rule_editor_panel/visual_rule_editor.tsx @@ -5,14 +5,17 @@ * 2.0. */ +import { EuiButton, EuiCallOut, EuiEmptyPrompt, EuiSpacer } from '@elastic/eui'; import React, { Component, Fragment } from 'react'; -import { EuiEmptyPrompt, EuiCallOut, EuiSpacer, EuiButton } from '@elastic/eui'; + import { FormattedMessage } from '@kbn/i18n/react'; + +import type { Rule, RuleGroup } from '../../model'; +import { AllRule, FieldRule } from '../../model'; +import { isRuleGroup } from '../services/is_rule_group'; +import { VISUAL_MAX_RULE_DEPTH } from '../services/role_mapping_constants'; import { FieldRuleEditor } from './field_rule_editor'; import { RuleGroupEditor } from './rule_group_editor'; -import { VISUAL_MAX_RULE_DEPTH } from '../services/role_mapping_constants'; -import { Rule, FieldRule, RuleGroup, AllRule } from '../../model'; -import { isRuleGroup } from '../services/is_rule_group'; interface Props { rules: Rule | null; diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/is_rule_group.ts b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/is_rule_group.ts index 0086ba0c61da1..08562e4cf2e3f 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/is_rule_group.ts +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/is_rule_group.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { Rule, FieldRule } from '../../model'; +import type { Rule } from '../../model'; +import { FieldRule } from '../../model'; export function isRuleGroup(rule: Rule) { return !(rule instanceof FieldRule); diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_mapping_validation.test.ts b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_mapping_validation.test.ts index d7d20b14e0167..85029de671c3f 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_mapping_validation.test.ts +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_mapping_validation.test.ts @@ -5,14 +5,14 @@ * 2.0. */ +import type { RoleMapping } from '../../../../../common/model'; import { + validateRoleMappingForSave, validateRoleMappingName, validateRoleMappingRoles, validateRoleMappingRoleTemplates, validateRoleMappingRules, - validateRoleMappingForSave, } from './role_mapping_validation'; -import { RoleMapping } from '../../../../../common/model'; describe('validateRoleMappingName', () => { it('requires a value', () => { diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_mapping_validation.ts b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_mapping_validation.ts index f6c065391d6b8..d934e48df059e 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_mapping_validation.ts +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_mapping_validation.ts @@ -6,7 +6,8 @@ */ import { i18n } from '@kbn/i18n'; -import { RoleMapping } from '../../../../../common/model'; + +import type { RoleMapping } from '../../../../../common/model'; import { generateRulesFromRaw } from '../../model'; interface ValidationResult { diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_template_type.test.ts b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_template_type.test.ts index 96c56feaeba4a..22ff31acd0c7c 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_template_type.test.ts +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_template_type.test.ts @@ -5,12 +5,12 @@ * 2.0. */ +import type { RoleTemplate } from '../../../../../common/model'; import { - isStoredRoleTemplate, isInlineRoleTemplate, isInvalidRoleTemplate, + isStoredRoleTemplate, } from './role_template_type'; -import { RoleTemplate } from '../../../../../common/model'; describe('#isStoredRoleTemplate', () => { it('returns true for stored templates, false otherwise', () => { diff --git a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_template_type.ts b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_template_type.ts index 56b5a8131132a..0735e03f819cb 100644 --- a/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_template_type.ts +++ b/x-pack/plugins/security/public/management/role_mappings/edit_role_mapping/services/role_template_type.ts @@ -5,11 +5,11 @@ * 2.0. */ -import { - RoleTemplate, - StoredRoleTemplate, +import type { InlineRoleTemplate, InvalidRoleTemplate, + RoleTemplate, + StoredRoleTemplate, } from '../../../../../common/model'; export function isStoredRoleTemplate( diff --git a/x-pack/plugins/security/public/management/role_mappings/model/all_rule.test.ts b/x-pack/plugins/security/public/management/role_mappings/model/all_rule.test.ts index 09a66e732c7b7..19c9314c5f365 100644 --- a/x-pack/plugins/security/public/management/role_mappings/model/all_rule.test.ts +++ b/x-pack/plugins/security/public/management/role_mappings/model/all_rule.test.ts @@ -5,7 +5,12 @@ * 2.0. */ -import { AllRule, AnyRule, FieldRule, ExceptAllRule, ExceptAnyRule, RuleGroup } from '.'; +import { AllRule } from './all_rule'; +import { AnyRule } from './any_rule'; +import { ExceptAllRule } from './except_all_rule'; +import { ExceptAnyRule } from './except_any_rule'; +import { FieldRule } from './field_rule'; +import type { RuleGroup } from './rule_group'; describe('All rule', () => { it('can be constructed without sub rules', () => { diff --git a/x-pack/plugins/security/public/management/role_mappings/model/all_rule.ts b/x-pack/plugins/security/public/management/role_mappings/model/all_rule.ts index 909d253a3ad6e..191d9072d12cb 100644 --- a/x-pack/plugins/security/public/management/role_mappings/model/all_rule.ts +++ b/x-pack/plugins/security/public/management/role_mappings/model/all_rule.ts @@ -6,8 +6,9 @@ */ import { i18n } from '@kbn/i18n'; + +import type { Rule } from './rule'; import { RuleGroup } from './rule_group'; -import { Rule } from './rule'; /** * Represents a group of rules which must all evaluate to true. diff --git a/x-pack/plugins/security/public/management/role_mappings/model/any_rule.test.ts b/x-pack/plugins/security/public/management/role_mappings/model/any_rule.test.ts index 5c0ff55dbf5ed..494729ce6288e 100644 --- a/x-pack/plugins/security/public/management/role_mappings/model/any_rule.test.ts +++ b/x-pack/plugins/security/public/management/role_mappings/model/any_rule.test.ts @@ -5,7 +5,12 @@ * 2.0. */ -import { AllRule, AnyRule, FieldRule, ExceptAllRule, ExceptAnyRule, RuleGroup } from '.'; +import { AllRule } from './all_rule'; +import { AnyRule } from './any_rule'; +import { ExceptAllRule } from './except_all_rule'; +import { ExceptAnyRule } from './except_any_rule'; +import { FieldRule } from './field_rule'; +import type { RuleGroup } from './rule_group'; describe('Any rule', () => { it('can be constructed without sub rules', () => { diff --git a/x-pack/plugins/security/public/management/role_mappings/model/any_rule.ts b/x-pack/plugins/security/public/management/role_mappings/model/any_rule.ts index bbe5a3f715aa0..c67fe02c63437 100644 --- a/x-pack/plugins/security/public/management/role_mappings/model/any_rule.ts +++ b/x-pack/plugins/security/public/management/role_mappings/model/any_rule.ts @@ -6,10 +6,11 @@ */ import { i18n } from '@kbn/i18n'; -import { RuleGroup } from './rule_group'; -import { Rule } from './rule'; + import { ExceptAllRule } from './except_all_rule'; import { ExceptAnyRule } from './except_any_rule'; +import type { Rule } from './rule'; +import { RuleGroup } from './rule_group'; /** * Represents a group of rules in which at least one must evaluate to true. diff --git a/x-pack/plugins/security/public/management/role_mappings/model/except_all_rule.test.ts b/x-pack/plugins/security/public/management/role_mappings/model/except_all_rule.test.ts index a3c9a674f03f7..2ab909f9a4385 100644 --- a/x-pack/plugins/security/public/management/role_mappings/model/except_all_rule.test.ts +++ b/x-pack/plugins/security/public/management/role_mappings/model/except_all_rule.test.ts @@ -5,7 +5,12 @@ * 2.0. */ -import { AllRule, AnyRule, FieldRule, ExceptAllRule, ExceptAnyRule, RuleGroup } from '.'; +import { AllRule } from './all_rule'; +import { AnyRule } from './any_rule'; +import { ExceptAllRule } from './except_all_rule'; +import { ExceptAnyRule } from './except_any_rule'; +import { FieldRule } from './field_rule'; +import type { RuleGroup } from './rule_group'; describe('Except All rule', () => { it('can be constructed without sub rules', () => { diff --git a/x-pack/plugins/security/public/management/role_mappings/model/except_all_rule.ts b/x-pack/plugins/security/public/management/role_mappings/model/except_all_rule.ts index e59475be1f58c..55d85e2bcd5af 100644 --- a/x-pack/plugins/security/public/management/role_mappings/model/except_all_rule.ts +++ b/x-pack/plugins/security/public/management/role_mappings/model/except_all_rule.ts @@ -6,8 +6,9 @@ */ import { i18n } from '@kbn/i18n'; + +import type { Rule } from './rule'; import { RuleGroup } from './rule_group'; -import { Rule } from './rule'; /** * Represents a group of rules in which at least one must evaluate to false. diff --git a/x-pack/plugins/security/public/management/role_mappings/model/except_any_rule.test.ts b/x-pack/plugins/security/public/management/role_mappings/model/except_any_rule.test.ts index f020bbf17ac2d..b5a6c8a889de9 100644 --- a/x-pack/plugins/security/public/management/role_mappings/model/except_any_rule.test.ts +++ b/x-pack/plugins/security/public/management/role_mappings/model/except_any_rule.test.ts @@ -5,7 +5,12 @@ * 2.0. */ -import { AllRule, AnyRule, FieldRule, ExceptAllRule, ExceptAnyRule, RuleGroup } from '.'; +import { AllRule } from './all_rule'; +import { AnyRule } from './any_rule'; +import { ExceptAllRule } from './except_all_rule'; +import { ExceptAnyRule } from './except_any_rule'; +import { FieldRule } from './field_rule'; +import type { RuleGroup } from './rule_group'; describe('Except Any rule', () => { it('can be constructed without sub rules', () => { diff --git a/x-pack/plugins/security/public/management/role_mappings/model/except_any_rule.ts b/x-pack/plugins/security/public/management/role_mappings/model/except_any_rule.ts index 1f22f241bbaf3..8123ed5b90b88 100644 --- a/x-pack/plugins/security/public/management/role_mappings/model/except_any_rule.ts +++ b/x-pack/plugins/security/public/management/role_mappings/model/except_any_rule.ts @@ -6,9 +6,10 @@ */ import { i18n } from '@kbn/i18n'; -import { RuleGroup } from './rule_group'; -import { Rule } from './rule'; + import { ExceptAllRule } from './except_all_rule'; +import type { Rule } from './rule'; +import { RuleGroup } from './rule_group'; /** * Represents a group of rules in which none can evaluate to true (all must evaluate to false). diff --git a/x-pack/plugins/security/public/management/role_mappings/model/field_rule.test.ts b/x-pack/plugins/security/public/management/role_mappings/model/field_rule.test.ts index 21cc1d052e677..5be756adf9bbb 100644 --- a/x-pack/plugins/security/public/management/role_mappings/model/field_rule.test.ts +++ b/x-pack/plugins/security/public/management/role_mappings/model/field_rule.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FieldRule } from '.'; +import { FieldRule } from './field_rule'; describe('FieldRule', () => { ['*', 1, null, true, false].forEach((value) => { diff --git a/x-pack/plugins/security/public/management/role_mappings/model/field_rule.ts b/x-pack/plugins/security/public/management/role_mappings/model/field_rule.ts index f3e4dae7717cf..0b97a8c6e097e 100644 --- a/x-pack/plugins/security/public/management/role_mappings/model/field_rule.ts +++ b/x-pack/plugins/security/public/management/role_mappings/model/field_rule.ts @@ -6,6 +6,7 @@ */ import { i18n } from '@kbn/i18n'; + import { Rule } from './rule'; /** The allowed types for field rule values */ diff --git a/x-pack/plugins/security/public/management/role_mappings/model/rule_builder.test.ts b/x-pack/plugins/security/public/management/role_mappings/model/rule_builder.test.ts index 6859cd3323fbe..551c1d8ef964f 100644 --- a/x-pack/plugins/security/public/management/role_mappings/model/rule_builder.test.ts +++ b/x-pack/plugins/security/public/management/role_mappings/model/rule_builder.test.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { generateRulesFromRaw, FieldRule } from '.'; -import { RoleMapping } from '../../../../common/model'; +import type { RoleMapping } from '../../../../common/model'; +import { FieldRule } from './field_rule'; +import { generateRulesFromRaw } from './rule_builder'; import { RuleBuilderError } from './rule_builder_error'; describe('generateRulesFromRaw', () => { diff --git a/x-pack/plugins/security/public/management/role_mappings/model/rule_builder.ts b/x-pack/plugins/security/public/management/role_mappings/model/rule_builder.ts index cbd08da4b76d4..f25f4fa7cda5f 100644 --- a/x-pack/plugins/security/public/management/role_mappings/model/rule_builder.ts +++ b/x-pack/plugins/security/public/management/role_mappings/model/rule_builder.ts @@ -6,14 +6,16 @@ */ import { i18n } from '@kbn/i18n'; -import { RoleMapping } from '../../../../common/model'; -import { FieldRule, FieldRuleValue } from './field_rule'; + +import type { RoleMapping } from '../../../../common/model'; import { AllRule } from './all_rule'; import { AnyRule } from './any_rule'; -import { Rule } from './rule'; import { ExceptAllRule } from './except_all_rule'; import { ExceptAnyRule } from './except_any_rule'; -import { RuleBuilderError } from '.'; +import type { FieldRuleValue } from './field_rule'; +import { FieldRule } from './field_rule'; +import type { Rule } from './rule'; +import { RuleBuilderError } from './rule_builder_error'; interface RuleBuilderResult { /** The maximum rule depth within the parsed rule set. */ diff --git a/x-pack/plugins/security/public/management/role_mappings/role_mappings_api_client.ts b/x-pack/plugins/security/public/management/role_mappings/role_mappings_api_client.ts index 4c391829592e2..f8474b91f26f4 100644 --- a/x-pack/plugins/security/public/management/role_mappings/role_mappings_api_client.ts +++ b/x-pack/plugins/security/public/management/role_mappings/role_mappings_api_client.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { HttpStart } from 'src/core/public'; -import { RoleMapping } from '../../../common/model'; +import type { HttpStart } from 'src/core/public'; + +import type { RoleMapping } from '../../../common/model'; interface CheckRoleMappingFeaturesResponse { canManageRoleMappings: boolean; diff --git a/x-pack/plugins/security/public/management/role_mappings/role_mappings_grid/create_role_mapping_button/create_role_mapping_button.tsx b/x-pack/plugins/security/public/management/role_mappings/role_mappings_grid/create_role_mapping_button/create_role_mapping_button.tsx index 6986eec661f1b..b7f3261e18914 100644 --- a/x-pack/plugins/security/public/management/role_mappings/role_mappings_grid/create_role_mapping_button/create_role_mapping_button.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/role_mappings_grid/create_role_mapping_button/create_role_mapping_button.tsx @@ -5,12 +5,14 @@ * 2.0. */ -import React from 'react'; import { EuiButton } from '@elastic/eui'; +import React from 'react'; + import { FormattedMessage } from '@kbn/i18n/react'; -import { ScopedHistory } from 'kibana/public'; -import { EDIT_ROLE_MAPPING_PATH } from '../../../management_urls'; +import type { ScopedHistory } from 'src/core/public'; + import { reactRouterNavigate } from '../../../../../../../../src/plugins/kibana_react/public'; +import { EDIT_ROLE_MAPPING_PATH } from '../../../management_urls'; interface CreateRoleMappingButtonProps { history: ScopedHistory; diff --git a/x-pack/plugins/security/public/management/role_mappings/role_mappings_grid/empty_prompt/empty_prompt.tsx b/x-pack/plugins/security/public/management/role_mappings/role_mappings_grid/empty_prompt/empty_prompt.tsx index 8d08013a47981..cc0b41592e1f8 100644 --- a/x-pack/plugins/security/public/management/role_mappings/role_mappings_grid/empty_prompt/empty_prompt.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/role_mappings_grid/empty_prompt/empty_prompt.tsx @@ -5,10 +5,12 @@ * 2.0. */ -import React, { Fragment } from 'react'; import { EuiEmptyPrompt } from '@elastic/eui'; +import React, { Fragment } from 'react'; + import { FormattedMessage } from '@kbn/i18n/react'; -import { ScopedHistory } from 'kibana/public'; +import type { ScopedHistory } from 'src/core/public'; + import { CreateRoleMappingButton } from '../create_role_mapping_button'; interface EmptyPromptProps { diff --git a/x-pack/plugins/security/public/management/role_mappings/role_mappings_grid/role_mappings_grid_page.test.tsx b/x-pack/plugins/security/public/management/role_mappings/role_mappings_grid/role_mappings_grid_page.test.tsx index 10185cb5b4a06..5f237e6504d32 100644 --- a/x-pack/plugins/security/public/management/role_mappings/role_mappings_grid/role_mappings_grid_page.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/role_mappings_grid/role_mappings_grid_page.test.tsx @@ -5,20 +5,20 @@ * 2.0. */ -import React from 'react'; -import { CoreStart, ScopedHistory } from 'kibana/public'; -import { mountWithIntl, nextTick } from '@kbn/test/jest'; -import { RoleMappingsGridPage } from '.'; -import { SectionLoading, PermissionDenied, NoCompatibleRealms } from '../components'; -import { EmptyPrompt } from './empty_prompt'; -import { findTestSubject } from '@kbn/test/jest'; import { EuiLink } from '@elastic/eui'; import { act } from '@testing-library/react'; -import { KibanaContextProvider } from '../../../../../../../src/plugins/kibana_react/public'; +import React from 'react'; + +import { findTestSubject, mountWithIntl, nextTick } from '@kbn/test/jest'; +import type { CoreStart, ScopedHistory } from 'src/core/public'; +import { coreMock, scopedHistoryMock } from 'src/core/public/mocks'; +import { KibanaContextProvider } from 'src/plugins/kibana_react/public'; -import { coreMock, scopedHistoryMock } from '../../../../../../../src/core/public/mocks'; -import { roleMappingsAPIClientMock } from '../role_mappings_api_client.mock'; import { rolesAPIClientMock } from '../../roles/index.mock'; +import { NoCompatibleRealms, PermissionDenied, SectionLoading } from '../components'; +import { roleMappingsAPIClientMock } from '../role_mappings_api_client.mock'; +import { EmptyPrompt } from './empty_prompt'; +import { RoleMappingsGridPage } from './role_mappings_grid_page'; describe('RoleMappingsGridPage', () => { let history: ScopedHistory; @@ -238,25 +238,12 @@ describe('RoleMappingsGridPage', () => { await nextTick(); wrapper.update(); - const deprecationTooltip = wrapper.find('[data-test-subj="roleDeprecationTooltip"]').props(); - - expect(deprecationTooltip).toMatchInlineSnapshot(` - Object { - "children":
- kibana_user - - -
, - "content": "The kibana_user role is deprecated. I don't like you.", - "data-test-subj": "roleDeprecationTooltip", - "delay": "regular", - "position": "top", - } - `); + const deprecationTooltip = wrapper + .find('[data-test-subj="roleDeprecationTooltip"]') + .prop('content'); + + expect(deprecationTooltip).toMatchInlineSnapshot( + `"The kibana_user role is deprecated. I don't like you."` + ); }); }); diff --git a/x-pack/plugins/security/public/management/role_mappings/role_mappings_grid/role_mappings_grid_page.tsx b/x-pack/plugins/security/public/management/role_mappings/role_mappings_grid/role_mappings_grid_page.tsx index 33f969095a356..f5f6d2daf306d 100644 --- a/x-pack/plugins/security/public/management/role_mappings/role_mappings_grid/role_mappings_grid_page.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/role_mappings_grid/role_mappings_grid_page.tsx @@ -5,7 +5,6 @@ * 2.0. */ -import React, { Component, Fragment } from 'react'; import { EuiButton, EuiButtonIcon, @@ -23,29 +22,32 @@ import { EuiTitle, EuiToolTip, } from '@elastic/eui'; +import React, { Component, Fragment } from 'react'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import type { PublicMethodsOf } from '@kbn/utility-types'; import type { - NotificationsStart, ApplicationStart, DocLinksStart, + NotificationsStart, ScopedHistory, } from 'src/core/public'; -import { RoleMapping, Role } from '../../../../common/model'; -import { EmptyPrompt } from './empty_prompt'; + +import { reactRouterNavigate } from '../../../../../../../src/plugins/kibana_react/public'; +import type { Role, RoleMapping } from '../../../../common/model'; +import { DisabledBadge, EnabledBadge } from '../../badges'; +import { EDIT_ROLE_MAPPING_PATH, getEditRoleMappingHref } from '../../management_urls'; +import { RoleTableDisplay } from '../../role_table_display'; +import type { RolesAPIClient } from '../../roles'; import { - NoCompatibleRealms, DeleteProvider, + NoCompatibleRealms, PermissionDenied, SectionLoading, } from '../components'; -import { EDIT_ROLE_MAPPING_PATH, getEditRoleMappingHref } from '../../management_urls'; -import { RoleMappingsAPIClient } from '../role_mappings_api_client'; -import { RoleTableDisplay } from '../../role_table_display'; -import { RolesAPIClient } from '../../roles'; -import { EnabledBadge, DisabledBadge } from '../../badges'; -import { reactRouterNavigate } from '../../../../../../../src/plugins/kibana_react/public'; +import type { RoleMappingsAPIClient } from '../role_mappings_api_client'; +import { EmptyPrompt } from './empty_prompt'; interface Props { rolesAPIClient: PublicMethodsOf; diff --git a/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.test.tsx b/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.test.tsx index 934601a6f4b48..e73abc3b1eeaf 100644 --- a/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.test.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.test.tsx @@ -23,8 +23,9 @@ jest.mock('./edit_role_mapping', () => ({ })}`, })); +import { coreMock, scopedHistoryMock } from 'src/core/public/mocks'; + import { roleMappingsManagementApp } from './role_mappings_management_app'; -import { coreMock, scopedHistoryMock } from '../../../../../../src/core/public/mocks'; async function mountApp(basePath: string, pathname: string) { const container = document.createElement('div'); diff --git a/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.tsx b/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.tsx index 24d197d1c64e7..4dfc9b43642bf 100644 --- a/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.tsx +++ b/x-pack/plugins/security/public/management/role_mappings/role_mappings_management_app.tsx @@ -7,13 +7,15 @@ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; -import { Router, Route, Switch, useParams } from 'react-router-dom'; +import { Route, Router, Switch, useParams } from 'react-router-dom'; + import { i18n } from '@kbn/i18n'; -import { StartServicesAccessor } from 'src/core/public'; -import { RegisterManagementAppArgs } from '../../../../../../src/plugins/management/public'; -import { PluginStartDependencies } from '../../plugin'; -import { tryDecodeURIComponent } from '../url_utils'; +import type { StartServicesAccessor } from 'src/core/public'; +import type { RegisterManagementAppArgs } from 'src/plugins/management/public'; + import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; +import type { PluginStartDependencies } from '../../plugin'; +import { tryDecodeURIComponent } from '../url_utils'; interface CreateParams { getStartServices: StartServicesAccessor; diff --git a/x-pack/plugins/security/public/management/role_table_display/role_table_display.tsx b/x-pack/plugins/security/public/management/role_table_display/role_table_display.tsx index d30fd1d0d6952..ac3ba0bd20118 100644 --- a/x-pack/plugins/security/public/management/role_table_display/role_table_display.tsx +++ b/x-pack/plugins/security/public/management/role_table_display/role_table_display.tsx @@ -5,10 +5,13 @@ * 2.0. */ +import { EuiIcon, EuiLink, EuiToolTip } from '@elastic/eui'; import React from 'react'; -import { EuiLink, EuiToolTip, EuiIcon } from '@elastic/eui'; -import { ApplicationStart } from 'kibana/public'; -import { Role, isRoleDeprecated, getExtendedRoleDeprecationNotice } from '../../../common/model'; + +import type { ApplicationStart } from 'src/core/public'; + +import type { Role } from '../../../common/model'; +import { getExtendedRoleDeprecationNotice, isRoleDeprecated } from '../../../common/model'; interface Props { role: Role | string; diff --git a/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_features.ts b/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_features.ts index 729ee7a661816..7bb0ba254c830 100644 --- a/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_features.ts +++ b/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_features.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { KibanaFeature, KibanaFeatureConfig } from '../../../../../features/public'; +import type { KibanaFeatureConfig } from '../../../../../features/public'; +import { KibanaFeature } from '../../../../../features/public'; export const createFeature = ( config: Pick< diff --git a/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_privileges.ts b/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_privileges.ts index 97ac98b7a9f9c..de829ea003b00 100644 --- a/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_privileges.ts +++ b/x-pack/plugins/security/public/management/roles/__fixtures__/kibana_privileges.ts @@ -5,16 +5,15 @@ * 2.0. */ +import type { KibanaFeature } from '../../../../../features/public'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { featuresPluginMock } from '../../../../../features/server/mocks'; +import type { SecurityLicenseFeatures } from '../../../../common/licensing'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { Actions } from '../../../../server/authorization'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { privilegesFactory } from '../../../../server/authorization/privileges'; -import { KibanaFeature } from '../../../../../features/public'; import { KibanaPrivileges } from '../model'; -import { SecurityLicenseFeatures } from '../../..'; - -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { featuresPluginMock } from '../../../../../features/server/mocks'; export const createRawKibanaPrivileges = ( features: KibanaFeature[], diff --git a/x-pack/plugins/security/public/management/roles/edit_role/collapsible_panel/collapsible_panel.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/collapsible_panel/collapsible_panel.test.tsx index 2a7bc68797d86..e37b440d2c021 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/collapsible_panel/collapsible_panel.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/collapsible_panel/collapsible_panel.test.tsx @@ -7,7 +7,9 @@ import { EuiLink } from '@elastic/eui'; import React from 'react'; + import { mountWithIntl, shallowWithIntl } from '@kbn/test/jest'; + import { CollapsiblePanel } from './collapsible_panel'; test('it renders without blowing up', () => { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/collapsible_panel/collapsible_panel.tsx b/x-pack/plugins/security/public/management/roles/edit_role/collapsible_panel/collapsible_panel.tsx index 87ce735c999eb..a8d98f5425657 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/collapsible_panel/collapsible_panel.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/collapsible_panel/collapsible_panel.tsx @@ -7,6 +7,7 @@ import './collapsible_panel.scss'; +import type { IconType } from '@elastic/eui'; import { EuiFlexGroup, EuiFlexItem, @@ -15,10 +16,11 @@ import { EuiPanel, EuiSpacer, EuiTitle, - IconType, } from '@elastic/eui'; +import type { ReactNode } from 'react'; +import React, { Component, Fragment } from 'react'; + import { FormattedMessage } from '@kbn/i18n/react'; -import React, { Component, Fragment, ReactNode } from 'react'; interface Props { iconType?: IconType; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/delete_role_button.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/delete_role_button.test.tsx index 735372fe87de8..1faf514e71925 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/delete_role_button.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/delete_role_button.test.tsx @@ -7,7 +7,9 @@ import { EuiButtonEmpty, EuiConfirmModal } from '@elastic/eui'; import React from 'react'; + import { mountWithIntl, shallowWithIntl } from '@kbn/test/jest'; + import { DeleteRoleButton } from './delete_role_button'; test('it renders without crashing', () => { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/delete_role_button.tsx b/x-pack/plugins/security/public/management/roles/edit_role/delete_role_button.tsx index 1b3a7fa024dd1..0029e91cce780 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/delete_role_button.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/delete_role_button.tsx @@ -6,9 +6,10 @@ */ import { EuiButtonEmpty, EuiConfirmModal } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; import React, { Component, Fragment } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; + interface Props { canDelete: boolean; onDelete: () => void; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.test.tsx index 6cda22c33ea42..3002db642bc1e 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.test.tsx @@ -5,25 +5,26 @@ * 2.0. */ -import { ReactWrapper } from 'enzyme'; -import React from 'react'; import { act } from '@testing-library/react'; +import type { ReactWrapper } from 'enzyme'; +import React from 'react'; + import { mountWithIntl, nextTick } from '@kbn/test/jest'; -import { Capabilities } from 'src/core/public'; -import { KibanaFeature } from '../../../../../features/public'; -import { Role } from '../../../../common/model'; -import { EditRolePage } from './edit_role_page'; -import { SimplePrivilegeSection } from './privileges/kibana/simple_privilege_section'; +import type { Capabilities } from 'src/core/public'; +import { coreMock, scopedHistoryMock } from 'src/core/public/mocks'; +import { dataPluginMock } from 'src/plugins/data/public/mocks'; -import { TransformErrorSection } from './privileges/kibana/transform_error_section'; -import { coreMock, scopedHistoryMock } from '../../../../../../../src/core/public/mocks'; -import { dataPluginMock } from '../../../../../../../src/plugins/data/public/mocks'; +import { KibanaFeature } from '../../../../../features/public'; +import type { Space } from '../../../../../spaces/public'; import { licenseMock } from '../../../../common/licensing/index.mock'; +import type { Role } from '../../../../common/model'; import { userAPIClientMock } from '../../users/index.mock'; -import { rolesAPIClientMock, indicesAPIClientMock, privilegesAPIClientMock } from '../index.mock'; -import { Space } from '../../../../../spaces/public'; -import { SpaceAwarePrivilegeSection } from './privileges/kibana/space_aware_privilege_section'; import { createRawKibanaPrivileges } from '../__fixtures__/kibana_privileges'; +import { indicesAPIClientMock, privilegesAPIClientMock, rolesAPIClientMock } from '../index.mock'; +import { EditRolePage } from './edit_role_page'; +import { SimplePrivilegeSection } from './privileges/kibana/simple_privilege_section'; +import { SpaceAwarePrivilegeSection } from './privileges/kibana/space_aware_privilege_section'; +import { TransformErrorSection } from './privileges/kibana/transform_error_section'; const buildFeatures = () => { return [ diff --git a/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.tsx b/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.tsx index 340cf4c72362d..cf9ac50b0daf0 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/edit_role_page.tsx @@ -8,6 +8,7 @@ import { EuiButton, EuiButtonEmpty, + EuiCallOut, EuiFieldText, EuiFlexGroup, EuiFlexItem, @@ -17,57 +18,54 @@ import { EuiSpacer, EuiText, EuiTitle, - EuiCallOut, } from '@elastic/eui'; +import type { ChangeEvent, FunctionComponent, HTMLProps } from 'react'; +import React, { Fragment, useCallback, useEffect, useRef, useState } from 'react'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import React, { - ChangeEvent, - Fragment, - FunctionComponent, - HTMLProps, - useCallback, - useEffect, - useRef, - useState, -} from 'react'; import type { PublicMethodsOf } from '@kbn/utility-types'; -import { +import type { Capabilities, + DocLinksStart, FatalErrorsSetup, HttpStart, IHttpFetchError, NotificationsStart, + ScopedHistory, } from 'src/core/public'; -import type { DocLinksStart, ScopedHistory } from 'kibana/public'; +import type { IndexPatternsContract } from 'src/plugins/data/public'; import type { SpacesApiUi } from 'src/plugins/spaces_oss/public'; -import { FeaturesPluginStart } from '../../../../../features/public'; -import { KibanaFeature } from '../../../../../features/common'; -import { IndexPatternsContract } from '../../../../../../../src/plugins/data/public'; -import { Space } from '../../../../../spaces/public'; -import { + +import { reactRouterNavigate } from '../../../../../../../src/plugins/kibana_react/public'; +import type { KibanaFeature } from '../../../../../features/common'; +import type { FeaturesPluginStart } from '../../../../../features/public'; +import type { Space } from '../../../../../spaces/public'; +import type { SecurityLicense } from '../../../../common/licensing'; +import type { + BuiltinESPrivileges, RawKibanaPrivileges, Role, - BuiltinESPrivileges, + RoleIndexPrivilege, +} from '../../../../common/model'; +import { + copyRole, + getExtendedRoleDeprecationNotice, + isRoleDeprecated as checkIfRoleDeprecated, isRoleReadOnly as checkIfRoleReadOnly, isRoleReserved as checkIfRoleReserved, - isRoleDeprecated as checkIfRoleDeprecated, - copyRole, prepareRoleClone, - RoleIndexPrivilege, - getExtendedRoleDeprecationNotice, } from '../../../../common/model'; -import { RoleValidationResult, RoleValidator } from './validate_role'; +import type { UserAPIClient } from '../../users'; +import type { IndicesAPIClient } from '../indices_api_client'; +import { KibanaPrivileges } from '../model'; +import type { PrivilegesAPIClient } from '../privileges_api_client'; +import type { RolesAPIClient } from '../roles_api_client'; import { DeleteRoleButton } from './delete_role_button'; import { ElasticsearchPrivileges, KibanaPrivilegesRegion } from './privileges'; import { ReservedRoleBadge } from './reserved_role_badge'; -import { SecurityLicense } from '../../../../common/licensing'; -import { UserAPIClient } from '../../users'; -import { IndicesAPIClient } from '../indices_api_client'; -import { RolesAPIClient } from '../roles_api_client'; -import { PrivilegesAPIClient } from '../privileges_api_client'; -import { KibanaPrivileges } from '../model'; -import { reactRouterNavigate } from '../../../../../../../src/plugins/kibana_react/public'; +import type { RoleValidationResult } from './validate_role'; +import { RoleValidator } from './validate_role'; interface Props { action: 'edit' | 'clone'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privilege_utils.ts b/x-pack/plugins/security/public/management/roles/edit_role/privilege_utils.ts index a543aa769c093..170aa3f6e89fe 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privilege_utils.ts +++ b/x-pack/plugins/security/public/management/roles/edit_role/privilege_utils.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { RoleKibanaPrivilege } from '../../../../common/model'; +import type { RoleKibanaPrivilege } from '../../../../common/model'; /** * Determines if the passed privilege spec defines global privileges. diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/cluster_privileges.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/cluster_privileges.test.tsx index d6e841a7d37e8..baeba5829562e 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/cluster_privileges.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/cluster_privileges.test.tsx @@ -7,10 +7,12 @@ import { shallow } from 'enzyme'; import React from 'react'; -import { Role } from '../../../../../../common/model'; -import { ClusterPrivileges } from './cluster_privileges'; + import { mountWithIntl } from '@kbn/test/jest'; +import type { Role } from '../../../../../../common/model'; +import { ClusterPrivileges } from './cluster_privileges'; + test('it renders without crashing', () => { const role: Role = { name: '', diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/cluster_privileges.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/cluster_privileges.tsx index cb11dbc472e56..6d2643c4b6998 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/cluster_privileges.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/cluster_privileges.tsx @@ -6,9 +6,11 @@ */ import { EuiComboBox, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import React, { Component } from 'react'; import _ from 'lodash'; -import { Role, isRoleReadOnly } from '../../../../../../common/model'; +import React, { Component } from 'react'; + +import type { Role } from '../../../../../../common/model'; +import { isRoleReadOnly } from '../../../../../../common/model'; interface Props { role: Role; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/elasticsearch_privileges.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/elasticsearch_privileges.test.tsx index 7336207569fb5..0ed9362956960 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/elasticsearch_privileges.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/elasticsearch_privileges.test.tsx @@ -6,16 +6,17 @@ */ import React from 'react'; + import { mountWithIntl, shallowWithIntl } from '@kbn/test/jest'; +import { coreMock } from 'src/core/public/mocks'; + +import { licenseMock } from '../../../../../../common/licensing/index.mock'; +import { indicesAPIClientMock } from '../../../index.mock'; import { RoleValidator } from '../../validate_role'; import { ClusterPrivileges } from './cluster_privileges'; import { ElasticsearchPrivileges } from './elasticsearch_privileges'; import { IndexPrivileges } from './index_privileges'; -import { licenseMock } from '../../../../../../common/licensing/index.mock'; -import { indicesAPIClientMock } from '../../../index.mock'; -import { coreMock } from '../../../../../../../../../src/core/public/mocks'; - function getProps() { const license = licenseMock.create(); license.getFeatures.mockReturnValue({ diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/elasticsearch_privileges.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/elasticsearch_privileges.tsx index 42f18b846a60a..e1967491be1f7 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/elasticsearch_privileges.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/elasticsearch_privileges.tsx @@ -16,16 +16,18 @@ import { EuiText, EuiTitle, } from '@elastic/eui'; +import React, { Component, Fragment } from 'react'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import type { PublicMethodsOf } from '@kbn/utility-types'; -import React, { Component, Fragment } from 'react'; import type { DocLinksStart } from 'src/core/public'; -import { Role, BuiltinESPrivileges } from '../../../../../../common/model'; -import { SecurityLicense } from '../../../../../../common/licensing'; -import { IndicesAPIClient } from '../../../indices_api_client'; -import { RoleValidator } from '../../validate_role'; + +import type { SecurityLicense } from '../../../../../../common/licensing'; +import type { BuiltinESPrivileges, Role } from '../../../../../../common/model'; +import type { IndicesAPIClient } from '../../../indices_api_client'; import { CollapsiblePanel } from '../../collapsible_panel'; +import type { RoleValidator } from '../../validate_role'; import { ClusterPrivileges } from './cluster_privileges'; import { IndexPrivileges } from './index_privileges'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privilege_form.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privilege_form.test.tsx index 7819779eefa3c..221e0ec245fd4 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privilege_form.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privilege_form.test.tsx @@ -7,7 +7,9 @@ import { EuiButtonIcon, EuiTextArea } from '@elastic/eui'; import React from 'react'; + import { mountWithIntl, shallowWithIntl } from '@kbn/test/jest'; + import { RoleValidator } from '../../validate_role'; import { IndexPrivilegeForm } from './index_privilege_form'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privilege_form.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privilege_form.tsx index c1c56e6082aef..697b5c1cac347 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privilege_form.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privilege_form.tsx @@ -5,10 +5,10 @@ * 2.0. */ +import type { EuiComboBoxOptionOption } from '@elastic/eui'; import { EuiButtonIcon, EuiComboBox, - EuiComboBoxOptionOption, EuiFlexGroup, EuiFlexItem, EuiFormRow, @@ -17,12 +17,15 @@ import { EuiSwitch, EuiTextArea, } from '@elastic/eui'; +import _ from 'lodash'; +import type { ChangeEvent } from 'react'; +import React, { Component, Fragment } from 'react'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import _ from 'lodash'; -import React, { ChangeEvent, Component, Fragment } from 'react'; -import { RoleIndexPrivilege } from '../../../../../../common/model'; -import { RoleValidator } from '../../validate_role'; + +import type { RoleIndexPrivilege } from '../../../../../../common/model'; +import type { RoleValidator } from '../../validate_role'; const fromOption = (option: any) => option.label; const toOption = (value: string) => ({ label: value }); diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privileges.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privileges.test.tsx index 77ff8e8633add..5b7d703865b9c 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privileges.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privileges.test.tsx @@ -6,13 +6,14 @@ */ import React from 'react'; + import { mountWithIntl, shallowWithIntl } from '@kbn/test/jest'; -import { RoleValidator } from '../../validate_role'; -import { IndexPrivilegeForm } from './index_privilege_form'; -import { IndexPrivileges } from './index_privileges'; import { licenseMock } from '../../../../../../common/licensing/index.mock'; import { indicesAPIClientMock } from '../../../index.mock'; +import { RoleValidator } from '../../validate_role'; +import { IndexPrivilegeForm } from './index_privilege_form'; +import { IndexPrivileges } from './index_privileges'; // the IndexPrivileges post-mount hook kicks off some promises; // we need to wait for those promises to resolve to ensure any errors are properly caught diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privileges.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privileges.tsx index 34d11b3f9c159..2f6bb73fc62fb 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privileges.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privileges.tsx @@ -7,16 +7,14 @@ import _ from 'lodash'; import React, { Component, Fragment } from 'react'; + import type { PublicMethodsOf } from '@kbn/utility-types'; -import { - Role, - RoleIndexPrivilege, - isRoleReadOnly, - isRoleEnabled, -} from '../../../../../../common/model'; -import { SecurityLicense } from '../../../../../../common/licensing'; -import { IndicesAPIClient } from '../../../indices_api_client'; -import { RoleValidator } from '../../validate_role'; + +import type { SecurityLicense } from '../../../../../../common/licensing'; +import type { Role, RoleIndexPrivilege } from '../../../../../../common/model'; +import { isRoleEnabled, isRoleReadOnly } from '../../../../../../common/model'; +import type { IndicesAPIClient } from '../../../indices_api_client'; +import type { RoleValidator } from '../../validate_role'; import { IndexPrivilegeForm } from './index_privilege_form'; interface Props { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/__fixtures__/index.ts b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/__fixtures__/index.ts index acfae9890d843..b43a6bee82e27 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/__fixtures__/index.ts +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/__fixtures__/index.ts @@ -5,12 +5,12 @@ * 2.0. */ -import { ReactWrapper } from 'enzyme'; - -import { EuiCheckbox, EuiCheckboxProps, EuiButtonGroup, EuiButtonGroupProps } from '@elastic/eui'; +import type { EuiButtonGroupProps, EuiCheckboxProps } from '@elastic/eui'; +import { EuiAccordion, EuiButtonGroup, EuiCheckbox } from '@elastic/eui'; +import type { ReactWrapper } from 'enzyme'; import { findTestSubject } from '@kbn/test/jest'; -import { EuiAccordion } from '@elastic/eui'; + import { SubFeatureForm } from '../sub_feature_form'; export function getDisplayedFeaturePrivileges(wrapper: ReactWrapper) { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/change_all_privileges.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/change_all_privileges.tsx index 8cae425fa47b9..154fcda6fd4c7 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/change_all_privileges.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/change_all_privileges.tsx @@ -10,16 +10,19 @@ import './change_all_privileges.scss'; import { EuiContextMenuItem, EuiContextMenuPanel, + EuiIcon, EuiLink, EuiPopover, - EuiIcon, EuiText, } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; import _ from 'lodash'; import React, { Component } from 'react'; -import { KibanaPrivilege } from '../../../../model'; + +import { FormattedMessage } from '@kbn/i18n/react'; + +import type { KibanaPrivilege } from '../../../../model'; import { NO_PRIVILEGE_VALUE } from '../constants'; + interface Props { onChange: (privilege: string) => void; privileges: KibanaPrivilege[]; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx index e805dbd6f48b2..216409642289b 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx @@ -5,17 +5,18 @@ * 2.0. */ +import { EuiAccordion } from '@elastic/eui'; import React from 'react'; -import { FeatureTable } from './feature_table'; -import { Role } from '../../../../../../../common/model'; -import { mountWithIntl } from '@kbn/test/jest'; -import { KibanaFeature, SubFeatureConfig } from '../../../../../../../../features/public'; -import { kibanaFeatures, createFeature } from '../../../../__fixtures__/kibana_features'; + +import { findTestSubject, mountWithIntl } from '@kbn/test/jest'; + +import type { KibanaFeature, SubFeatureConfig } from '../../../../../../../../features/public'; +import type { Role } from '../../../../../../../common/model'; +import { createFeature, kibanaFeatures } from '../../../../__fixtures__/kibana_features'; import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; import { PrivilegeFormCalculator } from '../privilege_form_calculator'; import { getDisplayedFeaturePrivileges } from './__fixtures__'; -import { findTestSubject } from '@kbn/test/jest'; -import { EuiAccordion } from '@elastic/eui'; +import { FeatureTable } from './feature_table'; const createRole = (kibana: Role['kibana'] = []): Role => { return { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx index 327f740188cce..50d40fbdc4751 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx @@ -5,32 +5,36 @@ * 2.0. */ +import './feature_table.scss'; + +import type { EuiAccordionProps } from '@elastic/eui'; import { - EuiAccordionProps, + EuiAccordion, EuiButtonGroup, - EuiIconTip, - EuiText, + EuiCallOut, EuiFlexGroup, EuiFlexItem, - EuiSpacer, - EuiCallOut, EuiHorizontalRule, - EuiAccordion, EuiIcon, + EuiIconTip, + EuiSpacer, + EuiText, EuiTitle, } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; +import type { ReactElement } from 'react'; +import React, { Component } from 'react'; + import { i18n } from '@kbn/i18n'; -import React, { Component, ReactElement } from 'react'; -import { AppCategory } from 'kibana/public'; -import { Role } from '../../../../../../../common/model'; -import { ChangeAllPrivilegesControl } from './change_all_privileges'; -import { FeatureTableExpandedRow } from './feature_table_expanded_row'; +import { FormattedMessage } from '@kbn/i18n/react'; +import type { AppCategory } from 'src/core/public'; + +import type { Role } from '../../../../../../../common/model'; +import type { KibanaPrivileges, SecuredFeature } from '../../../../model'; import { NO_PRIVILEGE_VALUE } from '../constants'; -import { PrivilegeFormCalculator } from '../privilege_form_calculator'; import { FeatureTableCell } from '../feature_table_cell'; -import { KibanaPrivileges, SecuredFeature } from '../../../../model'; -import './feature_table.scss'; +import type { PrivilegeFormCalculator } from '../privilege_form_calculator'; +import { ChangeAllPrivilegesControl } from './change_all_privileges'; +import { FeatureTableExpandedRow } from './feature_table_expanded_row'; interface Props { role: Role; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table_expanded_row.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table_expanded_row.test.tsx index e6daa851a7e90..cd1db2f9ce486 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table_expanded_row.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table_expanded_row.test.tsx @@ -5,15 +5,16 @@ * 2.0. */ +import { act } from '@testing-library/react'; import React from 'react'; -import { Role } from '../../../../../../../common/model'; -import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; + +import { findTestSubject, mountWithIntl } from '@kbn/test/jest'; + +import type { Role } from '../../../../../../../common/model'; import { kibanaFeatures } from '../../../../__fixtures__/kibana_features'; +import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; import { PrivilegeFormCalculator } from '../privilege_form_calculator'; -import { mountWithIntl } from '@kbn/test/jest'; import { FeatureTableExpandedRow } from './feature_table_expanded_row'; -import { findTestSubject } from '@kbn/test/jest'; -import { act } from '@testing-library/react'; const createRole = (kibana: Role['kibana'] = []): Role => { return { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table_expanded_row.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table_expanded_row.tsx index 4670099362efe..e528a0fc4b850 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table_expanded_row.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table_expanded_row.tsx @@ -5,12 +5,15 @@ * 2.0. */ -import React, { useState, useEffect } from 'react'; +import type { EuiSwitchEvent } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiSwitch } from '@elastic/eui'; +import React, { useEffect, useState } from 'react'; + import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiFlexItem, EuiFlexGroup, EuiSwitch, EuiSwitchEvent } from '@elastic/eui'; + +import type { SecuredFeature } from '../../../../model'; +import type { PrivilegeFormCalculator } from '../privilege_form_calculator'; import { SubFeatureForm } from './sub_feature_form'; -import { PrivilegeFormCalculator } from '../privilege_form_calculator'; -import { SecuredFeature } from '../../../../model'; interface Props { feature: SecuredFeature; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/sub_feature_form.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/sub_feature_form.test.tsx index b52315751e63b..d39d7acc6c3a1 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/sub_feature_form.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/sub_feature_form.test.tsx @@ -5,17 +5,19 @@ * 2.0. */ +import { EuiButtonGroup, EuiCheckbox } from '@elastic/eui'; +import { act } from '@testing-library/react'; import React from 'react'; + +import { mountWithIntl } from '@kbn/test/jest'; + +import { KibanaFeature } from '../../../../../../../../features/public'; +import type { Role } from '../../../../../../../common/model'; import { kibanaFeatures } from '../../../../__fixtures__/kibana_features'; import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; import { SecuredSubFeature } from '../../../../model'; import { PrivilegeFormCalculator } from '../privilege_form_calculator'; -import { Role } from '../../../../../../../common/model'; -import { mountWithIntl } from '@kbn/test/jest'; import { SubFeatureForm } from './sub_feature_form'; -import { EuiCheckbox, EuiButtonGroup } from '@elastic/eui'; -import { act } from '@testing-library/react'; -import { KibanaFeature } from '../../../../../../../../features/public'; // Note: these tests are not concerned with the proper display of privileges, // as that is verified by the feature_table and privilege_space_form tests. diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/sub_feature_form.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/sub_feature_form.tsx index 4cf8c49a4ec8a..494f3ec7d9acb 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/sub_feature_form.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/sub_feature_form.tsx @@ -5,17 +5,18 @@ * 2.0. */ +import { EuiButtonGroup, EuiCheckbox, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; import React from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiText, EuiCheckbox, EuiButtonGroup } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { NO_PRIVILEGE_VALUE } from '../constants'; -import { PrivilegeFormCalculator } from '../privilege_form_calculator'; -import { + +import type { SecuredSubFeature, - SubFeaturePrivilegeGroup, SubFeaturePrivilege, + SubFeaturePrivilegeGroup, } from '../../../../model'; +import { NO_PRIVILEGE_VALUE } from '../constants'; +import type { PrivilegeFormCalculator } from '../privilege_form_calculator'; interface Props { featureId: string; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.test.tsx index 18e015964c355..dcd2170325006 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.test.tsx @@ -5,12 +5,14 @@ * 2.0. */ +import { EuiIconTip } from '@elastic/eui'; import React from 'react'; -import { createFeature } from '../../../../__fixtures__/kibana_features'; + import { mountWithIntl } from '@kbn/test/jest'; -import { FeatureTableCell } from '.'; + +import { createFeature } from '../../../../__fixtures__/kibana_features'; import { SecuredFeature } from '../../../../model'; -import { EuiIconTip } from '@elastic/eui'; +import { FeatureTableCell } from './feature_table_cell'; describe('FeatureTableCell', () => { it('renders the feature name', () => { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.tsx index b9634939eee76..507416b51f9b6 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table_cell/feature_table_cell.tsx @@ -5,9 +5,10 @@ * 2.0. */ +import { EuiIconTip, EuiText } from '@elastic/eui'; import React from 'react'; -import { EuiText, EuiIconTip } from '@elastic/eui'; -import { SecuredFeature } from '../../../../model'; + +import type { SecuredFeature } from '../../../../model'; interface Props { feature: SecuredFeature; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/kibana_privileges_region.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/kibana_privileges_region.test.tsx index 4f08547c13d15..e27c2eb748560 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/kibana_privileges_region.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/kibana_privileges_region.test.tsx @@ -7,13 +7,14 @@ import { shallow } from 'enzyme'; import React from 'react'; -import { Role } from '../../../../../../common/model'; + +import type { Role } from '../../../../../../common/model'; +import { KibanaPrivileges } from '../../../model'; import { RoleValidator } from '../../validate_role'; import { KibanaPrivilegesRegion } from './kibana_privileges_region'; import { SimplePrivilegeSection } from './simple_privilege_section'; -import { TransformErrorSection } from './transform_error_section'; import { SpaceAwarePrivilegeSection } from './space_aware_privilege_section'; -import { KibanaPrivileges } from '../../../model'; +import { TransformErrorSection } from './transform_error_section'; const buildProps = (customProps = {}) => { return { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/kibana_privileges_region.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/kibana_privileges_region.tsx index 308fe673c1cdb..486b1c8bc1d03 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/kibana_privileges_region.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/kibana_privileges_region.tsx @@ -6,16 +6,18 @@ */ import React, { Component } from 'react'; -import { Capabilities } from 'src/core/public'; + +import type { Capabilities } from 'src/core/public'; import type { SpacesApiUi } from 'src/plugins/spaces_oss/public'; -import { Space } from '../../../../../../../spaces/public'; -import { Role } from '../../../../../../common/model'; -import { RoleValidator } from '../../validate_role'; + +import type { Space } from '../../../../../../../spaces/public'; +import type { Role } from '../../../../../../common/model'; +import type { KibanaPrivileges } from '../../../model'; import { CollapsiblePanel } from '../../collapsible_panel'; +import type { RoleValidator } from '../../validate_role'; import { SimplePrivilegeSection } from './simple_privilege_section'; import { SpaceAwarePrivilegeSection } from './space_aware_privilege_section'; import { TransformErrorSection } from './transform_error_section'; -import { KibanaPrivileges } from '../../../model'; interface Props { role: Role; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_form_calculator/privilege_form_calculator.test.ts b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_form_calculator/privilege_form_calculator.test.ts index e8220b726a1b1..a640c5cbbf087 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_form_calculator/privilege_form_calculator.test.ts +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_form_calculator/privilege_form_calculator.test.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; +import type { Role } from '../../../../../../../common/model'; import { kibanaFeatures } from '../../../../__fixtures__/kibana_features'; -import { Role } from '../../../../../../../common/model'; +import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; import { PrivilegeFormCalculator } from './privilege_form_calculator'; const createRole = (kibana: Role['kibana'] = []): Role => { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_form_calculator/privilege_form_calculator.ts b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_form_calculator/privilege_form_calculator.ts index 09374d13ad38e..f92d959a7208f 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_form_calculator/privilege_form_calculator.ts +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_form_calculator/privilege_form_calculator.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { Role } from '../../../../../../../common/model'; +import type { Role } from '../../../../../../../common/model'; +import type { KibanaPrivileges, SubFeaturePrivilegeGroup } from '../../../../model'; import { isGlobalPrivilegeDefinition } from '../../../privilege_utils'; -import { KibanaPrivileges, SubFeaturePrivilegeGroup } from '../../../../model'; /** * Calculator responsible for determining the displayed and effective privilege values for the following interfaces: diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/__fixtures__/index.ts b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/__fixtures__/index.ts index 7e0ae311433b1..6f5c729784bb1 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/__fixtures__/index.ts +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/__fixtures__/index.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { ReactWrapper } from 'enzyme'; - import { EuiTableRow } from '@elastic/eui'; +import type { ReactWrapper } from 'enzyme'; import { findTestSubject } from '@kbn/test/jest'; -import { Role, RoleKibanaPrivilege } from '../../../../../../../../common/model'; -import { PrivilegeSummaryExpandedRow } from '../privilege_summary_expanded_row'; + +import type { Role, RoleKibanaPrivilege } from '../../../../../../../../common/model'; import { FeatureTableCell } from '../../feature_table_cell'; +import { PrivilegeSummaryExpandedRow } from '../privilege_summary_expanded_row'; interface DisplayedFeaturePrivileges { [featureId: string]: { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary.test.tsx index e4ff169ed20df..b23566019b31a 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary.test.tsx @@ -5,17 +5,19 @@ * 2.0. */ +import { act } from '@testing-library/react'; import React from 'react'; -import { mountWithIntl } from '@kbn/test/jest'; + +import { findTestSubject, mountWithIntl } from '@kbn/test/jest'; +import { coreMock } from 'src/core/public/mocks'; + import { spacesManagerMock } from '../../../../../../../../spaces/public/spaces_manager/mocks'; import { getUiApi } from '../../../../../../../../spaces/public/ui_api'; -import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; +import type { RoleKibanaPrivilege } from '../../../../../../../common/model'; import { kibanaFeatures } from '../../../../__fixtures__/kibana_features'; -import { RoleKibanaPrivilege } from '../../../../../../../common/model'; -import { PrivilegeSummary } from '.'; -import { findTestSubject } from '@kbn/test/jest'; +import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; +import { PrivilegeSummary } from './privilege_summary'; import { PrivilegeSummaryTable } from './privilege_summary_table'; -import { coreMock } from 'src/core/public/mocks'; const createRole = (roleKibanaPrivileges: RoleKibanaPrivilege[]) => ({ name: 'some-role', @@ -64,7 +66,7 @@ describe('PrivilegeSummary', () => { expect(wrapper.find(PrivilegeSummaryTable)).toHaveLength(0); }); - it('clicking the button renders the privilege summary table', () => { + it('clicking the button renders the privilege summary table', async () => { const kibanaPrivileges = createKibanaPrivileges(kibanaFeatures); const role = createRole([ @@ -85,7 +87,10 @@ describe('PrivilegeSummary', () => { /> ); - findTestSubject(wrapper, 'viewPrivilegeSummaryButton').simulate('click'); + await act(async () => { + findTestSubject(wrapper, 'viewPrivilegeSummaryButton').simulate('click'); + }); + wrapper.update(); expect(wrapper.find(PrivilegeSummaryTable)).toHaveLength(1); }); }); diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary.tsx index ebe2dc6a164c2..749c1c8ccb4e2 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary.tsx @@ -5,16 +5,25 @@ * 2.0. */ -import React, { useState, Fragment } from 'react'; +import { + EuiButton, + EuiButtonEmpty, + EuiFlyout, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiFlyoutHeader, + EuiOverlayMask, + EuiTitle, +} from '@elastic/eui'; +import React, { Fragment, useState } from 'react'; + import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiButtonEmpty, EuiOverlayMask, EuiButton } from '@elastic/eui'; -import { EuiFlyout } from '@elastic/eui'; -import { EuiFlyoutHeader, EuiTitle, EuiFlyoutBody, EuiFlyoutFooter } from '@elastic/eui'; import type { SpacesApiUi } from 'src/plugins/spaces_oss/public'; -import { Space } from '../../../../../../../../spaces/public'; -import { Role } from '../../../../../../../common/model'; + +import type { Space } from '../../../../../../../../spaces/public'; +import type { Role } from '../../../../../../../common/model'; +import type { KibanaPrivileges } from '../../../../model'; import { PrivilegeSummaryTable } from './privilege_summary_table'; -import { KibanaPrivileges } from '../../../../model'; interface Props { role: Role; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_calculator.test.ts b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_calculator.test.ts index 7950bb4e91451..a6714cb7a2d83 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_calculator.test.ts +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_calculator.test.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { Role } from '../../../../../../../common/model'; -import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; +import type { Role } from '../../../../../../../common/model'; import { kibanaFeatures } from '../../../../__fixtures__/kibana_features'; +import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; import { PrivilegeSummaryCalculator } from './privilege_summary_calculator'; const createRole = (kibana: Role['kibana'] = []): Role => { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_calculator.ts b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_calculator.ts index e56d5e21c278e..14e2241cdf830 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_calculator.ts +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_calculator.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { Role, RoleKibanaPrivilege } from '../../../../../../../common/model'; +import type { Role, RoleKibanaPrivilege } from '../../../../../../../common/model'; +import type { KibanaPrivileges, PrimaryFeaturePrivilege, SecuredFeature } from '../../../../model'; +import type { PrivilegeCollection } from '../../../../model/privilege_collection'; import { isGlobalPrivilegeDefinition } from '../../../privilege_utils'; -import { KibanaPrivileges, PrimaryFeaturePrivilege, SecuredFeature } from '../../../../model'; -import { PrivilegeCollection } from '../../../../model/privilege_collection'; export interface EffectiveFeaturePrivileges { [featureId: string]: { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_expanded_row.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_expanded_row.tsx index 63ef3b0993af0..d81af7ae9de87 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_expanded_row.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_expanded_row.tsx @@ -5,11 +5,17 @@ * 2.0. */ +import { EuiFlexGroup, EuiFlexItem, EuiIconTip, EuiText } from '@elastic/eui'; import React from 'react'; + import { i18n } from '@kbn/i18n'; -import { EuiFlexGroup, EuiFlexItem, EuiText, EuiIconTip } from '@elastic/eui'; -import { SecuredFeature, SubFeaturePrivilegeGroup, SubFeaturePrivilege } from '../../../../model'; -import { EffectiveFeaturePrivileges } from './privilege_summary_calculator'; + +import type { + SecuredFeature, + SubFeaturePrivilege, + SubFeaturePrivilegeGroup, +} from '../../../../model'; +import type { EffectiveFeaturePrivileges } from './privilege_summary_calculator'; interface Props { feature: SecuredFeature; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_table.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_table.test.tsx index 1042eea3b0525..53a7084c7014e 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_table.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_table.test.tsx @@ -7,15 +7,18 @@ import { act } from '@testing-library/react'; import React from 'react'; + +import { mountWithIntl } from '@kbn/test/jest'; +import { coreMock } from 'src/core/public/mocks'; + import { spacesManagerMock } from '../../../../../../../../spaces/public/spaces_manager/mocks'; import { getUiApi } from '../../../../../../../../spaces/public/ui_api'; -import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; +import type { RoleKibanaPrivilege } from '../../../../../../../common/model'; import { kibanaFeatures } from '../../../../__fixtures__/kibana_features'; -import { mountWithIntl } from '@kbn/test/jest'; -import { PrivilegeSummaryTable, PrivilegeSummaryTableProps } from './privilege_summary_table'; -import { RoleKibanaPrivilege } from '../../../../../../../common/model'; +import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; import { getDisplayedFeaturePrivileges } from './__fixtures__'; -import { coreMock } from 'src/core/public/mocks'; +import type { PrivilegeSummaryTableProps } from './privilege_summary_table'; +import { PrivilegeSummaryTable } from './privilege_summary_table'; const createRole = (roleKibanaPrivileges: RoleKibanaPrivilege[]) => ({ name: 'some-role', diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_table.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_table.tsx index 693343889476a..582a7d6c5427e 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_table.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/privilege_summary_table.tsx @@ -5,32 +5,32 @@ * 2.0. */ -import React, { useMemo, useState, Fragment } from 'react'; -import { FormattedMessage } from '@kbn/i18n/react'; +import type { EuiBasicTableColumn } from '@elastic/eui'; import { + EuiAccordion, + EuiButtonIcon, EuiFlexGroup, EuiFlexItem, - EuiInMemoryTable, - EuiBasicTableColumn, - EuiButtonIcon, EuiIcon, EuiIconTip, + EuiInMemoryTable, EuiSpacer, - EuiAccordion, EuiTitle, } from '@elastic/eui'; +import React, { Fragment, useMemo, useState } from 'react'; + +import { FormattedMessage } from '@kbn/i18n/react'; import type { SpacesApiUi } from 'src/plugins/spaces_oss/public'; -import { Space } from '../../../../../../../../spaces/public'; -import { Role, RoleKibanaPrivilege } from '../../../../../../../common/model'; + +import type { Space } from '../../../../../../../../spaces/public'; +import type { Role, RoleKibanaPrivilege } from '../../../../../../../common/model'; +import type { KibanaPrivileges, SecuredFeature } from '../../../../model'; import { isGlobalPrivilegeDefinition } from '../../../privilege_utils'; import { FeatureTableCell } from '../feature_table_cell'; -import { SpaceColumnHeader } from './space_column_header'; +import type { EffectiveFeaturePrivileges } from './privilege_summary_calculator'; +import { PrivilegeSummaryCalculator } from './privilege_summary_calculator'; import { PrivilegeSummaryExpandedRow } from './privilege_summary_expanded_row'; -import { SecuredFeature, KibanaPrivileges } from '../../../../model'; -import { - PrivilegeSummaryCalculator, - EffectiveFeaturePrivileges, -} from './privilege_summary_calculator'; +import { SpaceColumnHeader } from './space_column_header'; export interface PrivilegeSummaryTableProps { role: Role; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/space_column_header.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/space_column_header.test.tsx index 12eac1852c212..77c8cdd69ec44 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/space_column_header.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/space_column_header.test.tsx @@ -7,14 +7,16 @@ import { act } from '@testing-library/react'; import React from 'react'; + import { mountWithIntl } from '@kbn/test/jest'; +import { coreMock } from 'src/core/public/mocks'; + +import { SpaceAvatarInternal } from '../../../../../../../../spaces/public/space_avatar/space_avatar_internal'; import { spacesManagerMock } from '../../../../../../../../spaces/public/spaces_manager/mocks'; import { getUiApi } from '../../../../../../../../spaces/public/ui_api'; -import { SpaceAvatarInternal } from '../../../../../../../../spaces/public/space_avatar/space_avatar_internal'; import type { RoleKibanaPrivilege } from '../../../../../../../common/model'; -import { SpaceColumnHeader } from './space_column_header'; import { SpacesPopoverList } from '../../../spaces_popover_list'; -import { coreMock } from 'src/core/public/mocks'; +import { SpaceColumnHeader } from './space_column_header'; const spaces = [ { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/space_column_header.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/space_column_header.tsx index 3c200fedf6ce0..fd535d20de557 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/space_column_header.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/privilege_summary/space_column_header.tsx @@ -6,11 +6,13 @@ */ import React, { Fragment, useMemo } from 'react'; -import { FormattedMessage } from '@kbn/i18n/react'; + import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import type { Space } from 'src/plugins/spaces_oss/common'; import type { SpacesApiUi } from 'src/plugins/spaces_oss/public'; -import { RoleKibanaPrivilege } from '../../../../../../../common/model'; + +import type { RoleKibanaPrivilege } from '../../../../../../../common/model'; import { isGlobalPrivilegeDefinition } from '../../../privilege_utils'; import { SpacesPopoverList } from '../../../spaces_popover_list'; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/privilege_selector.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/privilege_selector.tsx index d3734675babfc..72061958ecc35 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/privilege_selector.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/privilege_selector.tsx @@ -6,7 +6,9 @@ */ import { EuiSelect } from '@elastic/eui'; -import React, { ChangeEvent, Component } from 'react'; +import type { ChangeEvent } from 'react'; +import React, { Component } from 'react'; + import { NO_PRIVILEGE_VALUE } from '../constants'; interface Props { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.test.tsx index 309391093929f..bb7124b6c8876 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.test.tsx @@ -5,13 +5,16 @@ * 2.0. */ -import { EuiButtonGroup, EuiButtonGroupProps, EuiComboBox, EuiSuperSelect } from '@elastic/eui'; +import type { EuiButtonGroupProps } from '@elastic/eui'; +import { EuiButtonGroup, EuiComboBox, EuiSuperSelect } from '@elastic/eui'; import React from 'react'; + import { mountWithIntl, shallowWithIntl } from '@kbn/test/jest'; -import { Role } from '../../../../../../../common/model'; + +import type { Role } from '../../../../../../../common/model'; +import { KibanaPrivileges, SecuredFeature } from '../../../../model'; import { SimplePrivilegeSection } from './simple_privilege_section'; import { UnsupportedSpacePrivilegesWarning } from './unsupported_space_privileges_warning'; -import { KibanaPrivileges, SecuredFeature } from '../../../../model'; const buildProps = (customProps: any = {}) => { const features = [ diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.tsx index fc0468dc4c615..dd1304ebdaac2 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.tsx @@ -7,21 +7,24 @@ import { EuiComboBox, + EuiFlexGroup, + EuiFlexItem, EuiFormRow, EuiSuperSelect, EuiText, - EuiFlexGroup, - EuiFlexItem, } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; import React, { Component, Fragment } from 'react'; -import { Role, RoleKibanaPrivilege, copyRole } from '../../../../../../../common/model'; + +import { FormattedMessage } from '@kbn/i18n/react'; + +import type { Role, RoleKibanaPrivilege } from '../../../../../../../common/model'; +import { copyRole } from '../../../../../../../common/model'; +import type { KibanaPrivileges } from '../../../../model'; import { isGlobalPrivilegeDefinition } from '../../../privilege_utils'; import { CUSTOM_PRIVILEGE_VALUE, NO_PRIVILEGE_VALUE } from '../constants'; import { FeatureTable } from '../feature_table'; -import { UnsupportedSpacePrivilegesWarning } from './unsupported_space_privileges_warning'; -import { KibanaPrivileges } from '../../../../model'; import { PrivilegeFormCalculator } from '../privilege_form_calculator'; +import { UnsupportedSpacePrivilegesWarning } from './unsupported_space_privileges_warning'; interface Props { role: Role; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/unsupported_space_privileges_warning.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/unsupported_space_privileges_warning.tsx index 39ebcafb435c2..6a81d22aceeb6 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/unsupported_space_privileges_warning.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/unsupported_space_privileges_warning.tsx @@ -6,9 +6,10 @@ */ import { EuiCallOut } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; import React, { Component } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; + export class UnsupportedSpacePrivilegesWarning extends Component<{}, {}> { public render() { return ; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_display.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_display.test.tsx index 993e7eb2c05f4..8aa2b77f8fc12 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_display.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_display.test.tsx @@ -7,7 +7,9 @@ import { EuiText } from '@elastic/eui'; import React from 'react'; + import { mountWithIntl } from '@kbn/test/jest'; + import { PrivilegeDisplay } from './privilege_display'; describe('PrivilegeDisplay', () => { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_display.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_display.tsx index c412b86f488f3..52e61c6e92603 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_display.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_display.tsx @@ -5,9 +5,12 @@ * 2.0. */ -import { EuiIcon, EuiText, PropsOf } from '@elastic/eui'; +import type { PropsOf } from '@elastic/eui'; +import { EuiIcon, EuiText } from '@elastic/eui'; import _ from 'lodash'; -import React, { ReactNode, FC } from 'react'; +import type { FC, ReactNode } from 'react'; +import React from 'react'; + import { NO_PRIVILEGE_VALUE } from '../constants'; interface Props extends PropsOf { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx index 2d79a8354645d..9312a2eb78018 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx @@ -5,18 +5,19 @@ * 2.0. */ -import { Role } from '../../../../../../../common/model'; -import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; -import { kibanaFeatures } from '../../../../__fixtures__/kibana_features'; -import { mountWithIntl } from '@kbn/test/jest'; -import { PrivilegeSpaceForm } from './privilege_space_form'; +import { EuiButtonGroup } from '@elastic/eui'; import React from 'react'; -import { Space } from '../../../../../../../../spaces/public'; + +import { findTestSubject, mountWithIntl } from '@kbn/test/jest'; + +import type { Space } from '../../../../../../../../spaces/public'; +import type { Role } from '../../../../../../../common/model'; +import { kibanaFeatures } from '../../../../__fixtures__/kibana_features'; +import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; import { FeatureTable } from '../feature_table'; import { getDisplayedFeaturePrivileges } from '../feature_table/__fixtures__'; -import { findTestSubject } from '@kbn/test/jest'; +import { PrivilegeSpaceForm } from './privilege_space_form'; import { SpaceSelector } from './space_selector'; -import { EuiButtonGroup } from '@elastic/eui'; const createRole = (kibana: Role['kibana'] = []): Role => { return { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.tsx index e146af39245f9..b290cb301866d 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.tsx @@ -5,11 +5,13 @@ * 2.0. */ +import type { ButtonColor } from '@elastic/eui'; import { - ButtonColor, EuiButton, EuiButtonEmpty, + EuiButtonGroup, EuiCallOut, + EuiErrorBoundary, EuiFlexGroup, EuiFlexItem, EuiFlyout, @@ -22,19 +24,20 @@ import { EuiSpacer, EuiText, EuiTitle, - EuiErrorBoundary, } from '@elastic/eui'; +import React, { Component, Fragment } from 'react'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import React, { Component, Fragment } from 'react'; -import { EuiButtonGroup } from '@elastic/eui'; -import { Space } from '../../../../../../../../spaces/public'; -import { Role, copyRole } from '../../../../../../../common/model'; -import { SpaceSelector } from './space_selector'; -import { FeatureTable } from '../feature_table'; + +import type { Space } from '../../../../../../../../spaces/public'; +import type { Role } from '../../../../../../../common/model'; +import { copyRole } from '../../../../../../../common/model'; +import type { KibanaPrivileges } from '../../../../model'; import { CUSTOM_PRIVILEGE_VALUE } from '../constants'; +import { FeatureTable } from '../feature_table'; import { PrivilegeFormCalculator } from '../privilege_form_calculator'; -import { KibanaPrivileges } from '../../../../model'; +import { SpaceSelector } from './space_selector'; interface Props { role: Role; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.test.tsx index e1af748c8545a..4c657294c965c 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.test.tsx @@ -5,17 +5,18 @@ * 2.0. */ -import React from 'react'; import { EuiBadge, EuiInMemoryTable } from '@elastic/eui'; -import { mountWithIntl } from '@kbn/test/jest'; -import { ReactWrapper } from 'enzyme'; -import { PrivilegeSpaceTable } from './privilege_space_table'; -import { PrivilegeDisplay } from './privilege_display'; -import { Role, RoleKibanaPrivilege } from '../../../../../../../common/model'; +import type { ReactWrapper } from 'enzyme'; +import React from 'react'; + +import { findTestSubject, mountWithIntl } from '@kbn/test/jest'; + +import { KibanaFeature } from '../../../../../../../../features/public'; +import type { Role, RoleKibanaPrivilege } from '../../../../../../../common/model'; import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; import { PrivilegeFormCalculator } from '../privilege_form_calculator'; -import { KibanaFeature } from '../../../../../../../../features/public'; -import { findTestSubject } from '@kbn/test/jest'; +import { PrivilegeDisplay } from './privilege_display'; +import { PrivilegeSpaceTable } from './privilege_space_table'; interface TableRow { spaces: string[]; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.tsx index 0bf59feffebe8..f6f26141383f4 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.tsx @@ -7,27 +7,30 @@ import './privilege_space_table.scss'; +import type { EuiBadgeProps, EuiBasicTableColumn } from '@elastic/eui'; import { EuiBadge, - EuiBadgeProps, EuiButtonEmpty, EuiButtonIcon, - EuiInMemoryTable, - EuiBasicTableColumn, - EuiIcon, - EuiIconTip, EuiFlexGroup, EuiFlexItem, + EuiIcon, + EuiIconTip, + EuiInMemoryTable, } from '@elastic/eui'; +import React, { Component } from 'react'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import React, { Component } from 'react'; -import { Space, getSpaceColor } from '../../../../../../../../spaces/public'; -import { FeaturesPrivileges, Role, copyRole } from '../../../../../../../common/model'; -import { PrivilegeDisplay } from './privilege_display'; + +import type { Space } from '../../../../../../../../spaces/public'; +import { getSpaceColor } from '../../../../../../../../spaces/public'; +import type { FeaturesPrivileges, Role } from '../../../../../../../common/model'; +import { copyRole } from '../../../../../../../common/model'; import { isGlobalPrivilegeDefinition } from '../../../privilege_utils'; -import { PrivilegeFormCalculator } from '../privilege_form_calculator'; import { CUSTOM_PRIVILEGE_VALUE } from '../constants'; +import type { PrivilegeFormCalculator } from '../privilege_form_calculator'; +import { PrivilegeDisplay } from './privilege_display'; const SPACES_DISPLAY_COUNT = 4; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/space_aware_privilege_section.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/space_aware_privilege_section.test.tsx index 11c8e5585c9d5..ebc82f28f5426 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/space_aware_privilege_section.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/space_aware_privilege_section.test.tsx @@ -6,14 +6,16 @@ */ import React from 'react'; + import { mountWithIntl, shallowWithIntl } from '@kbn/test/jest'; + +import { kibanaFeatures } from '../../../../__fixtures__/kibana_features'; +import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; import { RoleValidator } from '../../../validate_role'; +import { PrivilegeSummary } from '../privilege_summary'; import { PrivilegeSpaceForm } from './privilege_space_form'; import { PrivilegeSpaceTable } from './privilege_space_table'; import { SpaceAwarePrivilegeSection } from './space_aware_privilege_section'; -import { PrivilegeSummary } from '../privilege_summary'; -import { createKibanaPrivileges } from '../../../../__fixtures__/kibana_privileges'; -import { kibanaFeatures } from '../../../../__fixtures__/kibana_features'; const buildProps = (customProps: any = {}) => { return { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/space_aware_privilege_section.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/space_aware_privilege_section.tsx index ae0a6a503c73a..08c220b54f471 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/space_aware_privilege_section.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/space_aware_privilege_section.tsx @@ -9,25 +9,28 @@ import { EuiButton, EuiCallOut, EuiEmptyPrompt, + EuiErrorBoundary, EuiFlexGroup, EuiFlexItem, EuiSpacer, - EuiErrorBoundary, } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; import _ from 'lodash'; import React, { Component, Fragment } from 'react'; -import { Capabilities } from 'src/core/public'; + +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import type { Capabilities } from 'src/core/public'; import type { SpacesApiUi } from 'src/plugins/spaces_oss/public'; -import { Space } from '../../../../../../../../spaces/public'; -import { Role, isRoleReserved } from '../../../../../../../common/model'; -import { RoleValidator } from '../../../validate_role'; -import { PrivilegeSpaceTable } from './privilege_space_table'; -import { PrivilegeSpaceForm } from './privilege_space_form'; + +import type { Space } from '../../../../../../../../spaces/public'; +import type { Role } from '../../../../../../../common/model'; +import { isRoleReserved } from '../../../../../../../common/model'; +import type { KibanaPrivileges } from '../../../../model'; +import type { RoleValidator } from '../../../validate_role'; import { PrivilegeFormCalculator } from '../privilege_form_calculator'; import { PrivilegeSummary } from '../privilege_summary'; -import { KibanaPrivileges } from '../../../../model'; +import { PrivilegeSpaceForm } from './privilege_space_form'; +import { PrivilegeSpaceTable } from './privilege_space_table'; interface Props { kibanaPrivileges: KibanaPrivileges; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/space_selector.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/space_selector.tsx index 99b15edb6563f..3e84e02a00008 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/space_selector.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/space_selector.tsx @@ -5,10 +5,14 @@ * 2.0. */ -import { EuiComboBox, EuiComboBoxOptionOption, EuiHealth, EuiHighlight } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; +import type { EuiComboBoxOptionOption } from '@elastic/eui'; +import { EuiComboBox, EuiHealth, EuiHighlight } from '@elastic/eui'; import React, { Component } from 'react'; -import { getSpaceColor, Space } from '../../../../../../../../spaces/public'; + +import { i18n } from '@kbn/i18n'; + +import type { Space } from '../../../../../../../../spaces/public'; +import { getSpaceColor } from '../../../../../../../../spaces/public'; const spaceToOption = (space?: Space, currentSelection?: 'global' | 'spaces') => { if (!space) { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/transform_error_section/transform_error_section.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/transform_error_section/transform_error_section.tsx index 3a06f69ca795e..962fee3ffdc4d 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/transform_error_section/transform_error_section.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/transform_error_section/transform_error_section.tsx @@ -6,9 +6,10 @@ */ import { EuiEmptyPrompt } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; import React, { PureComponent } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; + export class TransformErrorSection extends PureComponent<{}, {}> { public render() { return ( diff --git a/x-pack/plugins/security/public/management/roles/edit_role/reserved_role_badge.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/reserved_role_badge.test.tsx index 84bc51e765e67..3145c43f2be42 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/reserved_role_badge.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/reserved_role_badge.test.tsx @@ -8,7 +8,8 @@ import { EuiIcon } from '@elastic/eui'; import { shallow } from 'enzyme'; import React from 'react'; -import { Role } from '../../../../common/model'; + +import type { Role } from '../../../../common/model'; import { ReservedRoleBadge } from './reserved_role_badge'; const reservedRole: Role = { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/reserved_role_badge.tsx b/x-pack/plugins/security/public/management/roles/edit_role/reserved_role_badge.tsx index 85d575d38ff6f..8445fa4e7569a 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/reserved_role_badge.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/reserved_role_badge.tsx @@ -5,11 +5,13 @@ * 2.0. */ +import { EuiIcon, EuiToolTip } from '@elastic/eui'; import React from 'react'; -import { EuiIcon, EuiToolTip } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { Role, isRoleReserved } from '../../../../common/model'; + +import type { Role } from '../../../../common/model'; +import { isRoleReserved } from '../../../../common/model'; interface Props { role: Role; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/spaces_popover_list.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/spaces_popover_list.test.tsx index a9b49eb2b137c..673346a6f1444 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/spaces_popover_list.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/spaces_popover_list.test.tsx @@ -5,22 +5,24 @@ * 2.0. */ -import { act } from '@testing-library/react'; -import React from 'react'; -import { mountWithIntl } from '@kbn/test/jest'; -import { SpacesPopoverList } from '.'; import { EuiButtonEmpty, - EuiContextMenuPanel, EuiContextMenuItem, + EuiContextMenuPanel, EuiFieldSearch, EuiPopover, } from '@elastic/eui'; +import { act } from '@testing-library/react'; +import React from 'react'; + +import { mountWithIntl } from '@kbn/test/jest'; +import { coreMock } from 'src/core/public/mocks'; import type { Space } from 'src/plugins/spaces_oss/common'; + +import { SpaceAvatarInternal } from '../../../../../../spaces/public/space_avatar/space_avatar_internal'; import { spacesManagerMock } from '../../../../../../spaces/public/spaces_manager/mocks'; import { getUiApi } from '../../../../../../spaces/public/ui_api'; -import { SpaceAvatarInternal } from '../../../../../../spaces/public/space_avatar/space_avatar_internal'; -import { coreMock } from 'src/core/public/mocks'; +import { SpacesPopoverList } from './spaces_popover_list'; const mockSpaces = [ { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/spaces_popover_list.tsx b/x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/spaces_popover_list.tsx index 783fbf03f766d..9861b008beb9f 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/spaces_popover_list.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/spaces_popover_list.tsx @@ -15,11 +15,13 @@ import { EuiPopover, EuiText, } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { i18n } from '@kbn/i18n'; import React, { Component, memo } from 'react'; + +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import type { Space } from 'src/plugins/spaces_oss/common'; import type { SpacesApiUi } from 'src/plugins/spaces_oss/public'; + import { SPACE_SEARCH_COUNT_THRESHOLD } from '../../../../../../spaces/common'; interface Props { diff --git a/x-pack/plugins/security/public/management/roles/edit_role/validate_role.test.ts b/x-pack/plugins/security/public/management/roles/edit_role/validate_role.test.ts index 780d393278fde..f508e444dc714 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/validate_role.test.ts +++ b/x-pack/plugins/security/public/management/roles/edit_role/validate_role.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Role } from '../../../../common/model'; +import type { Role } from '../../../../common/model'; import { RoleValidator } from './validate_role'; let validator: RoleValidator; diff --git a/x-pack/plugins/security/public/management/roles/edit_role/validate_role.ts b/x-pack/plugins/security/public/management/roles/edit_role/validate_role.ts index e70aba7308e43..ac509dba353d2 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/validate_role.ts +++ b/x-pack/plugins/security/public/management/roles/edit_role/validate_role.ts @@ -6,8 +6,9 @@ */ import { i18n } from '@kbn/i18n'; -import { Role, RoleIndexPrivilege } from '../../../../common/model'; -import { NAME_REGEX, MAX_NAME_LENGTH } from '../../../../common/constants'; + +import { MAX_NAME_LENGTH, NAME_REGEX } from '../../../../common/constants'; +import type { Role, RoleIndexPrivilege } from '../../../../common/model'; interface RoleValidatorOptions { shouldValidate?: boolean; diff --git a/x-pack/plugins/security/public/management/roles/indices_api_client.ts b/x-pack/plugins/security/public/management/roles/indices_api_client.ts index b55382332dec2..ebec4d858d7ad 100644 --- a/x-pack/plugins/security/public/management/roles/indices_api_client.ts +++ b/x-pack/plugins/security/public/management/roles/indices_api_client.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { HttpStart } from 'src/core/public'; +import type { HttpStart } from 'src/core/public'; export class IndicesAPIClient { constructor(private readonly http: HttpStart) {} diff --git a/x-pack/plugins/security/public/management/roles/model/kibana_privileges.test.ts b/x-pack/plugins/security/public/management/roles/model/kibana_privileges.test.ts index 4697481c4021d..7d26a08511e40 100644 --- a/x-pack/plugins/security/public/management/roles/model/kibana_privileges.test.ts +++ b/x-pack/plugins/security/public/management/roles/model/kibana_privileges.test.ts @@ -5,11 +5,11 @@ * 2.0. */ -import { createRawKibanaPrivileges } from '../__fixtures__/kibana_privileges'; +import type { RoleKibanaPrivilege } from '../../../../common/model'; import { kibanaFeatures } from '../__fixtures__/kibana_features'; -import { KibanaPrivileges } from './kibana_privileges'; -import { RoleKibanaPrivilege } from '../../../../common/model'; +import { createRawKibanaPrivileges } from '../__fixtures__/kibana_privileges'; import { KibanaPrivilege } from './kibana_privilege'; +import { KibanaPrivileges } from './kibana_privileges'; describe('KibanaPrivileges', () => { describe('#getBasePrivileges', () => { diff --git a/x-pack/plugins/security/public/management/roles/model/kibana_privileges.ts b/x-pack/plugins/security/public/management/roles/model/kibana_privileges.ts index ba6070393e255..c2dd66172f751 100644 --- a/x-pack/plugins/security/public/management/roles/model/kibana_privileges.ts +++ b/x-pack/plugins/security/public/management/roles/model/kibana_privileges.ts @@ -5,12 +5,12 @@ * 2.0. */ -import { RawKibanaPrivileges, RoleKibanaPrivilege } from '../../../../common/model'; +import type { KibanaFeature } from '../../../../../features/common'; +import type { RawKibanaPrivileges, RoleKibanaPrivilege } from '../../../../common/model'; +import { isGlobalPrivilegeDefinition } from '../edit_role/privilege_utils'; import { KibanaPrivilege } from './kibana_privilege'; import { PrivilegeCollection } from './privilege_collection'; import { SecuredFeature } from './secured_feature'; -import { KibanaFeature } from '../../../../../features/common'; -import { isGlobalPrivilegeDefinition } from '../edit_role/privilege_utils'; function toBasePrivilege(entry: [string, string[]]): [string, KibanaPrivilege] { const [privilegeId, actions] = entry; diff --git a/x-pack/plugins/security/public/management/roles/model/primary_feature_privilege.ts b/x-pack/plugins/security/public/management/roles/model/primary_feature_privilege.ts index 4d711297821e6..323575862de52 100644 --- a/x-pack/plugins/security/public/management/roles/model/primary_feature_privilege.ts +++ b/x-pack/plugins/security/public/management/roles/model/primary_feature_privilege.ts @@ -5,8 +5,8 @@ * 2.0. */ +import type { FeatureKibanaPrivileges } from '../../../../../features/public'; import { KibanaPrivilege } from './kibana_privilege'; -import { FeatureKibanaPrivileges } from '../../../../../features/public'; export class PrimaryFeaturePrivilege extends KibanaPrivilege { constructor( diff --git a/x-pack/plugins/security/public/management/roles/model/privilege_collection.ts b/x-pack/plugins/security/public/management/roles/model/privilege_collection.ts index 3d57f1fe875d6..e08b7d849402a 100644 --- a/x-pack/plugins/security/public/management/roles/model/privilege_collection.ts +++ b/x-pack/plugins/security/public/management/roles/model/privilege_collection.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { KibanaPrivilege } from './kibana_privilege'; +import type { KibanaPrivilege } from './kibana_privilege'; export class PrivilegeCollection { private actions: ReadonlySet; diff --git a/x-pack/plugins/security/public/management/roles/model/secured_feature.ts b/x-pack/plugins/security/public/management/roles/model/secured_feature.ts index 917ce634a2543..c5d879b9d2d54 100644 --- a/x-pack/plugins/security/public/management/roles/model/secured_feature.ts +++ b/x-pack/plugins/security/public/management/roles/model/secured_feature.ts @@ -5,10 +5,11 @@ * 2.0. */ -import { KibanaFeature, KibanaFeatureConfig } from '../../../../../features/common'; +import type { KibanaFeatureConfig } from '../../../../../features/common'; +import { KibanaFeature } from '../../../../../features/common'; import { PrimaryFeaturePrivilege } from './primary_feature_privilege'; import { SecuredSubFeature } from './secured_sub_feature'; -import { SubFeaturePrivilege } from './sub_feature_privilege'; +import type { SubFeaturePrivilege } from './sub_feature_privilege'; export class SecuredFeature extends KibanaFeature { private readonly primaryFeaturePrivileges: PrimaryFeaturePrivilege[]; diff --git a/x-pack/plugins/security/public/management/roles/model/secured_sub_feature.ts b/x-pack/plugins/security/public/management/roles/model/secured_sub_feature.ts index a3bf49f1bd39d..d143d7f217547 100644 --- a/x-pack/plugins/security/public/management/roles/model/secured_sub_feature.ts +++ b/x-pack/plugins/security/public/management/roles/model/secured_sub_feature.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { SubFeature, SubFeatureConfig } from '../../../../../features/common'; +import type { SubFeatureConfig } from '../../../../../features/common'; +import { SubFeature } from '../../../../../features/common'; import { SubFeaturePrivilege } from './sub_feature_privilege'; import { SubFeaturePrivilegeGroup } from './sub_feature_privilege_group'; diff --git a/x-pack/plugins/security/public/management/roles/model/sub_feature_privilege.ts b/x-pack/plugins/security/public/management/roles/model/sub_feature_privilege.ts index e84153b6a6e72..a10c38cb3f818 100644 --- a/x-pack/plugins/security/public/management/roles/model/sub_feature_privilege.ts +++ b/x-pack/plugins/security/public/management/roles/model/sub_feature_privilege.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { SubFeaturePrivilegeConfig } from '../../../../../features/public'; +import type { SubFeaturePrivilegeConfig } from '../../../../../features/public'; import { KibanaPrivilege } from './kibana_privilege'; export class SubFeaturePrivilege extends KibanaPrivilege { diff --git a/x-pack/plugins/security/public/management/roles/model/sub_feature_privilege_group.ts b/x-pack/plugins/security/public/management/roles/model/sub_feature_privilege_group.ts index 6e2b61b439fea..ca18ef28e0a73 100644 --- a/x-pack/plugins/security/public/management/roles/model/sub_feature_privilege_group.ts +++ b/x-pack/plugins/security/public/management/roles/model/sub_feature_privilege_group.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { SubFeaturePrivilegeGroupConfig } from '../../../../../features/common'; +import type { SubFeaturePrivilegeGroupConfig } from '../../../../../features/common'; import { SubFeaturePrivilege } from './sub_feature_privilege'; export class SubFeaturePrivilegeGroup { diff --git a/x-pack/plugins/security/public/management/roles/privileges_api_client.ts b/x-pack/plugins/security/public/management/roles/privileges_api_client.ts index e9a6884790cba..0bb89eebb6b11 100644 --- a/x-pack/plugins/security/public/management/roles/privileges_api_client.ts +++ b/x-pack/plugins/security/public/management/roles/privileges_api_client.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { HttpStart } from 'src/core/public'; -import { BuiltinESPrivileges, RawKibanaPrivileges } from '../../../common/model'; +import type { HttpStart } from 'src/core/public'; + +import type { BuiltinESPrivileges, RawKibanaPrivileges } from '../../../common/model'; export class PrivilegesAPIClient { constructor(private readonly http: HttpStart) {} diff --git a/x-pack/plugins/security/public/management/roles/roles_api_client.test.ts b/x-pack/plugins/security/public/management/roles/roles_api_client.test.ts index b2d0b4d2b7755..3bae230377b84 100644 --- a/x-pack/plugins/security/public/management/roles/roles_api_client.test.ts +++ b/x-pack/plugins/security/public/management/roles/roles_api_client.test.ts @@ -5,9 +5,10 @@ * 2.0. */ -import { Role } from '../../../common/model'; +import { httpServiceMock } from 'src/core/public/mocks'; + +import type { Role } from '../../../common/model'; import { RolesAPIClient } from './roles_api_client'; -import { httpServiceMock } from '../../../../../../src/core/public/mocks'; describe('RolesAPIClient', () => { async function saveRole(role: Role, spacesEnabled: boolean) { diff --git a/x-pack/plugins/security/public/management/roles/roles_api_client.ts b/x-pack/plugins/security/public/management/roles/roles_api_client.ts index c9cd5c11b2e0f..aff3a7ccacd66 100644 --- a/x-pack/plugins/security/public/management/roles/roles_api_client.ts +++ b/x-pack/plugins/security/public/management/roles/roles_api_client.ts @@ -5,8 +5,10 @@ * 2.0. */ -import { HttpStart } from 'src/core/public'; -import { Role, RoleIndexPrivilege, copyRole } from '../../../common/model'; +import type { HttpStart } from 'src/core/public'; + +import type { Role, RoleIndexPrivilege } from '../../../common/model'; +import { copyRole } from '../../../common/model'; import { isGlobalPrivilegeDefinition } from './edit_role/privilege_utils'; export class RolesAPIClient { diff --git a/x-pack/plugins/security/public/management/roles/roles_grid/confirm_delete/confirm_delete.tsx b/x-pack/plugins/security/public/management/roles/roles_grid/confirm_delete/confirm_delete.tsx index 81302465bb373..e5ec22507925e 100644 --- a/x-pack/plugins/security/public/management/roles/roles_grid/confirm_delete/confirm_delete.tsx +++ b/x-pack/plugins/security/public/management/roles/roles_grid/confirm_delete/confirm_delete.tsx @@ -5,7 +5,6 @@ * 2.0. */ -import React, { Component, Fragment } from 'react'; import { EuiButton, EuiButtonEmpty, @@ -16,11 +15,14 @@ import { EuiModalHeaderTitle, EuiText, } from '@elastic/eui'; +import React, { Component, Fragment } from 'react'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import type { PublicMethodsOf } from '@kbn/utility-types'; -import { NotificationsStart } from 'src/core/public'; -import { RolesAPIClient } from '../../roles_api_client'; +import type { NotificationsStart } from 'src/core/public'; + +import type { RolesAPIClient } from '../../roles_api_client'; interface Props { rolesToDelete: string[]; diff --git a/x-pack/plugins/security/public/management/roles/roles_grid/permission_denied/permission_denied.tsx b/x-pack/plugins/security/public/management/roles/roles_grid/permission_denied/permission_denied.tsx index 43f7a6c671826..5506bce345ffb 100644 --- a/x-pack/plugins/security/public/management/roles/roles_grid/permission_denied/permission_denied.tsx +++ b/x-pack/plugins/security/public/management/roles/roles_grid/permission_denied/permission_denied.tsx @@ -6,9 +6,10 @@ */ import { EuiEmptyPrompt, EuiFlexGroup, EuiPageContent } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; import React from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; + export const PermissionDenied = () => ( diff --git a/x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.test.tsx b/x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.test.tsx index 025055d414a5c..9194fea271442 100644 --- a/x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.test.tsx +++ b/x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.test.tsx @@ -5,19 +5,19 @@ * 2.0. */ -import { EuiIcon, EuiBasicTable } from '@elastic/eui'; -import type { PublicMethodsOf } from '@kbn/utility-types'; -import { ReactWrapper } from 'enzyme'; +import { EuiBasicTable, EuiIcon } from '@elastic/eui'; +import type { ReactWrapper } from 'enzyme'; import React from 'react'; -import { mountWithIntl } from '@kbn/test/jest'; -import { RolesAPIClient } from '../roles_api_client'; -import { PermissionDenied } from './permission_denied'; -import { RolesGridPage } from './roles_grid_page'; -import { coreMock, scopedHistoryMock } from '../../../../../../../src/core/public/mocks'; +import { findTestSubject, mountWithIntl } from '@kbn/test/jest'; +import type { PublicMethodsOf } from '@kbn/utility-types'; +import { coreMock, scopedHistoryMock } from 'src/core/public/mocks'; + +import { DisabledBadge, ReservedBadge } from '../../badges'; import { rolesAPIClientMock } from '../index.mock'; -import { ReservedBadge, DisabledBadge } from '../../badges'; -import { findTestSubject } from '@kbn/test/jest'; +import type { RolesAPIClient } from '../roles_api_client'; +import { PermissionDenied } from './permission_denied'; +import { RolesGridPage } from './roles_grid_page'; const mock403 = () => ({ body: { statusCode: 403 } }); diff --git a/x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.tsx b/x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.tsx index b23a5ee3d5322..5f90774d7dfed 100644 --- a/x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.tsx +++ b/x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.tsx @@ -5,43 +5,43 @@ * 2.0. */ -import _ from 'lodash'; -import React, { Component } from 'react'; +import type { EuiBasicTableColumn, EuiSwitchEvent } from '@elastic/eui'; import { EuiButton, + EuiButtonIcon, + EuiFlexGroup, + EuiFlexItem, EuiInMemoryTable, EuiLink, EuiPageContent, EuiPageContentBody, EuiPageContentHeader, EuiPageContentHeaderSection, + EuiSwitch, EuiText, EuiTitle, - EuiButtonIcon, - EuiBasicTableColumn, - EuiSwitchEvent, - EuiSwitch, - EuiFlexGroup, - EuiFlexItem, } from '@elastic/eui'; +import _ from 'lodash'; +import React, { Component } from 'react'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import type { PublicMethodsOf } from '@kbn/utility-types'; -import { NotificationsStart } from 'src/core/public'; -import { ScopedHistory } from 'kibana/public'; +import type { NotificationsStart, ScopedHistory } from 'src/core/public'; + +import { reactRouterNavigate } from '../../../../../../../src/plugins/kibana_react/public'; +import type { Role } from '../../../../common/model'; import { - Role, + getExtendedRoleDeprecationNotice, + isRoleDeprecated, isRoleEnabled, isRoleReadOnly, isRoleReserved, - isRoleDeprecated, - getExtendedRoleDeprecationNotice, } from '../../../../common/model'; -import { RolesAPIClient } from '../roles_api_client'; +import { DeprecatedBadge, DisabledBadge, ReservedBadge } from '../../badges'; +import type { RolesAPIClient } from '../roles_api_client'; import { ConfirmDelete } from './confirm_delete'; import { PermissionDenied } from './permission_denied'; -import { DisabledBadge, DeprecatedBadge, ReservedBadge } from '../../badges'; -import { reactRouterNavigate } from '../../../../../../../src/plugins/kibana_react/public'; interface Props { notifications: NotificationsStart; diff --git a/x-pack/plugins/security/public/management/roles/roles_management_app.test.tsx b/x-pack/plugins/security/public/management/roles/roles_management_app.test.tsx index c576aac7a8169..476aabb845c51 100644 --- a/x-pack/plugins/security/public/management/roles/roles_management_app.test.tsx +++ b/x-pack/plugins/security/public/management/roles/roles_management_app.test.tsx @@ -5,7 +5,11 @@ * 2.0. */ +import { coreMock, scopedHistoryMock } from 'src/core/public/mocks'; + +import { featuresPluginMock } from '../../../../features/public/mocks'; import { licenseMock } from '../../../common/licensing/index.mock'; +import { rolesManagementApp } from './roles_management_app'; jest.mock('./roles_grid', () => ({ RolesGridPage: (props: any) => `Roles Page: ${JSON.stringify(props)}`, @@ -17,11 +21,6 @@ jest.mock('./edit_role', () => ({ `Role Edit Page: ${JSON.stringify({ ...props, docLinks: props.docLinks ? {} : undefined })}`, })); -import { rolesManagementApp } from './roles_management_app'; - -import { coreMock, scopedHistoryMock } from '../../../../../../src/core/public/mocks'; -import { featuresPluginMock } from '../../../../features/public/mocks'; - async function mountApp(basePath: string, pathname: string) { const { fatalErrors } = coreMock.createSetup(); const container = document.createElement('div'); diff --git a/x-pack/plugins/security/public/management/roles/roles_management_app.tsx b/x-pack/plugins/security/public/management/roles/roles_management_app.tsx index b89caea904e06..88be73200b8c1 100644 --- a/x-pack/plugins/security/public/management/roles/roles_management_app.tsx +++ b/x-pack/plugins/security/public/management/roles/roles_management_app.tsx @@ -7,12 +7,14 @@ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; -import { Router, Route, Switch, useParams } from 'react-router-dom'; +import { Route, Router, Switch, useParams } from 'react-router-dom'; + import { i18n } from '@kbn/i18n'; -import { StartServicesAccessor, FatalErrorsSetup } from 'src/core/public'; -import { RegisterManagementAppArgs } from '../../../../../../src/plugins/management/public'; -import { SecurityLicense } from '../../../common/licensing'; -import { PluginStartDependencies } from '../../plugin'; +import type { FatalErrorsSetup, StartServicesAccessor } from 'src/core/public'; +import type { RegisterManagementAppArgs } from 'src/plugins/management/public'; + +import type { SecurityLicense } from '../../../common/licensing'; +import type { PluginStartDependencies } from '../../plugin'; import { tryDecodeURIComponent } from '../url_utils'; interface CreateParams { diff --git a/x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.test.tsx b/x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.test.tsx index 9631b457ca272..3d8c95d52f505 100644 --- a/x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.test.tsx +++ b/x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.test.tsx @@ -6,14 +6,15 @@ */ import { EuiFieldPassword } from '@elastic/eui'; -import { ReactWrapper } from 'enzyme'; +import type { ReactWrapper } from 'enzyme'; import React from 'react'; + import { mountWithIntl } from '@kbn/test/jest'; -import { User } from '../../../../../common/model'; -import { ChangePasswordForm } from './change_password_form'; +import { coreMock } from 'src/core/public/mocks'; -import { coreMock } from '../../../../../../../../src/core/public/mocks'; +import type { User } from '../../../../../common/model'; import { userAPIClientMock } from '../../index.mock'; +import { ChangePasswordForm } from './change_password_form'; function getCurrentPasswordField(wrapper: ReactWrapper) { return wrapper.find(EuiFieldPassword).filter('[data-test-subj="currentPassword"]'); diff --git a/x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.tsx b/x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.tsx index c8790daf64130..b412ef5350974 100644 --- a/x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.tsx +++ b/x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.tsx @@ -15,13 +15,16 @@ import { EuiFormRow, } from '@elastic/eui'; import _ from 'lodash'; +import type { ChangeEvent } from 'react'; +import React, { Component } from 'react'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import type { PublicMethodsOf } from '@kbn/utility-types'; -import React, { ChangeEvent, Component } from 'react'; -import { NotificationsStart } from 'src/core/public'; -import { User } from '../../../../../common/model'; -import { UserAPIClient } from '../..'; +import type { NotificationsStart } from 'src/core/public'; + +import type { User } from '../../../../../common/model'; +import type { UserAPIClient } from '../../user_api_client'; interface Props { user: User; diff --git a/x-pack/plugins/security/public/management/users/components/confirm_delete_users/confirm_delete_users.test.tsx b/x-pack/plugins/security/public/management/users/components/confirm_delete_users/confirm_delete_users.test.tsx index c8d2f949949e5..5ce22b42e624f 100644 --- a/x-pack/plugins/security/public/management/users/components/confirm_delete_users/confirm_delete_users.test.tsx +++ b/x-pack/plugins/security/public/management/users/components/confirm_delete_users/confirm_delete_users.test.tsx @@ -5,12 +5,13 @@ * 2.0. */ -import { mountWithIntl } from '@kbn/test/jest'; -import { ConfirmDeleteUsers } from './confirm_delete_users'; import React from 'react'; -import { coreMock } from '../../../../../../../../src/core/public/mocks'; +import { mountWithIntl } from '@kbn/test/jest'; +import { coreMock } from 'src/core/public/mocks'; + import { userAPIClientMock } from '../../index.mock'; +import { ConfirmDeleteUsers } from './confirm_delete_users'; describe('ConfirmDeleteUsers', () => { it('renders a warning for a single user', () => { diff --git a/x-pack/plugins/security/public/management/users/components/confirm_delete_users/confirm_delete_users.tsx b/x-pack/plugins/security/public/management/users/components/confirm_delete_users/confirm_delete_users.tsx index 38adca145dfc5..ba3b29a92fd50 100644 --- a/x-pack/plugins/security/public/management/users/components/confirm_delete_users/confirm_delete_users.tsx +++ b/x-pack/plugins/security/public/management/users/components/confirm_delete_users/confirm_delete_users.tsx @@ -5,13 +5,15 @@ * 2.0. */ -import React, { Component, Fragment } from 'react'; import { EuiConfirmModal } from '@elastic/eui'; +import React, { Component, Fragment } from 'react'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import type { PublicMethodsOf } from '@kbn/utility-types'; -import { NotificationsStart } from 'src/core/public'; -import { UserAPIClient } from '../..'; +import type { NotificationsStart } from 'src/core/public'; + +import type { UserAPIClient } from '../../user_api_client'; interface Props { usersToDelete: string[]; diff --git a/x-pack/plugins/security/public/management/users/edit_user/change_password_flyout.tsx b/x-pack/plugins/security/public/management/users/edit_user/change_password_flyout.tsx index 189ada7fcf8fa..01b387c9e1fc2 100644 --- a/x-pack/plugins/security/public/management/users/edit_user/change_password_flyout.tsx +++ b/x-pack/plugins/security/public/management/users/edit_user/change_password_flyout.tsx @@ -5,26 +5,30 @@ * 2.0. */ -import React, { FunctionComponent } from 'react'; import { EuiCallOut, EuiFieldPassword, EuiFlexGroup, + EuiFlexItem, EuiForm, EuiFormRow, EuiIcon, EuiLoadingContent, EuiSpacer, EuiText, - EuiFlexItem, } from '@elastic/eui'; +import type { FunctionComponent } from 'react'; +import React from 'react'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; + import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; -import { useForm, ValidationErrors } from '../../../components/use_form'; -import { useCurrentUser } from '../../../components/use_current_user'; import { FormFlyout } from '../../../components/form_flyout'; -import { UserAPIClient } from '..'; +import { useCurrentUser } from '../../../components/use_current_user'; +import type { ValidationErrors } from '../../../components/use_form'; +import { useForm } from '../../../components/use_form'; +import { UserAPIClient } from '../user_api_client'; export interface ChangePasswordFormValues { current_password?: string; diff --git a/x-pack/plugins/security/public/management/users/edit_user/confirm_delete_users.tsx b/x-pack/plugins/security/public/management/users/edit_user/confirm_delete_users.tsx index 189f0c3845d63..b3c6f80812fab 100644 --- a/x-pack/plugins/security/public/management/users/edit_user/confirm_delete_users.tsx +++ b/x-pack/plugins/security/public/management/users/edit_user/confirm_delete_users.tsx @@ -5,14 +5,17 @@ * 2.0. */ -import React, { FunctionComponent } from 'react'; import { EuiText } from '@elastic/eui'; +import type { FunctionComponent } from 'react'; +import React from 'react'; +import useAsyncFn from 'react-use/lib/useAsyncFn'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import useAsyncFn from 'react-use/lib/useAsyncFn'; + import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; import { ConfirmModal } from '../../../components/confirm_modal'; -import { UserAPIClient } from '..'; +import { UserAPIClient } from '../user_api_client'; export interface ConfirmDeleteUsersProps { usernames: string[]; diff --git a/x-pack/plugins/security/public/management/users/edit_user/confirm_disable_users.tsx b/x-pack/plugins/security/public/management/users/edit_user/confirm_disable_users.tsx index e0fb4e554ee3c..a3d36e19504e1 100644 --- a/x-pack/plugins/security/public/management/users/edit_user/confirm_disable_users.tsx +++ b/x-pack/plugins/security/public/management/users/edit_user/confirm_disable_users.tsx @@ -5,14 +5,17 @@ * 2.0. */ -import React, { FunctionComponent } from 'react'; import { EuiText } from '@elastic/eui'; +import type { FunctionComponent } from 'react'; +import React from 'react'; +import useAsyncFn from 'react-use/lib/useAsyncFn'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import useAsyncFn from 'react-use/lib/useAsyncFn'; + import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; import { ConfirmModal } from '../../../components/confirm_modal'; -import { UserAPIClient } from '..'; +import { UserAPIClient } from '../user_api_client'; export interface ConfirmDisableUsersProps { usernames: string[]; diff --git a/x-pack/plugins/security/public/management/users/edit_user/confirm_enable_users.tsx b/x-pack/plugins/security/public/management/users/edit_user/confirm_enable_users.tsx index 2cb4cf8b4a9e2..24364d7b56d99 100644 --- a/x-pack/plugins/security/public/management/users/edit_user/confirm_enable_users.tsx +++ b/x-pack/plugins/security/public/management/users/edit_user/confirm_enable_users.tsx @@ -5,14 +5,17 @@ * 2.0. */ -import React, { FunctionComponent } from 'react'; import { EuiText } from '@elastic/eui'; +import type { FunctionComponent } from 'react'; +import React from 'react'; +import useAsyncFn from 'react-use/lib/useAsyncFn'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import useAsyncFn from 'react-use/lib/useAsyncFn'; + import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; import { ConfirmModal } from '../../../components/confirm_modal'; -import { UserAPIClient } from '..'; +import { UserAPIClient } from '../user_api_client'; export interface ConfirmEnableUsersProps { usernames: string[]; diff --git a/x-pack/plugins/security/public/management/users/edit_user/create_user_page.test.tsx b/x-pack/plugins/security/public/management/users/edit_user/create_user_page.test.tsx index 018ed58c8e488..2c40fec2ec31d 100644 --- a/x-pack/plugins/security/public/management/users/edit_user/create_user_page.test.tsx +++ b/x-pack/plugins/security/public/management/users/edit_user/create_user_page.test.tsx @@ -5,10 +5,12 @@ * 2.0. */ -import React from 'react'; -import { render, fireEvent, waitFor, within } from '@testing-library/react'; +import { fireEvent, render, waitFor, within } from '@testing-library/react'; import { createMemoryHistory } from 'history'; -import { coreMock } from '../../../../../../../src/core/public/mocks'; +import React from 'react'; + +import { coreMock } from 'src/core/public/mocks'; + import { securityMock } from '../../../mocks'; import { Providers } from '../users_management_app'; import { CreateUserPage } from './create_user_page'; diff --git a/x-pack/plugins/security/public/management/users/edit_user/create_user_page.tsx b/x-pack/plugins/security/public/management/users/edit_user/create_user_page.tsx index a624f0f282e51..cb76d54981a11 100644 --- a/x-pack/plugins/security/public/management/users/edit_user/create_user_page.tsx +++ b/x-pack/plugins/security/public/management/users/edit_user/create_user_page.tsx @@ -5,7 +5,6 @@ * 2.0. */ -import React, { FunctionComponent } from 'react'; import { EuiHorizontalRule, EuiPageContent, @@ -14,8 +13,12 @@ import { EuiPageContentHeaderSection, EuiTitle, } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; +import type { FunctionComponent } from 'react'; +import React from 'react'; import { useHistory } from 'react-router-dom'; + +import { FormattedMessage } from '@kbn/i18n/react'; + import { UserForm } from './user_form'; export const CreateUserPage: FunctionComponent = () => { diff --git a/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.test.tsx b/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.test.tsx index 764ec95ee9853..fb01ea0e61865 100644 --- a/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.test.tsx +++ b/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.test.tsx @@ -5,7 +5,6 @@ * 2.0. */ -import React from 'react'; import { fireEvent, render, @@ -14,7 +13,10 @@ import { within, } from '@testing-library/react'; import { createMemoryHistory } from 'history'; -import { coreMock } from '../../../../../../../src/core/public/mocks'; +import React from 'react'; + +import { coreMock } from 'src/core/public/mocks'; + import { mockAuthenticatedUser } from '../../../../common/model/authenticated_user.mock'; import { securityMock } from '../../../mocks'; import { Providers } from '../users_management_app'; diff --git a/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.tsx b/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.tsx index 41d96231ee566..74a5a923aac68 100644 --- a/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.tsx +++ b/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.tsx @@ -5,11 +5,13 @@ * 2.0. */ -import React, { FunctionComponent, useState, useEffect } from 'react'; import { EuiAvatar, EuiButton, EuiCallOut, + EuiDescriptionList, + EuiDescriptionListDescription, + EuiDescriptionListTitle, EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, @@ -21,22 +23,23 @@ import { EuiSpacer, EuiText, EuiTitle, - EuiDescriptionList, - EuiDescriptionListTitle, - EuiDescriptionListDescription, } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; +import type { FunctionComponent } from 'react'; +import React, { useEffect, useState } from 'react'; import { useHistory } from 'react-router-dom'; import useAsyncFn from 'react-use/lib/useAsyncFn'; + +import { FormattedMessage } from '@kbn/i18n/react'; + import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; import { getUserDisplayName } from '../../../../common/model'; +import { UserAPIClient } from '../user_api_client'; import { isUserDeprecated, isUserReserved } from '../user_utils'; -import { UserForm } from './user_form'; import { ChangePasswordFlyout } from './change_password_flyout'; +import { ConfirmDeleteUsers } from './confirm_delete_users'; import { ConfirmDisableUsers } from './confirm_disable_users'; import { ConfirmEnableUsers } from './confirm_enable_users'; -import { ConfirmDeleteUsers } from './confirm_delete_users'; -import { UserAPIClient } from '..'; +import { UserForm } from './user_form'; export interface EditUserPageProps { username: string; diff --git a/x-pack/plugins/security/public/management/users/edit_user/user_form.tsx b/x-pack/plugins/security/public/management/users/edit_user/user_form.tsx index 10e9e86e10f3a..8433f54a73343 100644 --- a/x-pack/plugins/security/public/management/users/edit_user/user_form.tsx +++ b/x-pack/plugins/security/public/management/users/edit_user/user_form.tsx @@ -5,7 +5,6 @@ * 2.0. */ -import React, { FunctionComponent, useEffect, useCallback } from 'react'; import { EuiButton, EuiButtonEmpty, @@ -19,18 +18,24 @@ import { EuiSpacer, EuiTextColor, } from '@elastic/eui'; +import { throttle } from 'lodash'; +import type { FunctionComponent } from 'react'; +import React, { useCallback, useEffect } from 'react'; +import useAsyncFn from 'react-use/lib/useAsyncFn'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import useAsyncFn from 'react-use/lib/useAsyncFn'; -import { throttle } from 'lodash'; + import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; -import { User, Role, isRoleDeprecated } from '../../../../common/model'; -import { NAME_REGEX, MAX_NAME_LENGTH } from '../../../../common/constants'; -import { useForm, ValidationErrors } from '../../../components/use_form'; +import { MAX_NAME_LENGTH, NAME_REGEX } from '../../../../common/constants'; +import type { Role, User } from '../../../../common/model'; +import { isRoleDeprecated } from '../../../../common/model'; import { DocLink } from '../../../components/doc_link'; -import { RolesAPIClient } from '../../roles'; +import type { ValidationErrors } from '../../../components/use_form'; +import { useForm } from '../../../components/use_form'; import { RoleComboBox } from '../../role_combo_box'; -import { UserAPIClient } from '..'; +import { RolesAPIClient } from '../../roles'; +import { UserAPIClient } from '../user_api_client'; export const THROTTLE_USERS_WAIT = 10000; diff --git a/x-pack/plugins/security/public/management/users/user_api_client.ts b/x-pack/plugins/security/public/management/users/user_api_client.ts index 4fa033d70a039..9197634383504 100644 --- a/x-pack/plugins/security/public/management/users/user_api_client.ts +++ b/x-pack/plugins/security/public/management/users/user_api_client.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { HttpStart } from 'src/core/public'; -import { User, EditUser } from '../../../common/model'; +import type { HttpStart } from 'src/core/public'; + +import type { EditUser, User } from '../../../common/model'; const usersUrl = '/internal/security/users'; diff --git a/x-pack/plugins/security/public/management/users/user_utils.test.ts b/x-pack/plugins/security/public/management/users/user_utils.test.ts index 6086766abd534..273086be971d1 100644 --- a/x-pack/plugins/security/public/management/users/user_utils.test.ts +++ b/x-pack/plugins/security/public/management/users/user_utils.test.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { User } from '../../../common/model'; -import { isUserReserved, isUserDeprecated, getExtendedUserDeprecationNotice } from './user_utils'; +import type { User } from '../../../common/model'; +import { getExtendedUserDeprecationNotice, isUserDeprecated, isUserReserved } from './user_utils'; describe('#isUserReserved', () => { it('returns false for a user with no metadata', () => { diff --git a/x-pack/plugins/security/public/management/users/user_utils.ts b/x-pack/plugins/security/public/management/users/user_utils.ts index 5ca5aff5d7c8a..bc7da560efcce 100644 --- a/x-pack/plugins/security/public/management/users/user_utils.ts +++ b/x-pack/plugins/security/public/management/users/user_utils.ts @@ -6,7 +6,8 @@ */ import { i18n } from '@kbn/i18n'; -import { User } from '../../../common/model'; + +import type { User } from '../../../common/model'; export const isUserReserved = (user: User) => user.metadata?._reserved ?? false; diff --git a/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.test.tsx b/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.test.tsx index d27c1eaa0449b..e3ad83fd0b934 100644 --- a/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.test.tsx +++ b/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.test.tsx @@ -5,19 +5,19 @@ * 2.0. */ -import { LocationDescriptorObject } from 'history'; -import { CoreStart, ScopedHistory } from 'kibana/public'; - -import { User } from '../../../../common/model'; -import { mountWithIntl, nextTick } from '@kbn/test/jest'; -import { UsersGridPage } from './users_grid_page'; +import { EuiBasicTable } from '@elastic/eui'; +import type { ReactWrapper } from 'enzyme'; +import type { LocationDescriptorObject } from 'history'; import React from 'react'; -import { ReactWrapper } from 'enzyme'; -import { userAPIClientMock } from '../index.mock'; -import { coreMock, scopedHistoryMock } from '../../../../../../../src/core/public/mocks'; + +import { findTestSubject, mountWithIntl, nextTick } from '@kbn/test/jest'; +import type { CoreStart, ScopedHistory } from 'src/core/public'; +import { coreMock, scopedHistoryMock } from 'src/core/public/mocks'; + +import type { User } from '../../../../common/model'; import { rolesAPIClientMock } from '../../roles/index.mock'; -import { findTestSubject } from '@kbn/test/jest'; -import { EuiBasicTable } from '@elastic/eui'; +import { userAPIClientMock } from '../index.mock'; +import { UsersGridPage } from './users_grid_page'; describe('UsersGridPage', () => { let history: ScopedHistory; @@ -236,26 +236,13 @@ describe('UsersGridPage', () => { await waitForRender(wrapper); - const deprecationTooltip = wrapper.find('[data-test-subj="roleDeprecationTooltip"]').props(); - - expect(deprecationTooltip).toMatchInlineSnapshot(` - Object { - "children":
- kibana_user - - -
, - "content": "The kibana_user role is deprecated. I don't like you.", - "data-test-subj": "roleDeprecationTooltip", - "delay": "regular", - "position": "top", - } - `); + const deprecationTooltip = wrapper + .find('[data-test-subj="roleDeprecationTooltip"]') + .prop('content'); + + expect(deprecationTooltip).toMatchInlineSnapshot( + `"The kibana_user role is deprecated. I don't like you."` + ); }); it('hides reserved users when instructed to', async () => { diff --git a/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.tsx b/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.tsx index 54e3fe9215f46..5b44c2f3c716c 100644 --- a/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.tsx +++ b/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.tsx @@ -5,35 +5,36 @@ * 2.0. */ -import React, { Component } from 'react'; +import type { EuiBasicTableColumn, EuiSwitchEvent } from '@elastic/eui'; import { EuiButton, - EuiLink, + EuiEmptyPrompt, EuiFlexGroup, + EuiFlexItem, EuiInMemoryTable, + EuiLink, EuiPageContent, - EuiTitle, + EuiPageContentBody, EuiPageContentHeader, EuiPageContentHeaderSection, - EuiPageContentBody, - EuiEmptyPrompt, - EuiBasicTableColumn, - EuiSwitchEvent, EuiSwitch, - EuiFlexItem, + EuiTitle, } from '@elastic/eui'; +import React, { Component } from 'react'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import type { PublicMethodsOf } from '@kbn/utility-types'; -import { NotificationsStart, ApplicationStart, ScopedHistory } from 'src/core/public'; -import { User, Role } from '../../../../common/model'; -import { ConfirmDeleteUsers } from '../components'; -import { isUserReserved, getExtendedUserDeprecationNotice, isUserDeprecated } from '../user_utils'; -import { DisabledBadge, ReservedBadge, DeprecatedBadge } from '../../badges'; -import { RoleTableDisplay } from '../../role_table_display'; -import { RolesAPIClient } from '../../roles'; +import type { ApplicationStart, NotificationsStart, ScopedHistory } from 'src/core/public'; + import { reactRouterNavigate } from '../../../../../../../src/plugins/kibana_react/public'; -import { UserAPIClient } from '..'; +import type { Role, User } from '../../../../common/model'; +import { DeprecatedBadge, DisabledBadge, ReservedBadge } from '../../badges'; +import { RoleTableDisplay } from '../../role_table_display'; +import type { RolesAPIClient } from '../../roles'; +import { ConfirmDeleteUsers } from '../components'; +import type { UserAPIClient } from '../user_api_client'; +import { getExtendedUserDeprecationNotice, isUserDeprecated, isUserReserved } from '../user_utils'; interface Props { userAPIClient: PublicMethodsOf; diff --git a/x-pack/plugins/security/public/management/users/users_management_app.test.tsx b/x-pack/plugins/security/public/management/users/users_management_app.test.tsx index fd18de22726c6..f4fed153d9975 100644 --- a/x-pack/plugins/security/public/management/users/users_management_app.test.tsx +++ b/x-pack/plugins/security/public/management/users/users_management_app.test.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import { coreMock, scopedHistoryMock } from '../../../../../../src/core/public/mocks'; +import { coreMock, scopedHistoryMock } from 'src/core/public/mocks'; + import { securityMock } from '../../mocks'; import { usersManagementApp } from './users_management_app'; diff --git a/x-pack/plugins/security/public/management/users/users_management_app.tsx b/x-pack/plugins/security/public/management/users/users_management_app.tsx index 0fc2e90e44c46..3e18734cbf368 100644 --- a/x-pack/plugins/security/public/management/users/users_management_app.tsx +++ b/x-pack/plugins/security/public/management/users/users_management_app.tsx @@ -5,24 +5,24 @@ * 2.0. */ -import React, { FunctionComponent } from 'react'; +import type { History } from 'history'; +import type { FunctionComponent } from 'react'; +import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; -import { Router, Route, Switch, Redirect, RouteComponentProps } from 'react-router-dom'; -import { History } from 'history'; +import type { RouteComponentProps } from 'react-router-dom'; +import { Redirect, Route, Router, Switch } from 'react-router-dom'; + import { i18n } from '@kbn/i18n'; import { I18nProvider } from '@kbn/i18n/react'; -import { StartServicesAccessor, CoreStart } from '../../../../../../src/core/public'; -import { RegisterManagementAppArgs } from '../../../../../../src/plugins/management/public'; +import type { CoreStart, StartServicesAccessor } from 'src/core/public'; +import type { RegisterManagementAppArgs } from 'src/plugins/management/public'; + import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; -import { AuthenticationServiceSetup } from '../../authentication'; -import { PluginStartDependencies } from '../../plugin'; -import { - BreadcrumbsProvider, - BreadcrumbsChangeHandler, - Breadcrumb, - getDocTitle, -} from '../../components/breadcrumb'; +import type { AuthenticationServiceSetup } from '../../authentication'; +import type { BreadcrumbsChangeHandler } from '../../components/breadcrumb'; +import { Breadcrumb, BreadcrumbsProvider, getDocTitle } from '../../components/breadcrumb'; import { AuthenticationProvider } from '../../components/use_current_user'; +import type { PluginStartDependencies } from '../../plugin'; import { tryDecodeURIComponent } from '../url_utils'; interface CreateParams { diff --git a/x-pack/plugins/security/public/mocks.ts b/x-pack/plugins/security/public/mocks.ts index e2c2b182fa980..0502025e9bae8 100644 --- a/x-pack/plugins/security/public/mocks.ts +++ b/x-pack/plugins/security/public/mocks.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { authenticationMock } from './authentication/index.mock'; -import { createSessionTimeoutMock } from './session/session_timeout.mock'; import { licenseMock } from '../common/licensing/index.mock'; +import { authenticationMock } from './authentication/index.mock'; import { navControlServiceMock } from './nav_control/index.mock'; +import { createSessionTimeoutMock } from './session/session_timeout.mock'; function createSetupMock() { return { diff --git a/x-pack/plugins/security/public/nav_control/index.mock.ts b/x-pack/plugins/security/public/nav_control/index.mock.ts index 59ff513dd4af8..769007d0bc0cd 100644 --- a/x-pack/plugins/security/public/nav_control/index.mock.ts +++ b/x-pack/plugins/security/public/nav_control/index.mock.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { SecurityNavControlServiceStart } from '.'; +import type { SecurityNavControlServiceStart } from './nav_control_service'; export const navControlServiceMock = { createStart: (): jest.Mocked => ({ diff --git a/x-pack/plugins/security/public/nav_control/nav_control_component.test.tsx b/x-pack/plugins/security/public/nav_control/nav_control_component.test.tsx index 6292d0b70efd1..bd338109a4460 100644 --- a/x-pack/plugins/security/public/nav_control/nav_control_component.test.tsx +++ b/x-pack/plugins/security/public/nav_control/nav_control_component.test.tsx @@ -5,15 +5,15 @@ * 2.0. */ +import { EuiHeaderSectionItemButton, EuiPopover } from '@elastic/eui'; import React from 'react'; import { BehaviorSubject } from 'rxjs'; -import { shallowWithIntl, nextTick, mountWithIntl } from '@kbn/test/jest'; -import { SecurityNavControl } from './nav_control_component'; -import type { AuthenticatedUser } from '../../common/model'; -import { EuiPopover, EuiHeaderSectionItemButton } from '@elastic/eui'; -import { findTestSubject } from '@kbn/test/jest'; +import { findTestSubject, mountWithIntl, nextTick, shallowWithIntl } from '@kbn/test/jest'; + +import type { AuthenticatedUser } from '../../common/model'; import { mockAuthenticatedUser } from '../../common/model/authenticated_user.mock'; +import { SecurityNavControl } from './nav_control_component'; describe('SecurityNavControl', () => { it(`renders a loading spinner when the user promise hasn't resolved yet.`, async () => { diff --git a/x-pack/plugins/security/public/nav_control/nav_control_component.tsx b/x-pack/plugins/security/public/nav_control/nav_control_component.tsx index 68f2701809501..c7649494bb810 100644 --- a/x-pack/plugins/security/public/nav_control/nav_control_component.tsx +++ b/x-pack/plugins/security/public/nav_control/nav_control_component.tsx @@ -5,24 +5,25 @@ * 2.0. */ -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; -import React, { Component } from 'react'; -import { Observable, Subscription } from 'rxjs'; +import './nav_control_component.scss'; + +import type { EuiContextMenuPanelItemDescriptor, IconType } from '@elastic/eui'; import { EuiAvatar, + EuiContextMenu, EuiHeaderSectionItemButton, - EuiPopover, - EuiLoadingSpinner, EuiIcon, - EuiContextMenu, - EuiContextMenuPanelItemDescriptor, - IconType, + EuiLoadingSpinner, + EuiPopover, EuiText, } from '@elastic/eui'; -import { AuthenticatedUser } from '../../common/model'; +import React, { Component } from 'react'; +import type { Observable, Subscription } from 'rxjs'; -import './nav_control_component.scss'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import type { AuthenticatedUser } from '../../common/model'; export interface UserMenuLink { label: string; diff --git a/x-pack/plugins/security/public/nav_control/nav_control_service.test.ts b/x-pack/plugins/security/public/nav_control/nav_control_service.test.ts index 5409c6d61d13a..72a1a6f5817a5 100644 --- a/x-pack/plugins/security/public/nav_control/nav_control_service.test.ts +++ b/x-pack/plugins/security/public/nav_control/nav_control_service.test.ts @@ -5,14 +5,16 @@ * 2.0. */ -import { coreMock } from 'src/core/public/mocks'; import { BehaviorSubject } from 'rxjs'; -import { ILicense } from '../../../licensing/public'; -import { SecurityNavControlService } from '.'; -import { SecurityLicenseService } from '../../common/licensing'; + import { nextTick } from '@kbn/test/jest'; -import { securityMock } from '../mocks'; +import { coreMock } from 'src/core/public/mocks'; + +import type { ILicense } from '../../../licensing/public'; +import { SecurityLicenseService } from '../../common/licensing'; import { mockAuthenticatedUser } from '../../common/model/authenticated_user.mock'; +import { securityMock } from '../mocks'; +import { SecurityNavControlService } from './nav_control_service'; const validLicense = { isAvailable: true, diff --git a/x-pack/plugins/security/public/nav_control/nav_control_service.tsx b/x-pack/plugins/security/public/nav_control/nav_control_service.tsx index 02ef208ce42a3..fc9ba262a2026 100644 --- a/x-pack/plugins/security/public/nav_control/nav_control_service.tsx +++ b/x-pack/plugins/security/public/nav_control/nav_control_service.tsx @@ -6,16 +6,18 @@ */ import { sortBy } from 'lodash'; -import { Observable, Subscription, BehaviorSubject, ReplaySubject } from 'rxjs'; +import React from 'react'; +import ReactDOM from 'react-dom'; +import type { Observable, Subscription } from 'rxjs'; +import { BehaviorSubject, ReplaySubject } from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; -import { CoreStart } from 'src/core/public'; -import ReactDOM from 'react-dom'; -import React from 'react'; +import type { CoreStart } from 'src/core/public'; -import { SecurityLicense } from '../../common/licensing'; -import { SecurityNavControl, UserMenuLink } from './nav_control_component'; -import { AuthenticationServiceSetup } from '../authentication'; +import type { SecurityLicense } from '../../common/licensing'; +import type { AuthenticationServiceSetup } from '../authentication'; +import type { UserMenuLink } from './nav_control_component'; +import { SecurityNavControl } from './nav_control_component'; interface SetupDeps { securityLicense: SecurityLicense; diff --git a/x-pack/plugins/security/public/plugin.test.tsx b/x-pack/plugins/security/public/plugin.test.tsx index c29b8ab3c729d..fa9d11422e884 100644 --- a/x-pack/plugins/security/public/plugin.test.tsx +++ b/x-pack/plugins/security/public/plugin.test.tsx @@ -5,19 +5,21 @@ * 2.0. */ -import { Observable } from 'rxjs'; import BroadcastChannel from 'broadcast-channel'; -import { CoreSetup } from 'src/core/public'; -import { DataPublicPluginStart } from '../../../../src/plugins/data/public'; -import { mockSecurityOssPlugin } from '../../../../src/plugins/security_oss/public/mocks'; -import { SessionTimeout } from './session'; -import { PluginStartDependencies, SecurityPlugin } from './plugin'; +import { Observable } from 'rxjs'; -import { coreMock } from '../../../../src/core/public/mocks'; -import { managementPluginMock } from '../../../../src/plugins/management/public/mocks'; +import type { CoreSetup } from 'src/core/public'; +import { coreMock } from 'src/core/public/mocks'; +import type { DataPublicPluginStart } from 'src/plugins/data/public'; +import { managementPluginMock } from 'src/plugins/management/public/mocks'; +import { mockSecurityOssPlugin } from 'src/plugins/security_oss/public/mocks'; + +import type { FeaturesPluginStart } from '../../features/public'; import { licensingMock } from '../../licensing/public/mocks'; import { ManagementService } from './management'; -import { FeaturesPluginStart } from '../../features/public'; +import type { PluginStartDependencies } from './plugin'; +import { SecurityPlugin } from './plugin'; +import { SessionTimeout } from './session'; describe('Security Plugin', () => { beforeAll(() => { diff --git a/x-pack/plugins/security/public/plugin.tsx b/x-pack/plugins/security/public/plugin.tsx index 8da7e71241b81..5d86f15174633 100644 --- a/x-pack/plugins/security/public/plugin.tsx +++ b/x-pack/plugins/security/public/plugin.tsx @@ -6,36 +6,34 @@ */ import { i18n } from '@kbn/i18n'; -import { SecurityOssPluginSetup, SecurityOssPluginStart } from 'src/plugins/security_oss/public'; -import { - CoreSetup, - CoreStart, - Plugin, - PluginInitializerContext, -} from '../../../../src/core/public'; -import { FeaturesPluginStart } from '../../features/public'; +import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from 'src/core/public'; +import type { DataPublicPluginStart } from 'src/plugins/data/public'; +import type { HomePublicPluginSetup } from 'src/plugins/home/public'; +import type { ManagementSetup, ManagementStart } from 'src/plugins/management/public'; +import type { + SecurityOssPluginSetup, + SecurityOssPluginStart, +} from 'src/plugins/security_oss/public'; + +import { FeatureCatalogueCategory } from '../../../../src/plugins/home/public'; +import type { FeaturesPluginStart } from '../../features/public'; +import type { LicensingPluginSetup } from '../../licensing/public'; import type { SpacesPluginStart } from '../../spaces/public'; -import { DataPublicPluginStart } from '../../../../src/plugins/data/public'; -import { - FeatureCatalogueCategory, - HomePublicPluginSetup, -} from '../../../../src/plugins/home/public'; -import { LicensingPluginSetup } from '../../licensing/public'; -import { ManagementSetup, ManagementStart } from '../../../../src/plugins/management/public'; +import { SecurityLicenseService } from '../common/licensing'; +import { accountManagementApp } from './account_management'; +import type { AuthenticationServiceSetup } from './authentication'; +import { AuthenticationService } from './authentication'; +import type { ConfigType } from './config'; +import { ManagementService } from './management'; +import { SecurityNavControlService } from './nav_control'; +import { SecurityCheckupService } from './security_checkup'; +import type { ISessionTimeout } from './session'; import { - ISessionTimeout, SessionExpired, SessionTimeout, SessionTimeoutHttpInterceptor, UnauthorizedResponseHttpInterceptor, } from './session'; -import { SecurityLicenseService } from '../common/licensing'; -import { SecurityNavControlService } from './nav_control'; -import { AuthenticationService, AuthenticationServiceSetup } from './authentication'; -import { ConfigType } from './config'; -import { ManagementService } from './management'; -import { accountManagementApp } from './account_management'; -import { SecurityCheckupService } from './security_checkup'; export interface PluginSetupDependencies { licensing: LicensingPluginSetup; diff --git a/x-pack/plugins/security/public/security_checkup/components/insecure_cluster_alert.tsx b/x-pack/plugins/security/public/security_checkup/components/insecure_cluster_alert.tsx index bbf3c508f9f2d..eeeac4533ed12 100644 --- a/x-pack/plugins/security/public/security_checkup/components/insecure_cluster_alert.tsx +++ b/x-pack/plugins/security/public/security_checkup/components/insecure_cluster_alert.tsx @@ -5,19 +5,20 @@ * 2.0. */ -import React, { useState } from 'react'; -import { i18n } from '@kbn/i18n'; -import { I18nProvider, FormattedMessage } from '@kbn/i18n/react'; -import { render, unmountComponentAtNode } from 'react-dom'; -import type { DocLinksStart, MountPoint } from 'kibana/public'; import { + EuiButton, EuiCheckbox, - EuiText, - EuiSpacer, EuiFlexGroup, EuiFlexItem, - EuiButton, + EuiSpacer, + EuiText, } from '@elastic/eui'; +import React, { useState } from 'react'; +import { render, unmountComponentAtNode } from 'react-dom'; + +import { i18n } from '@kbn/i18n'; +import { FormattedMessage, I18nProvider } from '@kbn/i18n/react'; +import type { DocLinksStart, MountPoint } from 'src/core/public'; export const insecureClusterAlertTitle = i18n.translate( 'xpack.security.checkup.insecureClusterTitle', diff --git a/x-pack/plugins/security/public/security_checkup/security_checkup_service.test.ts b/x-pack/plugins/security/public/security_checkup/security_checkup_service.test.ts index c86e40000bc53..29f1c2555e030 100644 --- a/x-pack/plugins/security/public/security_checkup/security_checkup_service.test.ts +++ b/x-pack/plugins/security/public/security_checkup/security_checkup_service.test.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { MountPoint } from 'kibana/public'; +import type { MountPoint } from 'src/core/public'; +import { docLinksServiceMock } from 'src/core/public/mocks'; +import { mockSecurityOssPlugin } from 'src/plugins/security_oss/public/mocks'; -import { docLinksServiceMock } from '../../../../../src/core/public/mocks'; -import { mockSecurityOssPlugin } from '../../../../../src/plugins/security_oss/public/mocks'; import { insecureClusterAlertTitle } from './components'; import { SecurityCheckupService } from './security_checkup_service'; diff --git a/x-pack/plugins/security/public/security_checkup/security_checkup_service.tsx b/x-pack/plugins/security/public/security_checkup/security_checkup_service.tsx index 333f712d39508..02adb85c21a80 100644 --- a/x-pack/plugins/security/public/security_checkup/security_checkup_service.tsx +++ b/x-pack/plugins/security/public/security_checkup/security_checkup_service.tsx @@ -5,13 +5,13 @@ * 2.0. */ -import type { DocLinksStart } from 'kibana/public'; - -import { +import type { DocLinksStart } from 'src/core/public'; +import type { SecurityOssPluginSetup, SecurityOssPluginStart, -} from '../../../../../src/plugins/security_oss/public'; -import { insecureClusterAlertTitle, insecureClusterAlertText } from './components'; +} from 'src/plugins/security_oss/public'; + +import { insecureClusterAlertText, insecureClusterAlertTitle } from './components'; interface SetupDeps { securityOssSetup: SecurityOssPluginSetup; diff --git a/x-pack/plugins/security/public/session/session_expired.mock.ts b/x-pack/plugins/security/public/session/session_expired.mock.ts index 0c921386303a7..f3a0e2b88f7eb 100644 --- a/x-pack/plugins/security/public/session/session_expired.mock.ts +++ b/x-pack/plugins/security/public/session/session_expired.mock.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ISessionExpired } from './session_expired'; +import type { ISessionExpired } from './session_expired'; export function createSessionExpiredMock() { return { diff --git a/x-pack/plugins/security/public/session/session_idle_timeout_warning.test.tsx b/x-pack/plugins/security/public/session/session_idle_timeout_warning.test.tsx index 53b88cd5ed58d..48a3bb482948e 100644 --- a/x-pack/plugins/security/public/session/session_idle_timeout_warning.test.tsx +++ b/x-pack/plugins/security/public/session/session_idle_timeout_warning.test.tsx @@ -6,7 +6,9 @@ */ import React from 'react'; + import { mountWithIntl } from '@kbn/test/jest'; + import { SessionIdleTimeoutWarning } from './session_idle_timeout_warning'; describe('SessionIdleTimeoutWarning', () => { diff --git a/x-pack/plugins/security/public/session/session_idle_timeout_warning.tsx b/x-pack/plugins/security/public/session/session_idle_timeout_warning.tsx index 92d8be8a4184f..47dce0aa9993e 100644 --- a/x-pack/plugins/security/public/session/session_idle_timeout_warning.tsx +++ b/x-pack/plugins/security/public/session/session_idle_timeout_warning.tsx @@ -5,11 +5,13 @@ * 2.0. */ -import { ToastInput } from 'src/core/public'; +import { EuiButton, EuiProgress } from '@elastic/eui'; import React from 'react'; + import { i18n } from '@kbn/i18n'; -import { EuiButton, EuiProgress } from '@elastic/eui'; import { FormattedMessage, FormattedRelative } from '@kbn/i18n/react'; +import type { ToastInput } from 'src/core/public'; + import { toMountPoint } from '../../../../../src/plugins/kibana_react/public'; interface Props { diff --git a/x-pack/plugins/security/public/session/session_lifespan_warning.tsx b/x-pack/plugins/security/public/session/session_lifespan_warning.tsx index 65ad6af0a5c68..e611c9aa2ac5f 100644 --- a/x-pack/plugins/security/public/session/session_lifespan_warning.tsx +++ b/x-pack/plugins/security/public/session/session_lifespan_warning.tsx @@ -5,11 +5,13 @@ * 2.0. */ -import { ToastInput } from 'src/core/public'; +import { EuiProgress } from '@elastic/eui'; import React from 'react'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage, FormattedRelative } from '@kbn/i18n/react'; -import { EuiProgress } from '@elastic/eui'; +import type { ToastInput } from 'src/core/public'; + import { toMountPoint } from '../../../../../src/plugins/kibana_react/public'; interface Props { diff --git a/x-pack/plugins/security/public/session/session_timeout.mock.ts b/x-pack/plugins/security/public/session/session_timeout.mock.ts index 00b6899ea3a1d..47e16810f2c2b 100644 --- a/x-pack/plugins/security/public/session/session_timeout.mock.ts +++ b/x-pack/plugins/security/public/session/session_timeout.mock.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ISessionTimeout } from './session_timeout'; +import type { ISessionTimeout } from './session_timeout'; export function createSessionTimeoutMock() { return { diff --git a/x-pack/plugins/security/public/session/session_timeout.test.tsx b/x-pack/plugins/security/public/session/session_timeout.test.tsx index df543a9343bc0..d224edb8cafd4 100644 --- a/x-pack/plugins/security/public/session/session_timeout.test.tsx +++ b/x-pack/plugins/security/public/session/session_timeout.test.tsx @@ -5,11 +5,13 @@ * 2.0. */ -import { coreMock } from 'src/core/public/mocks'; import BroadcastChannel from 'broadcast-channel'; -import { SessionTimeout } from './session_timeout'; -import { createSessionExpiredMock } from './session_expired.mock'; + import { mountWithIntl } from '@kbn/test/jest'; +import { coreMock } from 'src/core/public/mocks'; + +import { createSessionExpiredMock } from './session_expired.mock'; +import { SessionTimeout } from './session_timeout'; jest.useFakeTimers(); diff --git a/x-pack/plugins/security/public/session/session_timeout.tsx b/x-pack/plugins/security/public/session/session_timeout.tsx index ec0e4413be718..cc7eaa551b1b3 100644 --- a/x-pack/plugins/security/public/session/session_timeout.tsx +++ b/x-pack/plugins/security/public/session/session_timeout.tsx @@ -5,12 +5,14 @@ * 2.0. */ -import { NotificationsSetup, Toast, HttpSetup, ToastInput } from 'src/core/public'; import { BroadcastChannel } from 'broadcast-channel'; -import { SessionInfo } from '../../common/types'; + +import type { HttpSetup, NotificationsSetup, Toast, ToastInput } from 'src/core/public'; + +import type { SessionInfo } from '../../common/types'; +import type { ISessionExpired } from './session_expired'; import { createToast as createIdleTimeoutToast } from './session_idle_timeout_warning'; import { createToast as createLifespanToast } from './session_lifespan_warning'; -import { ISessionExpired } from './session_expired'; /** * Client session timeout is decreased by this number so that Kibana server diff --git a/x-pack/plugins/security/public/session/session_timeout_http_interceptor.test.ts b/x-pack/plugins/security/public/session/session_timeout_http_interceptor.test.ts index 9b1c52a6796a2..4f216d331c3f2 100644 --- a/x-pack/plugins/security/public/session/session_timeout_http_interceptor.test.ts +++ b/x-pack/plugins/security/public/session/session_timeout_http_interceptor.test.ts @@ -7,9 +7,11 @@ // @ts-ignore import fetchMock from 'fetch-mock/es5/client'; -import { SessionTimeoutHttpInterceptor } from './session_timeout_http_interceptor'; -import { setup } from '../../../../../src/core/test_helpers/http_test_setup'; + +import { setup } from 'src/core/test_helpers/http_test_setup'; + import { createSessionTimeoutMock } from './session_timeout.mock'; +import { SessionTimeoutHttpInterceptor } from './session_timeout_http_interceptor'; const mockCurrentUrl = (url: string) => window.history.pushState({}, '', url); diff --git a/x-pack/plugins/security/public/session/session_timeout_http_interceptor.ts b/x-pack/plugins/security/public/session/session_timeout_http_interceptor.ts index 35e302f9f8129..6fc7fb88578ff 100644 --- a/x-pack/plugins/security/public/session/session_timeout_http_interceptor.ts +++ b/x-pack/plugins/security/public/session/session_timeout_http_interceptor.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { +import type { HttpInterceptor, HttpInterceptorResponseError, HttpResponse, IAnonymousPaths, } from 'src/core/public'; -import { ISessionTimeout } from './session_timeout'; +import type { ISessionTimeout } from './session_timeout'; export class SessionTimeoutHttpInterceptor implements HttpInterceptor { constructor(private sessionTimeout: ISessionTimeout, private anonymousPaths: IAnonymousPaths) {} diff --git a/x-pack/plugins/security/public/session/unauthorized_response_http_interceptor.test.ts b/x-pack/plugins/security/public/session/unauthorized_response_http_interceptor.test.ts index de7e1cc388189..35bdb911b6ed1 100644 --- a/x-pack/plugins/security/public/session/unauthorized_response_http_interceptor.test.ts +++ b/x-pack/plugins/security/public/session/unauthorized_response_http_interceptor.test.ts @@ -7,9 +7,12 @@ // @ts-ignore import fetchMock from 'fetch-mock/es5/client'; + +import { setup } from 'src/core/test_helpers/http_test_setup'; + import { SessionExpired } from './session_expired'; -import { setup } from '../../../../../src/core/test_helpers/http_test_setup'; import { UnauthorizedResponseHttpInterceptor } from './unauthorized_response_http_interceptor'; + jest.mock('./session_expired'); const drainPromiseQueue = () => { diff --git a/x-pack/plugins/security/public/session/unauthorized_response_http_interceptor.ts b/x-pack/plugins/security/public/session/unauthorized_response_http_interceptor.ts index 3fb8b467940a1..43945c8f43c0f 100644 --- a/x-pack/plugins/security/public/session/unauthorized_response_http_interceptor.ts +++ b/x-pack/plugins/security/public/session/unauthorized_response_http_interceptor.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { +import type { HttpInterceptor, HttpInterceptorResponseError, - IHttpInterceptController, IAnonymousPaths, + IHttpInterceptController, } from 'src/core/public'; -import { SessionExpired } from './session_expired'; +import type { SessionExpired } from './session_expired'; export class UnauthorizedResponseHttpInterceptor implements HttpInterceptor { constructor(private sessionExpired: SessionExpired, private anonymousPaths: IAnonymousPaths) {} diff --git a/x-pack/plugins/security/server/anonymous_access/anonymous_access_service.mock.ts b/x-pack/plugins/security/server/anonymous_access/anonymous_access_service.mock.ts index a484dfb974517..b305685f9a233 100644 --- a/x-pack/plugins/security/server/anonymous_access/anonymous_access_service.mock.ts +++ b/x-pack/plugins/security/server/anonymous_access/anonymous_access_service.mock.ts @@ -5,9 +5,9 @@ * 2.0. */ -import type { AnonymousAccessServiceStart } from './anonymous_access_service'; +import { capabilitiesServiceMock } from 'src/core/server/mocks'; -import { capabilitiesServiceMock } from '../../../../../src/core/server/mocks'; +import type { AnonymousAccessServiceStart } from './anonymous_access_service'; export const anonymousAccessServiceMock = { createStart: (): jest.Mocked => ({ diff --git a/x-pack/plugins/security/server/anonymous_access/anonymous_access_service.test.ts b/x-pack/plugins/security/server/anonymous_access/anonymous_access_service.test.ts index 04aeb69bde1a3..3089ac580a39b 100644 --- a/x-pack/plugins/security/server/anonymous_access/anonymous_access_service.test.ts +++ b/x-pack/plugins/security/server/anonymous_access/anonymous_access_service.test.ts @@ -6,18 +6,19 @@ */ import { errors } from '@elastic/elasticsearch'; -import type { Logger } from '../../../../../src/core/server'; -import { ConfigSchema, createConfig } from '../config'; -import { AnonymousAccessService } from './anonymous_access_service'; +import type { Logger } from 'src/core/server'; import { coreMock, + elasticsearchServiceMock, httpServerMock, loggingSystemMock, - elasticsearchServiceMock, -} from '../../../../../src/core/server/mocks'; +} from 'src/core/server/mocks'; + import { spacesMock } from '../../../spaces/server/mocks'; +import { ConfigSchema, createConfig } from '../config'; import { securityMock } from '../mocks'; +import { AnonymousAccessService } from './anonymous_access_service'; const createSecurityConfig = (config: Record = {}) => { return createConfig(ConfigSchema.validate(config), loggingSystemMock.createLogger(), { diff --git a/x-pack/plugins/security/server/anonymous_access/anonymous_access_service.ts b/x-pack/plugins/security/server/anonymous_access/anonymous_access_service.ts index 30d4c22497ebe..ece0c63350995 100644 --- a/x-pack/plugins/security/server/anonymous_access/anonymous_access_service.ts +++ b/x-pack/plugins/security/server/anonymous_access/anonymous_access_service.ts @@ -6,18 +6,21 @@ */ import type { Request } from '@hapi/hapi'; -import { + +import type { + Capabilities, CapabilitiesStart, IBasePath, - KibanaRequest, - Logger, - Capabilities, IClusterClient, -} from '../../../../../src/core/server'; + Logger, +} from 'src/core/server'; + +import { KibanaRequest } from '../../../../../src/core/server'; import { addSpaceIdToPath } from '../../../spaces/common'; import type { SpacesServiceStart } from '../../../spaces/server'; import { AUTH_PROVIDER_HINT_QUERY_STRING_PARAMETER } from '../../common/constants'; -import { AnonymousAuthenticationProvider, HTTPAuthorizationHeader } from '../authentication'; +import type { HTTPAuthorizationHeader } from '../authentication'; +import { AnonymousAuthenticationProvider } from '../authentication'; import type { ConfigType } from '../config'; import { getDetailedErrorMessage, getErrorStatusCode } from '../errors'; diff --git a/x-pack/plugins/security/server/audit/audit_events.test.ts b/x-pack/plugins/security/server/audit/audit_events.test.ts index 984d1bdb66d92..f986c57987022 100644 --- a/x-pack/plugins/security/server/audit/audit_events.test.ts +++ b/x-pack/plugins/security/server/audit/audit_events.test.ts @@ -6,18 +6,20 @@ */ import { URL } from 'url'; + +import { httpServerMock } from 'src/core/server/mocks'; + +import { mockAuthenticatedUser } from '../../common/model/authenticated_user.mock'; +import { AuthenticationResult } from '../authentication'; import { EventOutcome, + httpRequestEvent, SavedObjectAction, savedObjectEvent, - userLoginEvent, - httpRequestEvent, - spaceAuditEvent, SpaceAuditAction, + spaceAuditEvent, + userLoginEvent, } from './audit_events'; -import { AuthenticationResult } from '../authentication'; -import { mockAuthenticatedUser } from '../../common/model/authenticated_user.mock'; -import { httpServerMock } from 'src/core/server/mocks'; describe('#savedObjectEvent', () => { test('creates event with `unknown` outcome', () => { diff --git a/x-pack/plugins/security/server/audit/audit_events.ts b/x-pack/plugins/security/server/audit/audit_events.ts index f353362e33513..00f77ff2bc5fd 100644 --- a/x-pack/plugins/security/server/audit/audit_events.ts +++ b/x-pack/plugins/security/server/audit/audit_events.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { KibanaRequest } from 'src/core/server'; -import { AuthenticationResult } from '../authentication/authentication_result'; +import type { KibanaRequest } from 'src/core/server'; + +import type { AuthenticationResult } from '../authentication/authentication_result'; /** * Audit event schema using ECS format: https://www.elastic.co/guide/en/ecs/1.6/index.html diff --git a/x-pack/plugins/security/server/audit/audit_service.test.ts b/x-pack/plugins/security/server/audit/audit_service.test.ts index f59fd6ecdec91..ffacaff7237c5 100644 --- a/x-pack/plugins/security/server/audit/audit_service.test.ts +++ b/x-pack/plugins/security/server/audit/audit_service.test.ts @@ -5,23 +5,27 @@ * 2.0. */ -import { - AuditService, - filterEvent, - createLoggingConfig, - RECORD_USAGE_INTERVAL, -} from './audit_service'; -import { AuditEvent, EventCategory, EventType, EventOutcome } from './audit_events'; +import { BehaviorSubject, Observable, of } from 'rxjs'; + import { coreMock, - loggingSystemMock, - httpServiceMock, httpServerMock, + httpServiceMock, + loggingSystemMock, } from 'src/core/server/mocks'; + +import type { SecurityLicenseFeatures } from '../../common/licensing'; import { licenseMock } from '../../common/licensing/index.mock'; -import { ConfigSchema, ConfigType } from '../config'; -import { SecurityLicenseFeatures } from '../../common/licensing'; -import { BehaviorSubject, Observable, of } from 'rxjs'; +import type { ConfigType } from '../config'; +import { ConfigSchema } from '../config'; +import type { AuditEvent } from './audit_events'; +import { EventCategory, EventOutcome, EventType } from './audit_events'; +import { + AuditService, + createLoggingConfig, + filterEvent, + RECORD_USAGE_INTERVAL, +} from './audit_service'; jest.useFakeTimers(); diff --git a/x-pack/plugins/security/server/audit/audit_service.ts b/x-pack/plugins/security/server/audit/audit_service.ts index 99dd2c82ec9fe..7511e079b9adb 100644 --- a/x-pack/plugins/security/server/audit/audit_service.ts +++ b/x-pack/plugins/security/server/audit/audit_service.ts @@ -5,20 +5,23 @@ * 2.0. */ -import { Subscription } from 'rxjs'; -import { map, distinctUntilKeyChanged } from 'rxjs/operators'; -import { - Logger, - LoggingServiceSetup, - KibanaRequest, +import type { Subscription } from 'rxjs'; +import { distinctUntilKeyChanged, map } from 'rxjs/operators'; + +import type { HttpServiceSetup, + KibanaRequest, + Logger, LoggerContextConfigInput, -} from '../../../../../src/core/server'; -import { SecurityLicense, SecurityLicenseFeatures } from '../../common/licensing'; -import { ConfigType } from '../config'; -import { SpacesPluginSetup } from '../../../spaces/server'; -import { AuditEvent, httpRequestEvent } from './audit_events'; -import { SecurityPluginSetup } from '..'; + LoggingServiceSetup, +} from 'src/core/server'; + +import type { SpacesPluginSetup } from '../../../spaces/server'; +import type { SecurityLicense, SecurityLicenseFeatures } from '../../common/licensing'; +import type { ConfigType } from '../config'; +import type { SecurityPluginSetup } from '../plugin'; +import type { AuditEvent } from './audit_events'; +import { httpRequestEvent } from './audit_events'; export const ECS_VERSION = '1.6.0'; export const RECORD_USAGE_INTERVAL = 60 * 60 * 1000; // 1 hour diff --git a/x-pack/plugins/security/server/audit/index.mock.ts b/x-pack/plugins/security/server/audit/index.mock.ts index 7bea926830622..f8816f07ed3ae 100644 --- a/x-pack/plugins/security/server/audit/index.mock.ts +++ b/x-pack/plugins/security/server/audit/index.mock.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { SecurityAuditLogger } from './security_audit_logger'; -import { AuditService } from './audit_service'; +import type { AuditService } from './audit_service'; +import type { SecurityAuditLogger } from './security_audit_logger'; export const securityAuditLoggerMock = { create() { diff --git a/x-pack/plugins/security/server/audit/security_audit_logger.ts b/x-pack/plugins/security/server/audit/security_audit_logger.ts index 9d1d896470d77..280cc233fca17 100644 --- a/x-pack/plugins/security/server/audit/security_audit_logger.ts +++ b/x-pack/plugins/security/server/audit/security_audit_logger.ts @@ -6,7 +6,7 @@ */ import type { AuthenticationProvider } from '../../common/model'; -import { LegacyAuditLogger } from './audit_service'; +import type { LegacyAuditLogger } from './audit_service'; /** * @deprecated diff --git a/x-pack/plugins/security/server/authentication/api_keys/api_keys.mock.ts b/x-pack/plugins/security/server/authentication/api_keys/api_keys.mock.ts index 0b0310de271fa..e82efeb5168d9 100644 --- a/x-pack/plugins/security/server/authentication/api_keys/api_keys.mock.ts +++ b/x-pack/plugins/security/server/authentication/api_keys/api_keys.mock.ts @@ -6,7 +6,8 @@ */ import type { PublicMethodsOf } from '@kbn/utility-types'; -import type { APIKeys } from '.'; + +import type { APIKeys } from './api_keys'; export const apiKeysMock = { create: (): jest.Mocked> => ({ diff --git a/x-pack/plugins/security/server/authentication/api_keys/api_keys.test.ts b/x-pack/plugins/security/server/authentication/api_keys/api_keys.test.ts index 8f23ce5582ff2..dda3a15903696 100644 --- a/x-pack/plugins/security/server/authentication/api_keys/api_keys.test.ts +++ b/x-pack/plugins/security/server/authentication/api_keys/api_keys.test.ts @@ -5,16 +5,12 @@ * 2.0. */ -import type { SecurityLicense } from '../../../common/licensing'; -import { APIKeys } from './api_keys'; +import { elasticsearchServiceMock, httpServerMock, loggingSystemMock } from 'src/core/server/mocks'; -import { - httpServerMock, - loggingSystemMock, - elasticsearchServiceMock, -} from '../../../../../../src/core/server/mocks'; +import type { SecurityLicense } from '../../../common/licensing'; import { licenseMock } from '../../../common/licensing/index.mock'; import { securityMock } from '../../mocks'; +import { APIKeys } from './api_keys'; const encodeToBase64 = (str: string) => Buffer.from(str).toString('base64'); diff --git a/x-pack/plugins/security/server/authentication/api_keys/api_keys.ts b/x-pack/plugins/security/server/authentication/api_keys/api_keys.ts index d9322b71c772a..bdf549095c3c0 100644 --- a/x-pack/plugins/security/server/authentication/api_keys/api_keys.ts +++ b/x-pack/plugins/security/server/authentication/api_keys/api_keys.ts @@ -5,11 +5,12 @@ * 2.0. */ -import type { IClusterClient, KibanaRequest, Logger } from '../../../../../../src/core/server'; +import type { IClusterClient, KibanaRequest, Logger } from 'src/core/server'; + import type { SecurityLicense } from '../../../common/licensing'; import { - HTTPAuthorizationHeader, BasicHTTPAuthorizationHeaderCredentials, + HTTPAuthorizationHeader, } from '../http_authentication'; /** diff --git a/x-pack/plugins/security/server/authentication/authentication_result.test.ts b/x-pack/plugins/security/server/authentication/authentication_result.test.ts index cd120d0e23cb2..e890f99e0da6e 100644 --- a/x-pack/plugins/security/server/authentication/authentication_result.test.ts +++ b/x-pack/plugins/security/server/authentication/authentication_result.test.ts @@ -6,6 +6,7 @@ */ import Boom from '@hapi/boom'; + import { mockAuthenticatedUser } from '../../common/model/authenticated_user.mock'; import { AuthenticationResult } from './authentication_result'; diff --git a/x-pack/plugins/security/server/authentication/authentication_result.ts b/x-pack/plugins/security/server/authentication/authentication_result.ts index 7c1f6e9250d47..a5b1e11754d97 100644 --- a/x-pack/plugins/security/server/authentication/authentication_result.ts +++ b/x-pack/plugins/security/server/authentication/authentication_result.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { AuthHeaders } from '../../../../../src/core/server'; -import { AuthenticatedUser } from '../../common/model'; +import type { AuthHeaders } from 'src/core/server'; + +import type { AuthenticatedUser } from '../../common/model'; /** * Represents status that `AuthenticationResult` can be in. diff --git a/x-pack/plugins/security/server/authentication/authentication_service.mock.ts b/x-pack/plugins/security/server/authentication/authentication_service.mock.ts index 864756d85fa45..ba3297aeb5493 100644 --- a/x-pack/plugins/security/server/authentication/authentication_service.mock.ts +++ b/x-pack/plugins/security/server/authentication/authentication_service.mock.ts @@ -6,9 +6,9 @@ */ import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; -import type { AuthenticationServiceStart } from './authentication_service'; import { apiKeysMock } from './api_keys/api_keys.mock'; +import type { AuthenticationServiceStart } from './authentication_service'; export const authenticationServiceMock = { createStart: (): DeeplyMockedKeys => ({ diff --git a/x-pack/plugins/security/server/authentication/authentication_service.test.ts b/x-pack/plugins/security/server/authentication/authentication_service.test.ts index a9c5fa3577476..b0be9445c3fc3 100644 --- a/x-pack/plugins/security/server/authentication/authentication_service.test.ts +++ b/x-pack/plugins/security/server/authentication/authentication_service.test.ts @@ -8,36 +8,37 @@ jest.mock('./authenticator'); import Boom from '@hapi/boom'; -import type { PublicMethodsOf } from '@kbn/utility-types'; - -import { - loggingSystemMock, - coreMock, - httpServerMock, - httpServiceMock, - elasticsearchServiceMock, -} from '../../../../../src/core/server/mocks'; -import { licenseMock } from '../../common/licensing/index.mock'; -import { mockAuthenticatedUser } from '../../common/model/authenticated_user.mock'; -import { auditServiceMock, securityAuditLoggerMock } from '../audit/index.mock'; -import { securityFeatureUsageServiceMock } from '../feature_usage/index.mock'; -import { sessionMock } from '../session_management/session.mock'; +import type { PublicMethodsOf } from '@kbn/utility-types'; import type { AuthenticationHandler, AuthToolkit, + HttpServiceSetup, + HttpServiceStart, KibanaRequest, Logger, LoggerFactory, - HttpServiceSetup, - HttpServiceStart, -} from '../../../../../src/core/server'; -import type { AuthenticatedUser } from '../../common/model'; +} from 'src/core/server'; +import { + coreMock, + elasticsearchServiceMock, + httpServerMock, + httpServiceMock, + loggingSystemMock, +} from 'src/core/server/mocks'; + import type { SecurityLicense } from '../../common/licensing'; +import { licenseMock } from '../../common/licensing/index.mock'; +import type { AuthenticatedUser } from '../../common/model'; +import { mockAuthenticatedUser } from '../../common/model/authenticated_user.mock'; import type { AuditServiceSetup, SecurityAuditLogger } from '../audit'; +import { auditServiceMock, securityAuditLoggerMock } from '../audit/index.mock'; +import type { ConfigType } from '../config'; +import { ConfigSchema, createConfig } from '../config'; import type { SecurityFeatureUsageServiceStart } from '../feature_usage'; +import { securityFeatureUsageServiceMock } from '../feature_usage/index.mock'; import type { Session } from '../session_management'; -import { ConfigSchema, ConfigType, createConfig } from '../config'; +import { sessionMock } from '../session_management/session.mock'; import { AuthenticationResult } from './authentication_result'; import { AuthenticationService } from './authentication_service'; diff --git a/x-pack/plugins/security/server/authentication/authentication_service.ts b/x-pack/plugins/security/server/authentication/authentication_service.ts index 6848d7a3c7df6..7feeff7a5d8ed 100644 --- a/x-pack/plugins/security/server/authentication/authentication_service.ts +++ b/x-pack/plugins/security/server/authentication/authentication_service.ts @@ -7,24 +7,26 @@ import type { PublicMethodsOf } from '@kbn/utility-types'; import type { - LoggerFactory, - KibanaRequest, - Logger, HttpServiceSetup, - IClusterClient, HttpServiceStart, -} from '../../../../../src/core/server'; + IClusterClient, + KibanaRequest, + Logger, + LoggerFactory, +} from 'src/core/server'; + import type { SecurityLicense } from '../../common/licensing'; import type { AuthenticatedUser } from '../../common/model'; import type { AuditServiceSetup, SecurityAuditLogger } from '../audit'; import type { ConfigType } from '../config'; +import { getErrorStatusCode } from '../errors'; import type { SecurityFeatureUsageServiceStart } from '../feature_usage'; import type { Session } from '../session_management'; -import type { DeauthenticationResult } from './deauthentication_result'; -import type { AuthenticationResult } from './authentication_result'; -import { getErrorStatusCode } from '../errors'; import { APIKeys } from './api_keys'; -import { Authenticator, ProviderLoginAttempt } from './authenticator'; +import type { AuthenticationResult } from './authentication_result'; +import type { ProviderLoginAttempt } from './authenticator'; +import { Authenticator } from './authenticator'; +import type { DeauthenticationResult } from './deauthentication_result'; interface AuthenticationServiceSetupParams { http: Pick; diff --git a/x-pack/plugins/security/server/authentication/authenticator.test.ts b/x-pack/plugins/security/server/authentication/authenticator.test.ts index 118ad287b67df..e0b9144f6a66f 100644 --- a/x-pack/plugins/security/server/authentication/authenticator.test.ts +++ b/x-pack/plugins/security/server/authentication/authenticator.test.ts @@ -11,25 +11,28 @@ jest.mock('./providers/saml'); jest.mock('./providers/http'); import Boom from '@hapi/boom'; + import type { PublicMethodsOf } from '@kbn/utility-types'; import { - loggingSystemMock, - httpServiceMock, - httpServerMock, elasticsearchServiceMock, -} from '../../../../../src/core/server/mocks'; + httpServerMock, + httpServiceMock, + loggingSystemMock, +} from 'src/core/server/mocks'; + +import type { SecurityLicenseFeatures } from '../../common/licensing'; import { licenseMock } from '../../common/licensing/index.mock'; import { mockAuthenticatedUser } from '../../common/model/authenticated_user.mock'; import { auditServiceMock, securityAuditLoggerMock } from '../audit/index.mock'; -import { sessionMock } from '../session_management/index.mock'; -import { SecurityLicenseFeatures } from '../../common/licensing'; import { ConfigSchema, createConfig } from '../config'; -import { SessionValue } from '../session_management'; +import { securityFeatureUsageServiceMock } from '../feature_usage/index.mock'; +import type { SessionValue } from '../session_management'; +import { sessionMock } from '../session_management/index.mock'; import { AuthenticationResult } from './authentication_result'; -import { Authenticator, AuthenticatorOptions } from './authenticator'; +import type { AuthenticatorOptions } from './authenticator'; +import { Authenticator } from './authenticator'; import { DeauthenticationResult } from './deauthentication_result'; -import { BasicAuthenticationProvider, SAMLAuthenticationProvider } from './providers'; -import { securityFeatureUsageServiceMock } from '../feature_usage/index.mock'; +import type { BasicAuthenticationProvider, SAMLAuthenticationProvider } from './providers'; function getMockOptions({ providers, diff --git a/x-pack/plugins/security/server/authentication/authenticator.ts b/x-pack/plugins/security/server/authentication/authenticator.ts index dc309f0dd4498..ff6f3ff0c2ae7 100644 --- a/x-pack/plugins/security/server/authentication/authenticator.ts +++ b/x-pack/plugins/security/server/authentication/authenticator.ts @@ -6,12 +6,9 @@ */ import type { PublicMethodsOf } from '@kbn/utility-types'; -import { - KibanaRequest, - LoggerFactory, - IBasePath, - IClusterClient, -} from '../../../../../src/core/server'; +import type { IBasePath, IClusterClient, LoggerFactory } from 'src/core/server'; + +import { KibanaRequest } from '../../../../../src/core/server'; import { AUTH_PROVIDER_HINT_QUERY_STRING_PARAMETER, LOGOUT_PROVIDER_QUERY_STRING_PARAMETER, @@ -21,30 +18,32 @@ import { import type { SecurityLicense } from '../../common/licensing'; import type { AuthenticatedUser, AuthenticationProvider } from '../../common/model'; import { shouldProviderUseLoginForm } from '../../common/model'; -import { SecurityAuditLogger, AuditServiceSetup, userLoginEvent } from '../audit'; +import type { AuditServiceSetup, SecurityAuditLogger } from '../audit'; +import { userLoginEvent } from '../audit'; import type { ConfigType } from '../config'; import { getErrorStatusCode } from '../errors'; import type { SecurityFeatureUsageServiceStart } from '../feature_usage'; -import type { SessionValue, Session } from '../session_management'; - -import { - AnonymousAuthenticationProvider, +import type { Session, SessionValue } from '../session_management'; +import { AuthenticationResult } from './authentication_result'; +import { canRedirectRequest } from './can_redirect_request'; +import { DeauthenticationResult } from './deauthentication_result'; +import { HTTPAuthorizationHeader } from './http_authentication'; +import type { AuthenticationProviderOptions, AuthenticationProviderSpecificOptions, BaseAuthenticationProvider, +} from './providers'; +import { + AnonymousAuthenticationProvider, BasicAuthenticationProvider, + HTTPAuthenticationProvider, KerberosAuthenticationProvider, - SAMLAuthenticationProvider, - TokenAuthenticationProvider, OIDCAuthenticationProvider, PKIAuthenticationProvider, - HTTPAuthenticationProvider, + SAMLAuthenticationProvider, + TokenAuthenticationProvider, } from './providers'; -import { AuthenticationResult } from './authentication_result'; -import { DeauthenticationResult } from './deauthentication_result'; import { Tokens } from './tokens'; -import { canRedirectRequest } from './can_redirect_request'; -import { HTTPAuthorizationHeader } from './http_authentication'; /** * The shape of the login attempt. diff --git a/x-pack/plugins/security/server/authentication/can_redirect_request.ts b/x-pack/plugins/security/server/authentication/can_redirect_request.ts index 8e6ad67da72dc..71c6365d9aea4 100644 --- a/x-pack/plugins/security/server/authentication/can_redirect_request.ts +++ b/x-pack/plugins/security/server/authentication/can_redirect_request.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { KibanaRequest } from '../../../../../src/core/server'; +import type { KibanaRequest } from 'src/core/server'; const ROUTE_TAG_API = 'api'; const KIBANA_XSRF_HEADER = 'kbn-xsrf'; diff --git a/x-pack/plugins/security/server/authentication/http_authentication/http_authorization_header.test.ts b/x-pack/plugins/security/server/authentication/http_authentication/http_authorization_header.test.ts index 16e976414fcda..008afcf2a9389 100644 --- a/x-pack/plugins/security/server/authentication/http_authentication/http_authorization_header.test.ts +++ b/x-pack/plugins/security/server/authentication/http_authentication/http_authorization_header.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { httpServerMock } from '../../../../../../src/core/server/mocks'; +import { httpServerMock } from 'src/core/server/mocks'; import { HTTPAuthorizationHeader } from './http_authorization_header'; diff --git a/x-pack/plugins/security/server/authentication/http_authentication/http_authorization_header.ts b/x-pack/plugins/security/server/authentication/http_authentication/http_authorization_header.ts index 1341e7afb270a..97d1f0c9b9c00 100644 --- a/x-pack/plugins/security/server/authentication/http_authentication/http_authorization_header.ts +++ b/x-pack/plugins/security/server/authentication/http_authentication/http_authorization_header.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { KibanaRequest } from '../../../../../../src/core/server'; +import type { KibanaRequest } from 'src/core/server'; export class HTTPAuthorizationHeader { /** diff --git a/x-pack/plugins/security/server/authentication/providers/anonymous.test.ts b/x-pack/plugins/security/server/authentication/providers/anonymous.test.ts index 5ae174b1e2273..124cdb0426518 100644 --- a/x-pack/plugins/security/server/authentication/providers/anonymous.test.ts +++ b/x-pack/plugins/security/server/authentication/providers/anonymous.test.ts @@ -7,12 +7,11 @@ import { errors } from '@elastic/elasticsearch'; -import { elasticsearchServiceMock, httpServerMock } from '../../../../../../src/core/server/mocks'; +import type { ScopeableRequest } from 'src/core/server'; +import { elasticsearchServiceMock, httpServerMock } from 'src/core/server/mocks'; + import { mockAuthenticatedUser } from '../../../common/model/authenticated_user.mock'; import { securityMock } from '../../mocks'; -import { mockAuthenticationProviderOptions } from './base.mock'; - -import { ScopeableRequest } from '../../../../../../src/core/server'; import { AuthenticationResult } from '../authentication_result'; import { DeauthenticationResult } from '../deauthentication_result'; import { @@ -20,6 +19,7 @@ import { HTTPAuthorizationHeader, } from '../http_authentication'; import { AnonymousAuthenticationProvider } from './anonymous'; +import { mockAuthenticationProviderOptions } from './base.mock'; function expectAuthenticateCall( mockClusterClient: ReturnType, diff --git a/x-pack/plugins/security/server/authentication/providers/anonymous.ts b/x-pack/plugins/security/server/authentication/providers/anonymous.ts index 8185882a31626..2efd26a9d2e19 100644 --- a/x-pack/plugins/security/server/authentication/providers/anonymous.ts +++ b/x-pack/plugins/security/server/authentication/providers/anonymous.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { KibanaRequest } from '../../../../../../src/core/server'; +import type { KibanaRequest } from 'src/core/server'; + import { getErrorStatusCode } from '../../errors'; import { AuthenticationResult } from '../authentication_result'; import { canRedirectRequest } from '../can_redirect_request'; @@ -14,7 +15,8 @@ import { BasicHTTPAuthorizationHeaderCredentials, HTTPAuthorizationHeader, } from '../http_authentication'; -import { AuthenticationProviderOptions, BaseAuthenticationProvider } from './base'; +import type { AuthenticationProviderOptions } from './base'; +import { BaseAuthenticationProvider } from './base'; /** * Credentials that are based on the username and password. diff --git a/x-pack/plugins/security/server/authentication/providers/base.mock.ts b/x-pack/plugins/security/server/authentication/providers/base.mock.ts index 424aacdb673e6..bb78b6e963763 100644 --- a/x-pack/plugins/security/server/authentication/providers/base.mock.ts +++ b/x-pack/plugins/security/server/authentication/providers/base.mock.ts @@ -6,10 +6,10 @@ */ import { - loggingSystemMock, - httpServiceMock, elasticsearchServiceMock, -} from '../../../../../../src/core/server/mocks'; + httpServiceMock, + loggingSystemMock, +} from 'src/core/server/mocks'; export type MockAuthenticationProviderOptions = ReturnType< typeof mockAuthenticationProviderOptions diff --git a/x-pack/plugins/security/server/authentication/providers/base.ts b/x-pack/plugins/security/server/authentication/providers/base.ts index 25d9c384f3073..20946ff6f5e80 100644 --- a/x-pack/plugins/security/server/authentication/providers/base.ts +++ b/x-pack/plugins/security/server/authentication/providers/base.ts @@ -7,18 +7,19 @@ import { deepFreeze } from '@kbn/std'; import type { PublicMethodsOf } from '@kbn/utility-types'; -import { - KibanaRequest, - Logger, - HttpServiceSetup, +import type { Headers, + HttpServiceSetup, IClusterClient, -} from '../../../../../../src/core/server'; + KibanaRequest, + Logger, +} from 'src/core/server'; + import type { AuthenticatedUser } from '../../../common/model'; import type { AuthenticationInfo } from '../../elasticsearch'; import { AuthenticationResult } from '../authentication_result'; -import { DeauthenticationResult } from '../deauthentication_result'; -import { Tokens } from '../tokens'; +import type { DeauthenticationResult } from '../deauthentication_result'; +import type { Tokens } from '../tokens'; /** * Represents available provider options. diff --git a/x-pack/plugins/security/server/authentication/providers/basic.test.ts b/x-pack/plugins/security/server/authentication/providers/basic.test.ts index 8a7c7f141c9e3..025589bd25b40 100644 --- a/x-pack/plugins/security/server/authentication/providers/basic.test.ts +++ b/x-pack/plugins/security/server/authentication/providers/basic.test.ts @@ -7,14 +7,14 @@ import { errors } from '@elastic/elasticsearch'; -import { elasticsearchServiceMock, httpServerMock } from '../../../../../../src/core/server/mocks'; +import type { ScopeableRequest } from 'src/core/server'; +import { elasticsearchServiceMock, httpServerMock } from 'src/core/server/mocks'; + import { mockAuthenticatedUser } from '../../../common/model/authenticated_user.mock'; import { securityMock } from '../../mocks'; -import { mockAuthenticationProviderOptions } from './base.mock'; - -import { ScopeableRequest } from '../../../../../../src/core/server'; import { AuthenticationResult } from '../authentication_result'; import { DeauthenticationResult } from '../deauthentication_result'; +import { mockAuthenticationProviderOptions } from './base.mock'; import { BasicAuthenticationProvider } from './basic'; function generateAuthorizationHeader(username: string, password: string) { diff --git a/x-pack/plugins/security/server/authentication/providers/basic.ts b/x-pack/plugins/security/server/authentication/providers/basic.ts index f9b80720e58bb..d0a3a90cae908 100644 --- a/x-pack/plugins/security/server/authentication/providers/basic.ts +++ b/x-pack/plugins/security/server/authentication/providers/basic.ts @@ -5,14 +5,15 @@ * 2.0. */ -import { KibanaRequest } from '../../../../../../src/core/server'; +import type { KibanaRequest } from 'src/core/server'; + import { NEXT_URL_QUERY_STRING_PARAMETER } from '../../../common/constants'; -import { canRedirectRequest } from '../can_redirect_request'; import { AuthenticationResult } from '../authentication_result'; +import { canRedirectRequest } from '../can_redirect_request'; import { DeauthenticationResult } from '../deauthentication_result'; import { - HTTPAuthorizationHeader, BasicHTTPAuthorizationHeaderCredentials, + HTTPAuthorizationHeader, } from '../http_authentication'; import { BaseAuthenticationProvider } from './base'; diff --git a/x-pack/plugins/security/server/authentication/providers/http.test.ts b/x-pack/plugins/security/server/authentication/providers/http.test.ts index 908af3901ffbe..451be10685558 100644 --- a/x-pack/plugins/security/server/authentication/providers/http.test.ts +++ b/x-pack/plugins/security/server/authentication/providers/http.test.ts @@ -7,14 +7,15 @@ import { errors } from '@elastic/elasticsearch'; -import { elasticsearchServiceMock, httpServerMock } from '../../../../../../src/core/server/mocks'; +import type { ScopeableRequest } from 'src/core/server'; +import { elasticsearchServiceMock, httpServerMock } from 'src/core/server/mocks'; + import { mockAuthenticatedUser } from '../../../common/model/authenticated_user.mock'; import { securityMock } from '../../mocks'; -import { MockAuthenticationProviderOptions, mockAuthenticationProviderOptions } from './base.mock'; - -import { ScopeableRequest } from '../../../../../../src/core/server'; import { AuthenticationResult } from '../authentication_result'; import { DeauthenticationResult } from '../deauthentication_result'; +import type { MockAuthenticationProviderOptions } from './base.mock'; +import { mockAuthenticationProviderOptions } from './base.mock'; import { HTTPAuthenticationProvider } from './http'; function expectAuthenticateCall( diff --git a/x-pack/plugins/security/server/authentication/providers/http.ts b/x-pack/plugins/security/server/authentication/providers/http.ts index 6e15886d1bf1c..2d5b4c5e82772 100644 --- a/x-pack/plugins/security/server/authentication/providers/http.ts +++ b/x-pack/plugins/security/server/authentication/providers/http.ts @@ -5,11 +5,13 @@ * 2.0. */ -import { KibanaRequest } from '../../../../../../src/core/server'; +import type { KibanaRequest } from 'src/core/server'; + import { AuthenticationResult } from '../authentication_result'; import { DeauthenticationResult } from '../deauthentication_result'; import { HTTPAuthorizationHeader } from '../http_authentication'; -import { AuthenticationProviderOptions, BaseAuthenticationProvider } from './base'; +import type { AuthenticationProviderOptions } from './base'; +import { BaseAuthenticationProvider } from './base'; interface HTTPAuthenticationProviderOptions { supportedSchemes: Set; diff --git a/x-pack/plugins/security/server/authentication/providers/kerberos.test.ts b/x-pack/plugins/security/server/authentication/providers/kerberos.test.ts index 92675ad02979c..1bcb845ca5c08 100644 --- a/x-pack/plugins/security/server/authentication/providers/kerberos.test.ts +++ b/x-pack/plugins/security/server/authentication/providers/kerberos.test.ts @@ -5,17 +5,18 @@ * 2.0. */ -import Boom from '@hapi/boom'; import { errors } from '@elastic/elasticsearch'; +import Boom from '@hapi/boom'; + +import type { KibanaRequest, ScopeableRequest } from 'src/core/server'; +import { elasticsearchServiceMock, httpServerMock } from 'src/core/server/mocks'; -import { elasticsearchServiceMock, httpServerMock } from '../../../../../../src/core/server/mocks'; import { mockAuthenticatedUser } from '../../../common/model/authenticated_user.mock'; import { securityMock } from '../../mocks'; -import { MockAuthenticationProviderOptions, mockAuthenticationProviderOptions } from './base.mock'; - -import { KibanaRequest, ScopeableRequest } from '../../../../../../src/core/server'; import { AuthenticationResult } from '../authentication_result'; import { DeauthenticationResult } from '../deauthentication_result'; +import type { MockAuthenticationProviderOptions } from './base.mock'; +import { mockAuthenticationProviderOptions } from './base.mock'; import { KerberosAuthenticationProvider } from './kerberos'; function expectAuthenticateCall( diff --git a/x-pack/plugins/security/server/authentication/providers/kerberos.ts b/x-pack/plugins/security/server/authentication/providers/kerberos.ts index 6740b74d61386..0de8e8e10a630 100644 --- a/x-pack/plugins/security/server/authentication/providers/kerberos.ts +++ b/x-pack/plugins/security/server/authentication/providers/kerberos.ts @@ -5,16 +5,19 @@ * 2.0. */ -import Boom from '@hapi/boom'; import { errors } from '@elastic/elasticsearch'; -import type { KibanaRequest } from '../../../../../../src/core/server'; +import Boom from '@hapi/boom'; + +import type { KibanaRequest } from 'src/core/server'; + import type { AuthenticationInfo } from '../../elasticsearch'; import { getDetailedErrorMessage, getErrorStatusCode } from '../../errors'; import { AuthenticationResult } from '../authentication_result'; +import { canRedirectRequest } from '../can_redirect_request'; import { DeauthenticationResult } from '../deauthentication_result'; import { HTTPAuthorizationHeader } from '../http_authentication'; -import { canRedirectRequest } from '../can_redirect_request'; -import { Tokens, TokenPair, RefreshTokenResult } from '../tokens'; +import type { RefreshTokenResult, TokenPair } from '../tokens'; +import { Tokens } from '../tokens'; import { BaseAuthenticationProvider } from './base'; /** diff --git a/x-pack/plugins/security/server/authentication/providers/oidc.test.ts b/x-pack/plugins/security/server/authentication/providers/oidc.test.ts index 19ccc5a6e7524..f35545e5e5f3a 100644 --- a/x-pack/plugins/security/server/authentication/providers/oidc.test.ts +++ b/x-pack/plugins/security/server/authentication/providers/oidc.test.ts @@ -5,19 +5,21 @@ * 2.0. */ -import Boom from '@hapi/boom'; import { errors } from '@elastic/elasticsearch'; +import Boom from '@hapi/boom'; -import { elasticsearchServiceMock, httpServerMock } from '../../../../../../src/core/server/mocks'; +import type { KibanaRequest } from 'src/core/server'; +import { elasticsearchServiceMock, httpServerMock } from 'src/core/server/mocks'; + +import type { AuthenticatedUser } from '../../../common/model'; import { mockAuthenticatedUser } from '../../../common/model/authenticated_user.mock'; import { securityMock } from '../../mocks'; -import { MockAuthenticationProviderOptions, mockAuthenticationProviderOptions } from './base.mock'; - -import { KibanaRequest } from '../../../../../../src/core/server'; import { AuthenticationResult } from '../authentication_result'; import { DeauthenticationResult } from '../deauthentication_result'; -import { OIDCAuthenticationProvider, OIDCLogin, ProviderLoginAttempt } from './oidc'; -import { AuthenticatedUser } from '../../../common/model'; +import type { MockAuthenticationProviderOptions } from './base.mock'; +import { mockAuthenticationProviderOptions } from './base.mock'; +import type { ProviderLoginAttempt } from './oidc'; +import { OIDCAuthenticationProvider, OIDCLogin } from './oidc'; describe('OIDCAuthenticationProvider', () => { let provider: OIDCAuthenticationProvider; diff --git a/x-pack/plugins/security/server/authentication/providers/oidc.ts b/x-pack/plugins/security/server/authentication/providers/oidc.ts index 78842bef7f48b..2afa49fe6e082 100644 --- a/x-pack/plugins/security/server/authentication/providers/oidc.ts +++ b/x-pack/plugins/security/server/authentication/providers/oidc.ts @@ -7,19 +7,19 @@ import Boom from '@hapi/boom'; import type from 'type-detect'; -import { KibanaRequest } from '../../../../../../src/core/server'; + +import type { KibanaRequest } from 'src/core/server'; + import { NEXT_URL_QUERY_STRING_PARAMETER } from '../../../common/constants'; import type { AuthenticationInfo } from '../../elasticsearch'; import { AuthenticationResult } from '../authentication_result'; import { canRedirectRequest } from '../can_redirect_request'; import { DeauthenticationResult } from '../deauthentication_result'; import { HTTPAuthorizationHeader } from '../http_authentication'; -import { Tokens, TokenPair, RefreshTokenResult } from '../tokens'; -import { - AuthenticationProviderOptions, - BaseAuthenticationProvider, - AuthenticationProviderSpecificOptions, -} from './base'; +import type { RefreshTokenResult, TokenPair } from '../tokens'; +import { Tokens } from '../tokens'; +import type { AuthenticationProviderOptions, AuthenticationProviderSpecificOptions } from './base'; +import { BaseAuthenticationProvider } from './base'; /** * Describes possible OpenID Connect login flows. diff --git a/x-pack/plugins/security/server/authentication/providers/pki.test.ts b/x-pack/plugins/security/server/authentication/providers/pki.test.ts index 7063bfbf3b373..4ad6fe61e259c 100644 --- a/x-pack/plugins/security/server/authentication/providers/pki.test.ts +++ b/x-pack/plugins/security/server/authentication/providers/pki.test.ts @@ -8,19 +8,21 @@ jest.mock('net'); jest.mock('tls'); -import { Socket } from 'net'; -import { PeerCertificate, TLSSocket } from 'tls'; -import Boom from '@hapi/boom'; import { errors } from '@elastic/elasticsearch'; +import Boom from '@hapi/boom'; +import { Socket } from 'net'; +import type { PeerCertificate } from 'tls'; +import { TLSSocket } from 'tls'; + +import type { KibanaRequest, ScopeableRequest } from 'src/core/server'; +import { elasticsearchServiceMock, httpServerMock } from 'src/core/server/mocks'; -import { elasticsearchServiceMock, httpServerMock } from '../../../../../../src/core/server/mocks'; import { mockAuthenticatedUser } from '../../../common/model/authenticated_user.mock'; import { securityMock } from '../../mocks'; -import { MockAuthenticationProviderOptions, mockAuthenticationProviderOptions } from './base.mock'; - -import { KibanaRequest, ScopeableRequest } from '../../../../../../src/core/server'; import { AuthenticationResult } from '../authentication_result'; import { DeauthenticationResult } from '../deauthentication_result'; +import type { MockAuthenticationProviderOptions } from './base.mock'; +import { mockAuthenticationProviderOptions } from './base.mock'; import { PKIAuthenticationProvider } from './pki'; interface MockPeerCertificate extends Partial { diff --git a/x-pack/plugins/security/server/authentication/providers/pki.ts b/x-pack/plugins/security/server/authentication/providers/pki.ts index 6d65eafae9060..0c002f005bce3 100644 --- a/x-pack/plugins/security/server/authentication/providers/pki.ts +++ b/x-pack/plugins/security/server/authentication/providers/pki.ts @@ -6,13 +6,15 @@ */ import Boom from '@hapi/boom'; -import { DetailedPeerCertificate } from 'tls'; -import { KibanaRequest } from '../../../../../../src/core/server'; +import type { DetailedPeerCertificate } from 'tls'; + +import type { KibanaRequest } from 'src/core/server'; + import type { AuthenticationInfo } from '../../elasticsearch'; import { AuthenticationResult } from '../authentication_result'; +import { canRedirectRequest } from '../can_redirect_request'; import { DeauthenticationResult } from '../deauthentication_result'; import { HTTPAuthorizationHeader } from '../http_authentication'; -import { canRedirectRequest } from '../can_redirect_request'; import { Tokens } from '../tokens'; import { BaseAuthenticationProvider } from './base'; diff --git a/x-pack/plugins/security/server/authentication/providers/saml.test.ts b/x-pack/plugins/security/server/authentication/providers/saml.test.ts index 2b7d56d65dbd5..50d9ab33fd96f 100644 --- a/x-pack/plugins/security/server/authentication/providers/saml.test.ts +++ b/x-pack/plugins/security/server/authentication/providers/saml.test.ts @@ -5,18 +5,19 @@ * 2.0. */ -import Boom from '@hapi/boom'; import { errors } from '@elastic/elasticsearch'; +import Boom from '@hapi/boom'; -import { elasticsearchServiceMock, httpServerMock } from '../../../../../../src/core/server/mocks'; +import { elasticsearchServiceMock, httpServerMock } from 'src/core/server/mocks'; + +import type { AuthenticatedUser } from '../../../common/model'; import { mockAuthenticatedUser } from '../../../common/model/authenticated_user.mock'; import { securityMock } from '../../mocks'; -import { MockAuthenticationProviderOptions, mockAuthenticationProviderOptions } from './base.mock'; - import { AuthenticationResult } from '../authentication_result'; import { DeauthenticationResult } from '../deauthentication_result'; +import type { MockAuthenticationProviderOptions } from './base.mock'; +import { mockAuthenticationProviderOptions } from './base.mock'; import { SAMLAuthenticationProvider, SAMLLogin } from './saml'; -import { AuthenticatedUser } from '../../../common/model'; describe('SAMLAuthenticationProvider', () => { let provider: SAMLAuthenticationProvider; diff --git a/x-pack/plugins/security/server/authentication/providers/saml.ts b/x-pack/plugins/security/server/authentication/providers/saml.ts index f7102d25e9c45..7c27e2ebeff10 100644 --- a/x-pack/plugins/security/server/authentication/providers/saml.ts +++ b/x-pack/plugins/security/server/authentication/providers/saml.ts @@ -6,16 +6,20 @@ */ import Boom from '@hapi/boom'; -import { KibanaRequest } from '../../../../../../src/core/server'; -import { isInternalURL } from '../../../common/is_internal_url'; + +import type { KibanaRequest } from 'src/core/server'; + import { NEXT_URL_QUERY_STRING_PARAMETER } from '../../../common/constants'; +import { isInternalURL } from '../../../common/is_internal_url'; import type { AuthenticationInfo } from '../../elasticsearch'; import { AuthenticationResult } from '../authentication_result'; -import { DeauthenticationResult } from '../deauthentication_result'; import { canRedirectRequest } from '../can_redirect_request'; +import { DeauthenticationResult } from '../deauthentication_result'; import { HTTPAuthorizationHeader } from '../http_authentication'; -import { Tokens, TokenPair, RefreshTokenResult } from '../tokens'; -import { AuthenticationProviderOptions, BaseAuthenticationProvider } from './base'; +import type { RefreshTokenResult, TokenPair } from '../tokens'; +import { Tokens } from '../tokens'; +import type { AuthenticationProviderOptions } from './base'; +import { BaseAuthenticationProvider } from './base'; /** * The state supported by the provider (for the SAML handshake or established session). diff --git a/x-pack/plugins/security/server/authentication/providers/token.test.ts b/x-pack/plugins/security/server/authentication/providers/token.test.ts index 3f3d1373092a6..4d80250607121 100644 --- a/x-pack/plugins/security/server/authentication/providers/token.test.ts +++ b/x-pack/plugins/security/server/authentication/providers/token.test.ts @@ -5,17 +5,18 @@ * 2.0. */ -import Boom from '@hapi/boom'; import { errors } from '@elastic/elasticsearch'; +import Boom from '@hapi/boom'; + +import type { ScopeableRequest } from 'src/core/server'; +import { elasticsearchServiceMock, httpServerMock } from 'src/core/server/mocks'; -import { elasticsearchServiceMock, httpServerMock } from '../../../../../../src/core/server/mocks'; import { mockAuthenticatedUser } from '../../../common/model/authenticated_user.mock'; import { securityMock } from '../../mocks'; -import { MockAuthenticationProviderOptions, mockAuthenticationProviderOptions } from './base.mock'; - -import { ScopeableRequest } from '../../../../../../src/core/server'; import { AuthenticationResult } from '../authentication_result'; import { DeauthenticationResult } from '../deauthentication_result'; +import type { MockAuthenticationProviderOptions } from './base.mock'; +import { mockAuthenticationProviderOptions } from './base.mock'; import { TokenAuthenticationProvider } from './token'; function expectAuthenticateCall( diff --git a/x-pack/plugins/security/server/authentication/providers/token.ts b/x-pack/plugins/security/server/authentication/providers/token.ts index 7ce13cc707c21..f202a0bd43fcf 100644 --- a/x-pack/plugins/security/server/authentication/providers/token.ts +++ b/x-pack/plugins/security/server/authentication/providers/token.ts @@ -6,15 +6,18 @@ */ import Boom from '@hapi/boom'; -import { KibanaRequest } from '../../../../../../src/core/server'; + +import type { KibanaRequest } from 'src/core/server'; + import { NEXT_URL_QUERY_STRING_PARAMETER } from '../../../common/constants'; -import { AuthenticationInfo } from '../../elasticsearch'; +import type { AuthenticationInfo } from '../../elasticsearch'; import { getDetailedErrorMessage } from '../../errors'; import { AuthenticationResult } from '../authentication_result'; -import { DeauthenticationResult } from '../deauthentication_result'; import { canRedirectRequest } from '../can_redirect_request'; +import { DeauthenticationResult } from '../deauthentication_result'; import { HTTPAuthorizationHeader } from '../http_authentication'; -import { Tokens, TokenPair, RefreshTokenResult } from '../tokens'; +import type { RefreshTokenResult, TokenPair } from '../tokens'; +import { Tokens } from '../tokens'; import { BaseAuthenticationProvider } from './base'; /** diff --git a/x-pack/plugins/security/server/authentication/tokens.test.ts b/x-pack/plugins/security/server/authentication/tokens.test.ts index b787956f79c1c..a6d52e355b145 100644 --- a/x-pack/plugins/security/server/authentication/tokens.test.ts +++ b/x-pack/plugins/security/server/authentication/tokens.test.ts @@ -6,13 +6,13 @@ */ import { errors } from '@elastic/elasticsearch'; -import { DeeplyMockedKeys } from '@kbn/utility-types/jest'; -import { elasticsearchServiceMock, loggingSystemMock } from '../../../../../src/core/server/mocks'; +import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; +import type { ElasticsearchClient } from 'src/core/server'; +import { elasticsearchServiceMock, loggingSystemMock } from 'src/core/server/mocks'; + import { mockAuthenticatedUser } from '../../common/model/authenticated_user.mock'; import { securityMock } from '../mocks'; - -import { ElasticsearchClient } from '../../../../../src/core/server'; import { Tokens } from './tokens'; describe('Tokens', () => { diff --git a/x-pack/plugins/security/server/authentication/tokens.ts b/x-pack/plugins/security/server/authentication/tokens.ts index 755ff9ac9e73b..e3c4644775613 100644 --- a/x-pack/plugins/security/server/authentication/tokens.ts +++ b/x-pack/plugins/security/server/authentication/tokens.ts @@ -5,7 +5,8 @@ * 2.0. */ -import type { ElasticsearchClient, Logger } from '../../../../../src/core/server'; +import type { ElasticsearchClient, Logger } from 'src/core/server'; + import type { AuthenticationInfo } from '../elasticsearch'; import { getErrorStatusCode } from '../errors'; diff --git a/x-pack/plugins/security/server/authorization/actions/actions.mock.ts b/x-pack/plugins/security/server/authorization/actions/actions.mock.ts index e520e8e56473b..97890e21c0eb7 100644 --- a/x-pack/plugins/security/server/authorization/actions/actions.mock.ts +++ b/x-pack/plugins/security/server/authorization/actions/actions.mock.ts @@ -5,13 +5,13 @@ * 2.0. */ +import type { Actions } from './actions'; +import { AlertingActions } from './alerting'; import { ApiActions } from './api'; import { AppActions } from './app'; import { SavedObjectActions } from './saved_object'; import { SpaceActions } from './space'; import { UIActions } from './ui'; -import { AlertingActions } from './alerting'; -import { Actions } from './actions'; jest.mock('./api'); jest.mock('./app'); diff --git a/x-pack/plugins/security/server/authorization/actions/actions.test.ts b/x-pack/plugins/security/server/authorization/actions/actions.test.ts index 7234dabf0e223..7b9e836f4db57 100644 --- a/x-pack/plugins/security/server/authorization/actions/actions.test.ts +++ b/x-pack/plugins/security/server/authorization/actions/actions.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Actions } from '.'; +import { Actions } from './actions'; describe('#constructor', () => { test(`doesn't allow an empty string`, () => { diff --git a/x-pack/plugins/security/server/authorization/actions/actions.ts b/x-pack/plugins/security/server/authorization/actions/actions.ts index ccd2480ec232a..23d07f73f04be 100644 --- a/x-pack/plugins/security/server/authorization/actions/actions.ts +++ b/x-pack/plugins/security/server/authorization/actions/actions.ts @@ -5,12 +5,12 @@ * 2.0. */ +import { AlertingActions } from './alerting'; import { ApiActions } from './api'; import { AppActions } from './app'; import { SavedObjectActions } from './saved_object'; import { SpaceActions } from './space'; import { UIActions } from './ui'; -import { AlertingActions } from './alerting'; /** Actions are used to create the "actions" that are associated with Elasticsearch's * application privileges, and are used to perform the authorization checks implemented diff --git a/x-pack/plugins/security/server/authorization/actions/ui.ts b/x-pack/plugins/security/server/authorization/actions/ui.ts index d91fdbb33f6c1..42513708def2a 100644 --- a/x-pack/plugins/security/server/authorization/actions/ui.ts +++ b/x-pack/plugins/security/server/authorization/actions/ui.ts @@ -6,7 +6,9 @@ */ import { isString } from 'lodash'; -import { Capabilities as UICapabilities } from '../../../../../../src/core/server'; + +import type { Capabilities as UICapabilities } from 'src/core/server'; + import { uiCapabilitiesRegex } from '../../../../features/server'; export class UIActions { diff --git a/x-pack/plugins/security/server/authorization/api_authorization.test.ts b/x-pack/plugins/security/server/authorization/api_authorization.test.ts index b8aa0951ac0a3..e34fc2cc2cdb2 100644 --- a/x-pack/plugins/security/server/authorization/api_authorization.test.ts +++ b/x-pack/plugins/security/server/authorization/api_authorization.test.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { initAPIAuthorization } from './api_authorization'; - import { coreMock, httpServerMock, httpServiceMock, loggingSystemMock, -} from '../../../../../src/core/server/mocks'; +} from 'src/core/server/mocks'; + +import { initAPIAuthorization } from './api_authorization'; import { authorizationMock } from './index.mock'; describe('initAPIAuthorization', () => { diff --git a/x-pack/plugins/security/server/authorization/api_authorization.ts b/x-pack/plugins/security/server/authorization/api_authorization.ts index f9c94070aedc4..dbf99bbfdf5f2 100644 --- a/x-pack/plugins/security/server/authorization/api_authorization.ts +++ b/x-pack/plugins/security/server/authorization/api_authorization.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { HttpServiceSetup, Logger } from '../../../../../src/core/server'; -import { AuthorizationServiceSetup } from '.'; +import type { HttpServiceSetup, Logger } from 'src/core/server'; + +import type { AuthorizationServiceSetup } from './authorization_service'; export function initAPIAuthorization( http: HttpServiceSetup, diff --git a/x-pack/plugins/security/server/authorization/app_authorization.test.ts b/x-pack/plugins/security/server/authorization/app_authorization.test.ts index 25a07b6a89428..0e4d902105efa 100644 --- a/x-pack/plugins/security/server/authorization/app_authorization.test.ts +++ b/x-pack/plugins/security/server/authorization/app_authorization.test.ts @@ -5,16 +5,16 @@ * 2.0. */ -import { PluginSetupContract as FeaturesSetupContract } from '../../../features/server'; -import { featuresPluginMock } from '../../../features/server/mocks'; -import { initAppAuthorization } from './app_authorization'; - import { - loggingSystemMock, coreMock, httpServerMock, httpServiceMock, -} from '../../../../../src/core/server/mocks'; + loggingSystemMock, +} from 'src/core/server/mocks'; + +import type { PluginSetupContract as FeaturesSetupContract } from '../../../features/server'; +import { featuresPluginMock } from '../../../features/server/mocks'; +import { initAppAuthorization } from './app_authorization'; import { authorizationMock } from './index.mock'; const createFeaturesSetupContractMock = (): FeaturesSetupContract => { diff --git a/x-pack/plugins/security/server/authorization/app_authorization.ts b/x-pack/plugins/security/server/authorization/app_authorization.ts index b34f2ebe16161..b57523581bc5c 100644 --- a/x-pack/plugins/security/server/authorization/app_authorization.ts +++ b/x-pack/plugins/security/server/authorization/app_authorization.ts @@ -5,9 +5,10 @@ * 2.0. */ -import { HttpServiceSetup, Logger } from '../../../../../src/core/server'; -import { PluginSetupContract as FeaturesPluginSetup } from '../../../features/server'; -import { AuthorizationServiceSetup } from '.'; +import type { HttpServiceSetup, Logger } from 'src/core/server'; + +import type { PluginSetupContract as FeaturesPluginSetup } from '../../../features/server'; +import type { AuthorizationServiceSetup } from './authorization_service'; class ProtectedApplications { private applications: Set | null = null; diff --git a/x-pack/plugins/security/server/authorization/authorization_service.test.ts b/x-pack/plugins/security/server/authorization/authorization_service.test.ts index 4259ded7f1a90..62c7dd9f8891c 100644 --- a/x-pack/plugins/security/server/authorization/authorization_service.test.ts +++ b/x-pack/plugins/security/server/authorization/authorization_service.test.ts @@ -5,6 +5,12 @@ * 2.0. */ +import { Subject } from 'rxjs'; + +import { nextTick } from '@kbn/test/jest'; +import { coreMock, elasticsearchServiceMock, loggingSystemMock } from 'src/core/server/mocks'; + +// Note: this import must be before other relative imports for the mocks to work as intended. import { mockAuthorizationModeFactory, mockCheckPrivilegesDynamicallyWithRequestFactory, @@ -14,23 +20,15 @@ import { mockRegisterPrivilegesWithCluster, } from './service.test.mocks'; -import { Subject } from 'rxjs'; -import { OnlineStatusRetryScheduler } from '../elasticsearch'; +import { featuresPluginMock } from '../../../features/server/mocks'; +import { licenseMock } from '../../common/licensing/index.mock'; +import type { OnlineStatusRetryScheduler } from '../elasticsearch'; +import { AuthorizationService } from './authorization_service'; import { checkPrivilegesWithRequestFactory } from './check_privileges'; import { checkPrivilegesDynamicallyWithRequestFactory } from './check_privileges_dynamically'; import { checkSavedObjectsPrivilegesWithRequestFactory } from './check_saved_objects_privileges'; import { authorizationModeFactory } from './mode'; import { privilegesFactory } from './privileges'; -import { AuthorizationService } from '.'; - -import { nextTick } from '@kbn/test/jest'; -import { - coreMock, - elasticsearchServiceMock, - loggingSystemMock, -} from '../../../../../src/core/server/mocks'; -import { featuresPluginMock } from '../../../features/server/mocks'; -import { licenseMock } from '../../common/licensing/index.mock'; const kibanaIndexName = '.a-kibana-index'; const application = `kibana-${kibanaIndexName}`; diff --git a/x-pack/plugins/security/server/authorization/authorization_service.tsx b/x-pack/plugins/security/server/authorization/authorization_service.tsx index 059d5c0cdebed..db3c84477ffb1 100644 --- a/x-pack/plugins/security/server/authorization/authorization_service.tsx +++ b/x-pack/plugins/security/server/authorization/authorization_service.tsx @@ -6,54 +6,49 @@ */ import querystring from 'querystring'; - import React from 'react'; import { renderToStaticMarkup } from 'react-dom/server'; -import { Subscription, Observable } from 'rxjs'; -import * as UiSharedDeps from '@kbn/ui-shared-deps'; +import type { Observable, Subscription } from 'rxjs'; -import type { Capabilities as UICapabilities } from '../../../../../src/core/types'; - -import { - LoggerFactory, - KibanaRequest, - Logger, - HttpServiceSetup, +import * as UiSharedDeps from '@kbn/ui-shared-deps'; +import type { CapabilitiesSetup, + HttpServiceSetup, IClusterClient, -} from '../../../../../src/core/server'; + KibanaRequest, + Logger, + LoggerFactory, +} from 'src/core/server'; +import type { Capabilities as UICapabilities } from 'src/core/types'; -import { +import type { PluginSetupContract as FeaturesPluginSetup, PluginStartContract as FeaturesPluginStart, } from '../../../features/server'; - -import { SpacesService } from '../plugin'; +import { APPLICATION_PREFIX } from '../../common/constants'; +import type { SecurityLicense } from '../../common/licensing'; +import type { AuthenticatedUser } from '../../common/model'; +import { canRedirectRequest } from '../authentication'; +import type { OnlineStatusRetryScheduler } from '../elasticsearch'; +import type { SpacesService } from '../plugin'; import { Actions } from './actions'; -import { checkPrivilegesWithRequestFactory } from './check_privileges'; -import { - CheckPrivilegesDynamicallyWithRequest, - checkPrivilegesDynamicallyWithRequestFactory, -} from './check_privileges_dynamically'; -import { - CheckSavedObjectsPrivilegesWithRequest, - checkSavedObjectsPrivilegesWithRequestFactory, -} from './check_saved_objects_privileges'; -import { AuthorizationMode, authorizationModeFactory } from './mode'; -import { privilegesFactory, PrivilegesService } from './privileges'; -import { initAppAuthorization } from './app_authorization'; import { initAPIAuthorization } from './api_authorization'; +import { initAppAuthorization } from './app_authorization'; +import { checkPrivilegesWithRequestFactory } from './check_privileges'; +import type { CheckPrivilegesDynamicallyWithRequest } from './check_privileges_dynamically'; +import { checkPrivilegesDynamicallyWithRequestFactory } from './check_privileges_dynamically'; +import type { CheckSavedObjectsPrivilegesWithRequest } from './check_saved_objects_privileges'; +import { checkSavedObjectsPrivilegesWithRequestFactory } from './check_saved_objects_privileges'; import { disableUICapabilitiesFactory } from './disable_ui_capabilities'; -import { validateFeaturePrivileges } from './validate_feature_privileges'; -import { validateReservedPrivileges } from './validate_reserved_privileges'; +import type { AuthorizationMode } from './mode'; +import { authorizationModeFactory } from './mode'; +import type { PrivilegesService } from './privileges'; +import { privilegesFactory } from './privileges'; import { registerPrivilegesWithCluster } from './register_privileges_with_cluster'; -import { APPLICATION_PREFIX } from '../../common/constants'; -import { SecurityLicense } from '../../common/licensing'; -import { CheckPrivilegesWithRequest } from './types'; -import { OnlineStatusRetryScheduler } from '../elasticsearch'; -import { canRedirectRequest } from '../authentication'; import { ResetSessionPage } from './reset_session_page'; -import { AuthenticatedUser } from '..'; +import type { CheckPrivilegesWithRequest } from './types'; +import { validateFeaturePrivileges } from './validate_feature_privileges'; +import { validateReservedPrivileges } from './validate_reserved_privileges'; export { Actions } from './actions'; export { CheckSavedObjectsPrivileges } from './check_saved_objects_privileges'; diff --git a/x-pack/plugins/security/server/authorization/check_privileges.test.ts b/x-pack/plugins/security/server/authorization/check_privileges.test.ts index 5bca46f22a512..2c1deed0f8c30 100644 --- a/x-pack/plugins/security/server/authorization/check_privileges.test.ts +++ b/x-pack/plugins/security/server/authorization/check_privileges.test.ts @@ -6,11 +6,12 @@ */ import { uniq } from 'lodash'; + +import { elasticsearchServiceMock, httpServerMock } from 'src/core/server/mocks'; + import { GLOBAL_RESOURCE } from '../../common/constants'; import { checkPrivilegesWithRequestFactory } from './check_privileges'; -import { HasPrivilegesResponse } from './types'; - -import { elasticsearchServiceMock, httpServerMock } from '../../../../../src/core/server/mocks'; +import type { HasPrivilegesResponse } from './types'; const application = 'kibana-our_application'; diff --git a/x-pack/plugins/security/server/authorization/check_privileges.ts b/x-pack/plugins/security/server/authorization/check_privileges.ts index c11be0e412d43..0fc11cddf9bbc 100644 --- a/x-pack/plugins/security/server/authorization/check_privileges.ts +++ b/x-pack/plugins/security/server/authorization/check_privileges.ts @@ -6,15 +6,17 @@ */ import { pick, transform, uniq } from 'lodash'; -import { IClusterClient, KibanaRequest } from '../../../../../src/core/server'; + +import type { IClusterClient, KibanaRequest } from 'src/core/server'; + import { GLOBAL_RESOURCE } from '../../common/constants'; import { ResourceSerializer } from './resource_serializer'; -import { - HasPrivilegesResponse, - HasPrivilegesResponseApplication, - CheckPrivilegesPayload, +import type { CheckPrivileges, + CheckPrivilegesPayload, CheckPrivilegesResponse, + HasPrivilegesResponse, + HasPrivilegesResponseApplication, } from './types'; import { validateEsPrivilegeResponse } from './validate_es_response'; diff --git a/x-pack/plugins/security/server/authorization/check_privileges_dynamically.test.ts b/x-pack/plugins/security/server/authorization/check_privileges_dynamically.test.ts index 10893313403f3..547782bbd1ba1 100644 --- a/x-pack/plugins/security/server/authorization/check_privileges_dynamically.test.ts +++ b/x-pack/plugins/security/server/authorization/check_privileges_dynamically.test.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { checkPrivilegesDynamicallyWithRequestFactory } from './check_privileges_dynamically'; +import { httpServerMock } from 'src/core/server/mocks'; -import { httpServerMock } from '../../../../../src/core/server/mocks'; +import { checkPrivilegesDynamicallyWithRequestFactory } from './check_privileges_dynamically'; test(`checkPrivileges.atSpace when spaces is enabled`, async () => { const expectedResult = Symbol(); diff --git a/x-pack/plugins/security/server/authorization/check_privileges_dynamically.ts b/x-pack/plugins/security/server/authorization/check_privileges_dynamically.ts index d238f5f53895f..4ce59c8706270 100644 --- a/x-pack/plugins/security/server/authorization/check_privileges_dynamically.ts +++ b/x-pack/plugins/security/server/authorization/check_privileges_dynamically.ts @@ -5,10 +5,14 @@ * 2.0. */ -import { KibanaRequest } from '../../../../../src/core/server'; -import { SpacesService } from '../plugin'; -import { CheckPrivilegesResponse, CheckPrivilegesWithRequest } from './types'; -import { CheckPrivilegesPayload } from './types'; +import type { KibanaRequest } from 'src/core/server'; + +import type { SpacesService } from '../plugin'; +import type { + CheckPrivilegesPayload, + CheckPrivilegesResponse, + CheckPrivilegesWithRequest, +} from './types'; export type CheckPrivilegesDynamically = ( privileges: CheckPrivilegesPayload diff --git a/x-pack/plugins/security/server/authorization/check_saved_objects_privileges.test.ts b/x-pack/plugins/security/server/authorization/check_saved_objects_privileges.test.ts index bf09d390880cf..8436295b74989 100644 --- a/x-pack/plugins/security/server/authorization/check_saved_objects_privileges.test.ts +++ b/x-pack/plugins/security/server/authorization/check_saved_objects_privileges.test.ts @@ -5,11 +5,11 @@ * 2.0. */ -import { checkSavedObjectsPrivilegesWithRequestFactory } from './check_saved_objects_privileges'; +import { httpServerMock } from 'src/core/server/mocks'; -import { httpServerMock } from '../../../../../src/core/server/mocks'; -import { CheckPrivileges, CheckPrivilegesWithRequest } from './types'; -import { SpacesService } from '../plugin'; +import type { SpacesService } from '../plugin'; +import { checkSavedObjectsPrivilegesWithRequestFactory } from './check_saved_objects_privileges'; +import type { CheckPrivileges, CheckPrivilegesWithRequest } from './types'; let mockCheckPrivileges: jest.Mocked; let mockCheckPrivilegesWithRequest: jest.Mocked; diff --git a/x-pack/plugins/security/server/authorization/check_saved_objects_privileges.ts b/x-pack/plugins/security/server/authorization/check_saved_objects_privileges.ts index cf8447c145ad8..f640848c9b08e 100644 --- a/x-pack/plugins/security/server/authorization/check_saved_objects_privileges.ts +++ b/x-pack/plugins/security/server/authorization/check_saved_objects_privileges.ts @@ -5,10 +5,11 @@ * 2.0. */ -import { KibanaRequest } from '../../../../../src/core/server'; +import type { KibanaRequest } from 'src/core/server'; + import { ALL_SPACES_ID } from '../../common/constants'; -import { SpacesService } from '../plugin'; -import { CheckPrivilegesWithRequest, CheckPrivilegesResponse } from './types'; +import type { SpacesService } from '../plugin'; +import type { CheckPrivilegesResponse, CheckPrivilegesWithRequest } from './types'; export type CheckSavedObjectsPrivilegesWithRequest = ( request: KibanaRequest diff --git a/x-pack/plugins/security/server/authorization/disable_ui_capabilities.test.ts b/x-pack/plugins/security/server/authorization/disable_ui_capabilities.test.ts index e599d42861756..15fb7ab39a044 100644 --- a/x-pack/plugins/security/server/authorization/disable_ui_capabilities.test.ts +++ b/x-pack/plugins/security/server/authorization/disable_ui_capabilities.test.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { Actions } from '.'; -import { disableUICapabilitiesFactory } from './disable_ui_capabilities'; +import { httpServerMock, loggingSystemMock } from 'src/core/server/mocks'; -import { httpServerMock, loggingSystemMock } from '../../../../../src/core/server/mocks'; +import { ElasticsearchFeature, KibanaFeature } from '../../../features/server'; +import type { AuthenticatedUser } from '../../common/model'; +import { Actions } from './actions'; +import { disableUICapabilitiesFactory } from './disable_ui_capabilities'; import { authorizationMock } from './index.mock'; -import { KibanaFeature, ElasticsearchFeature } from '../../../features/server'; -import { AuthenticatedUser } from '..'; -import { CheckPrivilegesResponse } from './types'; +import type { CheckPrivilegesResponse } from './types'; type MockAuthzOptions = | { rejectCheckPrivileges: any } diff --git a/x-pack/plugins/security/server/authorization/disable_ui_capabilities.ts b/x-pack/plugins/security/server/authorization/disable_ui_capabilities.ts index f59b2fcfde785..76f270f297820 100644 --- a/x-pack/plugins/security/server/authorization/disable_ui_capabilities.ts +++ b/x-pack/plugins/security/server/authorization/disable_ui_capabilities.ts @@ -6,18 +6,19 @@ */ import { flatten, isObject, mapValues } from 'lodash'; -import { RecursiveReadonly, RecursiveReadonlyArray } from '@kbn/utility-types'; -import type { Capabilities as UICapabilities } from '../../../../../src/core/types'; -import { KibanaRequest, Logger } from '../../../../../src/core/server'; -import { - KibanaFeature, + +import type { RecursiveReadonly, RecursiveReadonlyArray } from '@kbn/utility-types'; +import type { KibanaRequest, Logger } from 'src/core/server'; +import type { Capabilities as UICapabilities } from 'src/core/types'; + +import type { ElasticsearchFeature, FeatureElasticsearchPrivileges, + KibanaFeature, } from '../../../features/server'; - -import { CheckPrivilegesResponse } from './types'; -import { AuthorizationServiceSetup } from '.'; -import { AuthenticatedUser } from '..'; +import type { AuthenticatedUser } from '../../common/model'; +import type { AuthorizationServiceSetup } from './authorization_service'; +import type { CheckPrivilegesResponse } from './types'; export function disableUICapabilitiesFactory( request: KibanaRequest, diff --git a/x-pack/plugins/security/server/authorization/index.mock.ts b/x-pack/plugins/security/server/authorization/index.mock.ts index 53adb53ce3811..7416f2725938d 100644 --- a/x-pack/plugins/security/server/authorization/index.mock.ts +++ b/x-pack/plugins/security/server/authorization/index.mock.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { AuthorizationMode } from './mode'; import { actionsMock } from './actions/actions.mock'; +import type { AuthorizationMode } from './mode'; export const authorizationMock = { create: ({ diff --git a/x-pack/plugins/security/server/authorization/mode.test.ts b/x-pack/plugins/security/server/authorization/mode.test.ts index 6fe3b17e7f776..f0f01d500fede 100644 --- a/x-pack/plugins/security/server/authorization/mode.test.ts +++ b/x-pack/plugins/security/server/authorization/mode.test.ts @@ -5,12 +5,12 @@ * 2.0. */ -import { authorizationModeFactory } from './mode'; +import { httpServerMock } from 'src/core/server/mocks'; -import { httpServerMock } from '../../../../../src/core/server/mocks'; +import type { SecurityLicense } from '../../common/licensing'; import { licenseMock } from '../../common/licensing/index.mock'; -import { SecurityLicenseFeatures } from '../../common/licensing/license_features'; -import { SecurityLicense } from '../../common/licensing'; +import type { SecurityLicenseFeatures } from '../../common/licensing/license_features'; +import { authorizationModeFactory } from './mode'; describe(`#useRbacForRequest`, () => { let mockLicense: jest.Mocked; diff --git a/x-pack/plugins/security/server/authorization/mode.ts b/x-pack/plugins/security/server/authorization/mode.ts index 81122aabc8992..c2f6fcb0ac5cd 100644 --- a/x-pack/plugins/security/server/authorization/mode.ts +++ b/x-pack/plugins/security/server/authorization/mode.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { KibanaRequest } from '../../../../../src/core/server'; -import { SecurityLicense } from '../../common/licensing'; +import type { KibanaRequest } from 'src/core/server'; + +import type { SecurityLicense } from '../../common/licensing'; export interface AuthorizationMode { useRbacForRequest(request: KibanaRequest): boolean; diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.test.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.test.ts index f5d07525b8669..34bfb113ab0ea 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.test.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.test.ts @@ -5,9 +5,10 @@ * 2.0. */ +import type { FeatureKibanaPrivileges } from '../../../../../features/server'; +import { KibanaFeature } from '../../../../../features/server'; import { Actions } from '../../actions'; import { FeaturePrivilegeAlertingBuilder } from './alerting'; -import { KibanaFeature, FeatureKibanaPrivileges } from '../../../../../features/server'; const version = '1.0.0-zeta1'; diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.ts index 2c31ec3f2255b..c813f0f935cf5 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.ts @@ -6,7 +6,8 @@ */ import { uniq } from 'lodash'; -import { KibanaFeature, FeatureKibanaPrivileges } from '../../../../../features/server'; + +import type { FeatureKibanaPrivileges, KibanaFeature } from '../../../../../features/server'; import { BaseFeaturePrivilegeBuilder } from './feature_privilege_builder'; const readOperations: string[] = ['get', 'getAlertState', 'getAlertInstanceSummary', 'find']; diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/api.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/api.ts index 1e6eb65a9d9f3..5fe6b55f1c709 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/api.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/api.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FeatureKibanaPrivileges } from '../../../../../features/server'; +import type { FeatureKibanaPrivileges } from '../../../../../features/server'; import { BaseFeaturePrivilegeBuilder } from './feature_privilege_builder'; export class FeaturePrivilegeApiBuilder extends BaseFeaturePrivilegeBuilder { diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/app.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/app.ts index cfe8ffe8c84ad..f88d315fa1ef1 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/app.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/app.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FeatureKibanaPrivileges } from '../../../../../features/server'; +import type { FeatureKibanaPrivileges } from '../../../../../features/server'; import { BaseFeaturePrivilegeBuilder } from './feature_privilege_builder'; export class FeaturePrivilegeAppBuilder extends BaseFeaturePrivilegeBuilder { diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/catalogue.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/catalogue.ts index 14c5c70324295..0cfc31975cc2f 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/catalogue.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/catalogue.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FeatureKibanaPrivileges } from '../../../../../features/server'; +import type { FeatureKibanaPrivileges } from '../../../../../features/server'; import { BaseFeaturePrivilegeBuilder } from './feature_privilege_builder'; export class FeaturePrivilegeCatalogueBuilder extends BaseFeaturePrivilegeBuilder { diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/feature_privilege_builder.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/feature_privilege_builder.ts index 15e8536d15713..b62e5094ba09b 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/feature_privilege_builder.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/feature_privilege_builder.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { KibanaFeature, FeatureKibanaPrivileges } from '../../../../../features/server'; -import { Actions } from '../../actions'; +import type { FeatureKibanaPrivileges, KibanaFeature } from '../../../../../features/server'; +import type { Actions } from '../../actions'; export interface FeaturePrivilegeBuilder { getActions(privilegeDefinition: FeatureKibanaPrivileges, feature: KibanaFeature): string[]; diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/index.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/index.ts index c63098c1d351f..21cf2421ce1b2 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/index.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/index.ts @@ -6,8 +6,10 @@ */ import { flatten } from 'lodash'; -import { KibanaFeature, FeatureKibanaPrivileges } from '../../../../../features/server'; -import { Actions } from '../../actions'; + +import type { FeatureKibanaPrivileges, KibanaFeature } from '../../../../../features/server'; +import type { Actions } from '../../actions'; +import { FeaturePrivilegeAlertingBuilder } from './alerting'; import { FeaturePrivilegeApiBuilder } from './api'; import { FeaturePrivilegeAppBuilder } from './app'; import { FeaturePrivilegeCatalogueBuilder } from './catalogue'; @@ -15,8 +17,8 @@ import { FeaturePrivilegeBuilder } from './feature_privilege_builder'; import { FeaturePrivilegeManagementBuilder } from './management'; import { FeaturePrivilegeNavlinkBuilder } from './navlink'; import { FeaturePrivilegeSavedObjectBuilder } from './saved_object'; -import { FeaturePrivilegeAlertingBuilder } from './alerting'; import { FeaturePrivilegeUIBuilder } from './ui'; + export { FeaturePrivilegeBuilder }; export const featurePrivilegeBuilderFactory = (actions: Actions): FeaturePrivilegeBuilder => { diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/management.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/management.ts index 7d1fdc926ea8b..dd6a916618492 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/management.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/management.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FeatureKibanaPrivileges } from '../../../../../features/server'; +import type { FeatureKibanaPrivileges } from '../../../../../features/server'; import { BaseFeaturePrivilegeBuilder } from './feature_privilege_builder'; export class FeaturePrivilegeManagementBuilder extends BaseFeaturePrivilegeBuilder { diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/navlink.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/navlink.ts index 7d185d040e4c9..b1d9c06b4cef9 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/navlink.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/navlink.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FeatureKibanaPrivileges } from '../../../../../features/server'; +import type { FeatureKibanaPrivileges } from '../../../../../features/server'; import { BaseFeaturePrivilegeBuilder } from './feature_privilege_builder'; export class FeaturePrivilegeNavlinkBuilder extends BaseFeaturePrivilegeBuilder { diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/saved_object.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/saved_object.ts index 3a0d9f4a5a100..ea373b72aec24 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/saved_object.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/saved_object.ts @@ -6,7 +6,8 @@ */ import { flatten, uniq } from 'lodash'; -import { FeatureKibanaPrivileges } from '../../../../../features/server'; + +import type { FeatureKibanaPrivileges } from '../../../../../features/server'; import { BaseFeaturePrivilegeBuilder } from './feature_privilege_builder'; const readOperations: string[] = [ diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/ui.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/ui.ts index 76a4fc8ef778c..e1d76d3d92022 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/ui.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/ui.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { KibanaFeature, FeatureKibanaPrivileges } from '../../../../../features/server'; +import type { FeatureKibanaPrivileges, KibanaFeature } from '../../../../../features/server'; import { BaseFeaturePrivilegeBuilder } from './feature_privilege_builder'; export class FeaturePrivilegeUIBuilder extends BaseFeaturePrivilegeBuilder { diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_iterator/feature_privilege_iterator.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_iterator/feature_privilege_iterator.ts index d7f46840fa123..de2f44a446a19 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_iterator/feature_privilege_iterator.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_iterator/feature_privilege_iterator.ts @@ -6,8 +6,9 @@ */ import _ from 'lodash'; -import { LicenseType } from '../../../../../licensing/server'; -import { KibanaFeature, FeatureKibanaPrivileges } from '../../../../../features/server'; + +import type { FeatureKibanaPrivileges, KibanaFeature } from '../../../../../features/server'; +import type { LicenseType } from '../../../../../licensing/server'; import { subFeaturePrivilegeIterator } from './sub_feature_privilege_iterator'; interface IteratorOptions { diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_iterator/sub_feature_privilege_iterator.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_iterator/sub_feature_privilege_iterator.ts index 481c3448b1029..4e71fb363b080 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_iterator/sub_feature_privilege_iterator.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_iterator/sub_feature_privilege_iterator.ts @@ -5,9 +5,8 @@ * 2.0. */ -import { LicenseType } from '../../../../../licensing/server'; - -import { KibanaFeature, SubFeaturePrivilegeConfig } from '../../../../../features/common'; +import type { KibanaFeature, SubFeaturePrivilegeConfig } from '../../../../../features/common'; +import type { LicenseType } from '../../../../../licensing/server'; export function* subFeaturePrivilegeIterator( feature: KibanaFeature, diff --git a/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts b/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts index da2639aba1c6b..4da0020e94b15 100644 --- a/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts +++ b/x-pack/plugins/security/server/authorization/privileges/privileges.test.ts @@ -6,11 +6,10 @@ */ import { KibanaFeature } from '../../../../features/server'; +import { featuresPluginMock } from '../../../../features/server/mocks'; import { Actions } from '../actions'; import { privilegesFactory } from './privileges'; -import { featuresPluginMock } from '../../../../features/server/mocks'; - const actions = new Actions('1.0.0-zeta1'); describe('features', () => { diff --git a/x-pack/plugins/security/server/authorization/privileges/privileges.ts b/x-pack/plugins/security/server/authorization/privileges/privileges.ts index 49b566700f392..de0db392bdc86 100644 --- a/x-pack/plugins/security/server/authorization/privileges/privileges.ts +++ b/x-pack/plugins/security/server/authorization/privileges/privileges.ts @@ -6,13 +6,14 @@ */ import { uniq } from 'lodash'; -import { SecurityLicense } from '../../../common/licensing'; -import { + +import type { KibanaFeature, PluginSetupContract as FeaturesPluginSetup, } from '../../../../features/server'; -import { RawKibanaPrivileges } from '../../../common/model'; -import { Actions } from '../actions'; +import type { SecurityLicense } from '../../../common/licensing'; +import type { RawKibanaPrivileges } from '../../../common/model'; +import type { Actions } from '../actions'; import { featurePrivilegeBuilderFactory } from './feature_privilege_builder'; import { featurePrivilegeIterator, diff --git a/x-pack/plugins/security/server/authorization/privileges_serializer.ts b/x-pack/plugins/security/server/authorization/privileges_serializer.ts index 810065eb977bb..58b5ee50dc8f1 100644 --- a/x-pack/plugins/security/server/authorization/privileges_serializer.ts +++ b/x-pack/plugins/security/server/authorization/privileges_serializer.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { RawKibanaPrivileges } from '../../common/model'; +import type { RawKibanaPrivileges } from '../../common/model'; import { PrivilegeSerializer } from './privilege_serializer'; interface SerializedPrivilege { diff --git a/x-pack/plugins/security/server/authorization/register_privileges_with_cluster.test.ts b/x-pack/plugins/security/server/authorization/register_privileges_with_cluster.test.ts index e6ed329440e59..ee5d3373ffcdb 100644 --- a/x-pack/plugins/security/server/authorization/register_privileges_with_cluster.test.ts +++ b/x-pack/plugins/security/server/authorization/register_privileges_with_cluster.test.ts @@ -7,11 +7,11 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { Logger } from 'kibana/server'; -import { RawKibanaPrivileges } from '../../common/model'; -import { registerPrivilegesWithCluster } from './register_privileges_with_cluster'; +import type { Logger } from 'src/core/server'; +import { elasticsearchServiceMock, loggingSystemMock } from 'src/core/server/mocks'; -import { elasticsearchServiceMock, loggingSystemMock } from '../../../../../src/core/server/mocks'; +import type { RawKibanaPrivileges } from '../../common/model'; +import { registerPrivilegesWithCluster } from './register_privileges_with_cluster'; const application = 'default-application'; const registerPrivilegesWithClusterTest = ( diff --git a/x-pack/plugins/security/server/authorization/register_privileges_with_cluster.ts b/x-pack/plugins/security/server/authorization/register_privileges_with_cluster.ts index 15e62c317cb18..f32835e7727fc 100644 --- a/x-pack/plugins/security/server/authorization/register_privileges_with_cluster.ts +++ b/x-pack/plugins/security/server/authorization/register_privileges_with_cluster.ts @@ -5,11 +5,12 @@ * 2.0. */ -import { isEqual, isEqualWith, difference } from 'lodash'; -import { IClusterClient, Logger } from '../../../../../src/core/server'; +import { difference, isEqual, isEqualWith } from 'lodash'; +import type { IClusterClient, Logger } from 'src/core/server'; + +import type { PrivilegesService } from './privileges'; import { serializePrivileges } from './privileges_serializer'; -import { PrivilegesService } from './privileges'; export async function registerPrivilegesWithCluster( logger: Logger, diff --git a/x-pack/plugins/security/server/authorization/reset_session_page.test.tsx b/x-pack/plugins/security/server/authorization/reset_session_page.test.tsx index 8110000622452..e76c8ff138fcb 100644 --- a/x-pack/plugins/security/server/authorization/reset_session_page.test.tsx +++ b/x-pack/plugins/security/server/authorization/reset_session_page.test.tsx @@ -7,9 +7,10 @@ import React from 'react'; import { renderToStaticMarkup } from 'react-dom/server'; + import { ResetSessionPage } from './reset_session_page'; -jest.mock('../../../../../src/core/server/rendering/views/fonts', () => ({ +jest.mock('src/core/server/rendering/views/fonts', () => ({ Fonts: () => <>MockedFonts, })); diff --git a/x-pack/plugins/security/server/authorization/reset_session_page.tsx b/x-pack/plugins/security/server/authorization/reset_session_page.tsx index 30f4bf3854fd8..c2d43cd3dd030 100644 --- a/x-pack/plugins/security/server/authorization/reset_session_page.tsx +++ b/x-pack/plugins/security/server/authorization/reset_session_page.tsx @@ -5,20 +5,20 @@ * 2.0. */ -import React from 'react'; // @ts-expect-error no definitions in component folder import { EuiButton, EuiButtonEmpty } from '@elastic/eui/lib/components/button'; // @ts-expect-error no definitions in component folder -import { EuiPage, EuiPageBody, EuiPageContent } from '@elastic/eui/lib/components/page'; -// @ts-expect-error no definitions in component folder import { EuiEmptyPrompt } from '@elastic/eui/lib/components/empty_prompt'; // @ts-expect-error no definitions in component folder +import { icon as EuiIconAlert } from '@elastic/eui/lib/components/icon/assets/alert'; +// @ts-expect-error no definitions in component folder import { appendIconComponentCache } from '@elastic/eui/lib/components/icon/icon'; // @ts-expect-error no definitions in component folder -import { icon as EuiIconAlert } from '@elastic/eui/lib/components/icon/assets/alert'; +import { EuiPage, EuiPageBody, EuiPageContent } from '@elastic/eui/lib/components/page'; +import React from 'react'; -import { FormattedMessage, I18nProvider } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage, I18nProvider } from '@kbn/i18n/react'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { Fonts } from '../../../../../src/core/server/rendering/views/fonts'; diff --git a/x-pack/plugins/security/server/authorization/types.ts b/x-pack/plugins/security/server/authorization/types.ts index 1e682b9c1b3b0..8bfe892840637 100644 --- a/x-pack/plugins/security/server/authorization/types.ts +++ b/x-pack/plugins/security/server/authorization/types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { KibanaRequest } from 'src/core/server'; +import type { KibanaRequest } from 'src/core/server'; export interface HasPrivilegesResponseApplication { [resource: string]: { diff --git a/x-pack/plugins/security/server/authorization/validate_es_response.ts b/x-pack/plugins/security/server/authorization/validate_es_response.ts index 270ff26716e3f..d941b2d777c4f 100644 --- a/x-pack/plugins/security/server/authorization/validate_es_response.ts +++ b/x-pack/plugins/security/server/authorization/validate_es_response.ts @@ -6,7 +6,8 @@ */ import { schema } from '@kbn/config-schema'; -import { HasPrivilegesResponse } from './types'; + +import type { HasPrivilegesResponse } from './types'; /** * Validates an Elasticsearch "Has privileges" response against the expected application, actions, and resources. diff --git a/x-pack/plugins/security/server/authorization/validate_feature_privileges.ts b/x-pack/plugins/security/server/authorization/validate_feature_privileges.ts index 8df9c73a29d82..8bb53b076d46c 100644 --- a/x-pack/plugins/security/server/authorization/validate_feature_privileges.ts +++ b/x-pack/plugins/security/server/authorization/validate_feature_privileges.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { KibanaFeature } from '../../../features/server'; +import type { KibanaFeature } from '../../../features/server'; export function validateFeaturePrivileges(features: KibanaFeature[]) { for (const feature of features) { diff --git a/x-pack/plugins/security/server/authorization/validate_reserved_privileges.ts b/x-pack/plugins/security/server/authorization/validate_reserved_privileges.ts index 80adce08d6f22..7dd6ec21bdf30 100644 --- a/x-pack/plugins/security/server/authorization/validate_reserved_privileges.ts +++ b/x-pack/plugins/security/server/authorization/validate_reserved_privileges.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { KibanaFeature } from '../../../features/server'; +import type { KibanaFeature } from '../../../features/server'; export function validateReservedPrivileges(features: KibanaFeature[]) { const seenPrivilegeIds = new Set(); diff --git a/x-pack/plugins/security/server/config.test.ts b/x-pack/plugins/security/server/config.test.ts index 53e4152b3c8fb..9e266d774e86e 100644 --- a/x-pack/plugins/security/server/config.test.ts +++ b/x-pack/plugins/security/server/config.test.ts @@ -10,8 +10,9 @@ jest.mock('crypto', () => ({ constants: jest.requireActual('crypto').constants, })); -import { loggingSystemMock } from '../../../../src/core/server/mocks'; -import { createConfig, ConfigSchema } from './config'; +import { loggingSystemMock } from 'src/core/server/mocks'; + +import { ConfigSchema, createConfig } from './config'; describe('config schema', () => { it('generates proper defaults', () => { diff --git a/x-pack/plugins/security/server/config.ts b/x-pack/plugins/security/server/config.ts index 91444e3612901..ce83a92e23ae7 100644 --- a/x-pack/plugins/security/server/config.ts +++ b/x-pack/plugins/security/server/config.ts @@ -7,9 +7,13 @@ import crypto from 'crypto'; import type { Duration } from 'moment'; -import { schema, Type, TypeOf } from '@kbn/config-schema'; + +import type { Type, TypeOf } from '@kbn/config-schema'; +import { schema } from '@kbn/config-schema'; import { i18n } from '@kbn/i18n'; -import { Logger, config as coreConfig } from '../../../../src/core/server'; +import type { Logger } from 'src/core/server'; + +import { config as coreConfig } from '../../../../src/core/server'; import type { AuthenticationProvider } from '../common/model'; export type ConfigType = ReturnType; diff --git a/x-pack/plugins/security/server/config_deprecations.test.ts b/x-pack/plugins/security/server/config_deprecations.test.ts index c4c7f399e7b5d..2b6ad603e6163 100644 --- a/x-pack/plugins/security/server/config_deprecations.test.ts +++ b/x-pack/plugins/security/server/config_deprecations.test.ts @@ -5,10 +5,12 @@ * 2.0. */ -import { configDeprecationFactory, applyDeprecations } from '@kbn/config'; -import { securityConfigDeprecationProvider } from './config_deprecations'; import { cloneDeep } from 'lodash'; +import { applyDeprecations, configDeprecationFactory } from '@kbn/config'; + +import { securityConfigDeprecationProvider } from './config_deprecations'; + const applyConfigDeprecations = (settings: Record = {}) => { const deprecations = securityConfigDeprecationProvider(configDeprecationFactory); const deprecationMessages: string[] = []; diff --git a/x-pack/plugins/security/server/elasticsearch/elasticsearch_service.test.ts b/x-pack/plugins/security/server/elasticsearch/elasticsearch_service.test.ts index 1aed68220c839..15af59fdae7d1 100644 --- a/x-pack/plugins/security/server/elasticsearch/elasticsearch_service.test.ts +++ b/x-pack/plugins/security/server/elasticsearch/elasticsearch_service.test.ts @@ -6,13 +6,15 @@ */ import { BehaviorSubject } from 'rxjs'; -import { ServiceStatusLevels, CoreStatus } from '../../../../../src/core/server'; -import { SecurityLicense, SecurityLicenseFeatures } from '../../common/licensing'; -import { ElasticsearchService } from './elasticsearch_service'; -import { coreMock, loggingSystemMock } from '../../../../../src/core/server/mocks'; -import { licenseMock } from '../../common/licensing/index.mock'; import { nextTick } from '@kbn/test/jest'; +import type { CoreStatus } from 'src/core/server'; +import { ServiceStatusLevels } from 'src/core/server'; +import { coreMock, loggingSystemMock } from 'src/core/server/mocks'; + +import type { SecurityLicense, SecurityLicenseFeatures } from '../../common/licensing'; +import { licenseMock } from '../../common/licensing/index.mock'; +import { ElasticsearchService } from './elasticsearch_service'; describe('ElasticsearchService', () => { let service: ElasticsearchService; diff --git a/x-pack/plugins/security/server/elasticsearch/elasticsearch_service.ts b/x-pack/plugins/security/server/elasticsearch/elasticsearch_service.ts index 00fe140707ad5..873ed32d4b8a2 100644 --- a/x-pack/plugins/security/server/elasticsearch/elasticsearch_service.ts +++ b/x-pack/plugins/security/server/elasticsearch/elasticsearch_service.ts @@ -5,10 +5,14 @@ * 2.0. */ -import { BehaviorSubject, combineLatest, Observable } from 'rxjs'; +import type { Observable } from 'rxjs'; +import { BehaviorSubject, combineLatest } from 'rxjs'; import { distinctUntilChanged, filter, map, shareReplay, tap } from 'rxjs/operators'; -import { Logger, ServiceStatusLevels, StatusServiceSetup } from '../../../../../src/core/server'; -import { SecurityLicense } from '../../common/licensing'; + +import type { Logger, StatusServiceSetup } from 'src/core/server'; + +import { ServiceStatusLevels } from '../../../../../src/core/server'; +import type { SecurityLicense } from '../../common/licensing'; export interface ElasticsearchServiceSetupParams { readonly status: StatusServiceSetup; diff --git a/x-pack/plugins/security/server/errors.test.ts b/x-pack/plugins/security/server/errors.test.ts index 6070f8a779d85..9aa8635793281 100644 --- a/x-pack/plugins/security/server/errors.test.ts +++ b/x-pack/plugins/security/server/errors.test.ts @@ -5,9 +5,10 @@ * 2.0. */ -import Boom from '@hapi/boom'; import { errors as esErrors } from '@elastic/elasticsearch'; +import Boom from '@hapi/boom'; import { errors as legacyESErrors } from 'elasticsearch'; + import * as errors from './errors'; import { securityMock } from './mocks'; diff --git a/x-pack/plugins/security/server/errors.ts b/x-pack/plugins/security/server/errors.ts index b02945c5b3647..25d2aa44f3dc8 100644 --- a/x-pack/plugins/security/server/errors.ts +++ b/x-pack/plugins/security/server/errors.ts @@ -5,9 +5,10 @@ * 2.0. */ -import Boom from '@hapi/boom'; import { errors } from '@elastic/elasticsearch'; -import type { CustomHttpResponseOptions, ResponseError } from '../../../../src/core/server'; +import Boom from '@hapi/boom'; + +import type { CustomHttpResponseOptions, ResponseError } from 'src/core/server'; export function wrapError(error: any) { return Boom.boomify(error, { statusCode: getErrorStatusCode(error) }); diff --git a/x-pack/plugins/security/server/feature_usage/feature_usage_service.ts b/x-pack/plugins/security/server/feature_usage/feature_usage_service.ts index 9b82eaf200fcb..d8385867e93d6 100644 --- a/x-pack/plugins/security/server/feature_usage/feature_usage_service.ts +++ b/x-pack/plugins/security/server/feature_usage/feature_usage_service.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FeatureUsageServiceSetup, FeatureUsageServiceStart } from '../../../licensing/server'; +import type { FeatureUsageServiceSetup, FeatureUsageServiceStart } from '../../../licensing/server'; interface SetupDeps { featureUsage: FeatureUsageServiceSetup; diff --git a/x-pack/plugins/security/server/feature_usage/index.mock.ts b/x-pack/plugins/security/server/feature_usage/index.mock.ts index 2c1a45e9f12f0..34cd61a761106 100644 --- a/x-pack/plugins/security/server/feature_usage/index.mock.ts +++ b/x-pack/plugins/security/server/feature_usage/index.mock.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { SecurityFeatureUsageServiceStart } from './feature_usage_service'; +import type { SecurityFeatureUsageServiceStart } from './feature_usage_service'; export const securityFeatureUsageServiceMock = { createStartContract() { diff --git a/x-pack/plugins/security/server/features/security_features.ts b/x-pack/plugins/security/server/features/security_features.ts index 7b40849aaeaaa..4477ca2409faa 100644 --- a/x-pack/plugins/security/server/features/security_features.ts +++ b/x-pack/plugins/security/server/features/security_features.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ElasticsearchFeatureConfig } from '../../../features/server'; +import type { ElasticsearchFeatureConfig } from '../../../features/server'; const userManagementFeature: ElasticsearchFeatureConfig = { id: 'users', diff --git a/x-pack/plugins/security/server/index.ts b/x-pack/plugins/security/server/index.ts index 66b916ac7f70f..7120f480bbc42 100644 --- a/x-pack/plugins/security/server/index.ts +++ b/x-pack/plugins/security/server/index.ts @@ -11,15 +11,12 @@ import type { PluginConfigDescriptor, PluginInitializer, PluginInitializerContext, -} from '../../../../src/core/server'; +} from 'src/core/server'; + import { ConfigSchema } from './config'; import { securityConfigDeprecationProvider } from './config_deprecations'; -import { - SecurityPlugin, - SecurityPluginSetup, - SecurityPluginStart, - PluginSetupDependencies, -} from './plugin'; +import type { PluginSetupDependencies, SecurityPluginSetup, SecurityPluginStart } from './plugin'; +import { SecurityPlugin } from './plugin'; // These exports are part of public Security plugin contract, any change in signature of exported // functions or removal of exports should be considered as a breaking change. diff --git a/x-pack/plugins/security/server/mocks.ts b/x-pack/plugins/security/server/mocks.ts index c8d6c56a874ff..07f60ceb890f1 100644 --- a/x-pack/plugins/security/server/mocks.ts +++ b/x-pack/plugins/security/server/mocks.ts @@ -6,10 +6,11 @@ */ import type { ApiResponse } from '@elastic/elasticsearch'; -import { authenticationServiceMock } from './authentication/authentication_service.mock'; -import { authorizationMock } from './authorization/index.mock'; + import { licenseMock } from '../common/licensing/index.mock'; import { auditServiceMock } from './audit/index.mock'; +import { authenticationServiceMock } from './authentication/authentication_service.mock'; +import { authorizationMock } from './authorization/index.mock'; function createSetupMock() { const mockAuthz = authorizationMock.create(); diff --git a/x-pack/plugins/security/server/plugin.test.ts b/x-pack/plugins/security/server/plugin.test.ts index d57951ecb5b1d..0fa6c553c2e80 100644 --- a/x-pack/plugins/security/server/plugin.test.ts +++ b/x-pack/plugins/security/server/plugin.test.ts @@ -6,14 +6,16 @@ */ import { of } from 'rxjs'; + import { ByteSizeValue } from '@kbn/config-schema'; -import { ConfigSchema } from './config'; -import { SecurityPlugin, PluginSetupDependencies, PluginStartDependencies } from './plugin'; +import { coreMock } from 'src/core/server/mocks'; -import { coreMock } from '../../../../src/core/server/mocks'; import { featuresPluginMock } from '../../features/server/mocks'; -import { taskManagerMock } from '../../task_manager/server/mocks'; import { licensingMock } from '../../licensing/server/mocks'; +import { taskManagerMock } from '../../task_manager/server/mocks'; +import { ConfigSchema } from './config'; +import type { PluginSetupDependencies, PluginStartDependencies } from './plugin'; +import { SecurityPlugin } from './plugin'; describe('Security Plugin', () => { let plugin: SecurityPlugin; diff --git a/x-pack/plugins/security/server/plugin.ts b/x-pack/plugins/security/server/plugin.ts index cccfa7de6d177..586707dd8c9aa 100644 --- a/x-pack/plugins/security/server/plugin.ts +++ b/x-pack/plugins/security/server/plugin.ts @@ -5,44 +5,53 @@ * 2.0. */ -import { combineLatest, Subscription } from 'rxjs'; +import type { Subscription } from 'rxjs'; +import { combineLatest } from 'rxjs'; import { map } from 'rxjs/operators'; -import { TypeOf } from '@kbn/config-schema'; -import { RecursiveReadonly } from '@kbn/utility-types'; -import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; -import { SecurityOssPluginSetup } from 'src/plugins/security_oss/server'; -import { + +import type { TypeOf } from '@kbn/config-schema'; +import type { RecursiveReadonly } from '@kbn/utility-types'; +import type { CoreSetup, CoreStart, KibanaRequest, Logger, - PluginInitializerContext, Plugin, -} from '../../../../src/core/server'; -import { SpacesPluginSetup, SpacesPluginStart } from '../../spaces/server'; -import { PluginSetupContract as FeaturesSetupContract } from '../../features/server'; -import { + PluginInitializerContext, +} from 'src/core/server'; +import type { SecurityOssPluginSetup } from 'src/plugins/security_oss/server'; +import type { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; + +import type { PluginSetupContract as FeaturesPluginSetup, PluginStartContract as FeaturesPluginStart, } from '../../features/server'; -import { LicensingPluginSetup, LicensingPluginStart } from '../../licensing/server'; -import { TaskManagerSetupContract, TaskManagerStartContract } from '../../task_manager/server'; - -import { AuthenticationService, AuthenticationServiceStart } from './authentication'; -import { AuthorizationService, AuthorizationServiceSetup } from './authorization'; -import { AnonymousAccessService, AnonymousAccessServiceStart } from './anonymous_access'; -import { ConfigSchema, ConfigType, createConfig } from './config'; +import type { LicensingPluginSetup, LicensingPluginStart } from '../../licensing/server'; +import type { SpacesPluginSetup, SpacesPluginStart } from '../../spaces/server'; +import type { TaskManagerSetupContract, TaskManagerStartContract } from '../../task_manager/server'; +import type { SecurityLicense } from '../common/licensing'; +import { SecurityLicenseService } from '../common/licensing'; +import type { AuthenticatedUser } from '../common/model'; +import type { AnonymousAccessServiceStart } from './anonymous_access'; +import { AnonymousAccessService } from './anonymous_access'; +import type { AuditServiceSetup } from './audit'; +import { AuditService, SecurityAuditLogger } from './audit'; +import type { AuthenticationServiceStart } from './authentication'; +import { AuthenticationService } from './authentication'; +import type { AuthorizationServiceSetup } from './authorization'; +import { AuthorizationService } from './authorization'; +import type { ConfigSchema, ConfigType } from './config'; +import { createConfig } from './config'; +import { ElasticsearchService } from './elasticsearch'; +import type { SecurityFeatureUsageServiceStart } from './feature_usage'; +import { SecurityFeatureUsageService } from './feature_usage'; +import { securityFeatures } from './features'; import { defineRoutes } from './routes'; -import { SecurityLicenseService, SecurityLicense } from '../common/licensing'; -import { AuthenticatedUser } from '../common/model'; import { setupSavedObjects } from './saved_objects'; -import { AuditService, SecurityAuditLogger, AuditServiceSetup } from './audit'; -import { SecurityFeatureUsageService, SecurityFeatureUsageServiceStart } from './feature_usage'; -import { securityFeatures } from './features'; -import { ElasticsearchService } from './elasticsearch'; -import { Session, SessionManagementService } from './session_management'; -import { registerSecurityUsageCollector } from './usage_collector'; +import type { Session } from './session_management'; +import { SessionManagementService } from './session_management'; import { setupSpacesClient } from './spaces'; +import { registerSecurityUsageCollector } from './usage_collector'; export type SpacesService = Pick< SpacesPluginSetup['spacesService'], @@ -50,7 +59,7 @@ export type SpacesService = Pick< >; export type FeaturesService = Pick< - FeaturesSetupContract, + FeaturesPluginSetup, 'getKibanaFeatures' | 'getElasticsearchFeatures' >; diff --git a/x-pack/plugins/security/server/routes/api_keys/enabled.test.ts b/x-pack/plugins/security/server/routes/api_keys/enabled.test.ts index cbd5e0ecc7f16..da097faf8c6b2 100644 --- a/x-pack/plugins/security/server/routes/api_keys/enabled.test.ts +++ b/x-pack/plugins/security/server/routes/api_keys/enabled.test.ts @@ -6,16 +6,17 @@ */ import Boom from '@hapi/boom'; -import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; -import { kibanaResponseFactory, RequestHandler } from '../../../../../../src/core/server'; -import { httpServerMock } from '../../../../../../src/core/server/mocks'; -import { routeDefinitionParamsMock } from '../index.mock'; +import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; +import type { RequestHandler } from 'src/core/server'; +import { kibanaResponseFactory } from 'src/core/server'; +import { httpServerMock } from 'src/core/server/mocks'; import type { AuthenticationServiceStart } from '../../authentication'; -import { defineEnabledApiKeysRoutes } from './enabled'; import { authenticationServiceMock } from '../../authentication/authentication_service.mock'; import type { SecurityRequestHandlerContext } from '../../types'; +import { routeDefinitionParamsMock } from '../index.mock'; +import { defineEnabledApiKeysRoutes } from './enabled'; describe('API keys enabled', () => { function getMockContext( diff --git a/x-pack/plugins/security/server/routes/api_keys/enabled.ts b/x-pack/plugins/security/server/routes/api_keys/enabled.ts index 4de4aaea696b7..e788f3e6ff950 100644 --- a/x-pack/plugins/security/server/routes/api_keys/enabled.ts +++ b/x-pack/plugins/security/server/routes/api_keys/enabled.ts @@ -5,9 +5,9 @@ * 2.0. */ +import type { RouteDefinitionParams } from '../'; import { wrapIntoCustomErrorResponse } from '../../errors'; import { createLicensedRouteHandler } from '../licensed_route_handler'; -import { RouteDefinitionParams } from '..'; export function defineEnabledApiKeysRoutes({ router, diff --git a/x-pack/plugins/security/server/routes/api_keys/get.test.ts b/x-pack/plugins/security/server/routes/api_keys/get.test.ts index ceef745f62904..e3a13eb6d1bda 100644 --- a/x-pack/plugins/security/server/routes/api_keys/get.test.ts +++ b/x-pack/plugins/security/server/routes/api_keys/get.test.ts @@ -5,13 +5,14 @@ * 2.0. */ -import { kibanaResponseFactory } from '../../../../../../src/core/server'; -import { LicenseCheck } from '../../../../licensing/server'; -import { defineGetApiKeysRoutes } from './get'; +import Boom from '@hapi/boom'; + +import { kibanaResponseFactory } from 'src/core/server'; +import { coreMock, httpServerMock } from 'src/core/server/mocks'; -import { httpServerMock, coreMock } from '../../../../../../src/core/server/mocks'; +import type { LicenseCheck } from '../../../../licensing/server'; import { routeDefinitionParamsMock } from '../index.mock'; -import Boom from '@hapi/boom'; +import { defineGetApiKeysRoutes } from './get'; interface TestOptions { isAdmin?: boolean; diff --git a/x-pack/plugins/security/server/routes/api_keys/get.ts b/x-pack/plugins/security/server/routes/api_keys/get.ts index aebafa4c44bc3..7862401e1b80c 100644 --- a/x-pack/plugins/security/server/routes/api_keys/get.ts +++ b/x-pack/plugins/security/server/routes/api_keys/get.ts @@ -6,10 +6,11 @@ */ import { schema } from '@kbn/config-schema'; -import { ApiKey } from '../../../common/model'; + +import type { RouteDefinitionParams } from '../'; +import type { ApiKey } from '../../../common/model'; import { wrapIntoCustomErrorResponse } from '../../errors'; import { createLicensedRouteHandler } from '../licensed_route_handler'; -import { RouteDefinitionParams } from '..'; export function defineGetApiKeysRoutes({ router }: RouteDefinitionParams) { router.get( diff --git a/x-pack/plugins/security/server/routes/api_keys/index.ts b/x-pack/plugins/security/server/routes/api_keys/index.ts index b74f912fe2187..e6a8711bdf19e 100644 --- a/x-pack/plugins/security/server/routes/api_keys/index.ts +++ b/x-pack/plugins/security/server/routes/api_keys/index.ts @@ -5,11 +5,11 @@ * 2.0. */ +import type { RouteDefinitionParams } from '../'; +import { defineEnabledApiKeysRoutes } from './enabled'; import { defineGetApiKeysRoutes } from './get'; -import { defineCheckPrivilegesRoutes } from './privileges'; import { defineInvalidateApiKeysRoutes } from './invalidate'; -import { defineEnabledApiKeysRoutes } from './enabled'; -import { RouteDefinitionParams } from '..'; +import { defineCheckPrivilegesRoutes } from './privileges'; export function defineApiKeysRoutes(params: RouteDefinitionParams) { defineEnabledApiKeysRoutes(params); diff --git a/x-pack/plugins/security/server/routes/api_keys/invalidate.test.ts b/x-pack/plugins/security/server/routes/api_keys/invalidate.test.ts index 0438a0d514390..7ec7eabf32c25 100644 --- a/x-pack/plugins/security/server/routes/api_keys/invalidate.test.ts +++ b/x-pack/plugins/security/server/routes/api_keys/invalidate.test.ts @@ -6,13 +6,14 @@ */ import Boom from '@hapi/boom'; -import { Type } from '@kbn/config-schema'; -import { kibanaResponseFactory } from '../../../../../../src/core/server'; -import { LicenseCheck } from '../../../../licensing/server'; -import { defineInvalidateApiKeysRoutes } from './invalidate'; -import { coreMock, httpServerMock } from '../../../../../../src/core/server/mocks'; +import type { Type } from '@kbn/config-schema'; +import { kibanaResponseFactory } from 'src/core/server'; +import { coreMock, httpServerMock } from 'src/core/server/mocks'; + +import type { LicenseCheck } from '../../../../licensing/server'; import { routeDefinitionParamsMock } from '../index.mock'; +import { defineInvalidateApiKeysRoutes } from './invalidate'; interface TestOptions { licenseCheckResult?: LicenseCheck; diff --git a/x-pack/plugins/security/server/routes/api_keys/invalidate.ts b/x-pack/plugins/security/server/routes/api_keys/invalidate.ts index 7fc4dbe6b5a5d..fe4884250e83d 100644 --- a/x-pack/plugins/security/server/routes/api_keys/invalidate.ts +++ b/x-pack/plugins/security/server/routes/api_keys/invalidate.ts @@ -6,10 +6,11 @@ */ import { schema } from '@kbn/config-schema'; -import { createLicensedRouteHandler } from '../licensed_route_handler'; -import { ApiKey } from '../../../common/model'; + +import type { RouteDefinitionParams } from '../'; +import type { ApiKey } from '../../../common/model'; import { wrapError, wrapIntoCustomErrorResponse } from '../../errors'; -import { RouteDefinitionParams } from '..'; +import { createLicensedRouteHandler } from '../licensed_route_handler'; interface ResponseType { itemsInvalidated: Array>; diff --git a/x-pack/plugins/security/server/routes/api_keys/privileges.test.ts b/x-pack/plugins/security/server/routes/api_keys/privileges.test.ts index a8a382d547d5a..019c61fd435be 100644 --- a/x-pack/plugins/security/server/routes/api_keys/privileges.test.ts +++ b/x-pack/plugins/security/server/routes/api_keys/privileges.test.ts @@ -6,13 +6,14 @@ */ import Boom from '@hapi/boom'; -import { LicenseCheck } from '../../../../licensing/server'; -import { kibanaResponseFactory } from '../../../../../../src/core/server'; -import { coreMock, httpServerMock } from '../../../../../../src/core/server/mocks'; +import { kibanaResponseFactory } from 'src/core/server'; +import { coreMock, httpServerMock } from 'src/core/server/mocks'; + +import type { LicenseCheck } from '../../../../licensing/server'; +import { authenticationServiceMock } from '../../authentication/authentication_service.mock'; import { routeDefinitionParamsMock } from '../index.mock'; import { defineCheckPrivilegesRoutes } from './privileges'; -import { authenticationServiceMock } from '../../authentication/authentication_service.mock'; interface TestOptions { licenseCheckResult?: LicenseCheck; diff --git a/x-pack/plugins/security/server/routes/api_keys/privileges.ts b/x-pack/plugins/security/server/routes/api_keys/privileges.ts index c1a1c0c24a5e8..18de00ed79956 100644 --- a/x-pack/plugins/security/server/routes/api_keys/privileges.ts +++ b/x-pack/plugins/security/server/routes/api_keys/privileges.ts @@ -5,9 +5,9 @@ * 2.0. */ +import type { RouteDefinitionParams } from '../'; import { wrapIntoCustomErrorResponse } from '../../errors'; import { createLicensedRouteHandler } from '../licensed_route_handler'; -import { RouteDefinitionParams } from '..'; export function defineCheckPrivilegesRoutes({ router, diff --git a/x-pack/plugins/security/server/routes/authentication/common.test.ts b/x-pack/plugins/security/server/routes/authentication/common.test.ts index 654e4fc18f195..6b3ce15669c27 100644 --- a/x-pack/plugins/security/server/routes/authentication/common.test.ts +++ b/x-pack/plugins/security/server/routes/authentication/common.test.ts @@ -7,26 +7,23 @@ import { Type } from '@kbn/config-schema'; import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; -import { - kibanaResponseFactory, - RequestHandler, - RouteConfig, -} from '../../../../../../src/core/server'; +import type { RequestHandler, RouteConfig } from 'src/core/server'; +import { kibanaResponseFactory } from 'src/core/server'; +import { httpServerMock } from 'src/core/server/mocks'; + import type { SecurityLicense, SecurityLicenseFeatures } from '../../../common/licensing'; +import { mockAuthenticatedUser } from '../../../common/model/authenticated_user.mock'; +import type { AuthenticationServiceStart } from '../../authentication'; import { AuthenticationResult, - AuthenticationServiceStart, DeauthenticationResult, OIDCLogin, SAMLLogin, } from '../../authentication'; -import { defineCommonRoutes } from './common'; +import { authenticationServiceMock } from '../../authentication/authentication_service.mock'; import type { SecurityRequestHandlerContext, SecurityRouter } from '../../types'; - -import { httpServerMock } from '../../../../../../src/core/server/mocks'; -import { mockAuthenticatedUser } from '../../../common/model/authenticated_user.mock'; import { routeDefinitionParamsMock } from '../index.mock'; -import { authenticationServiceMock } from '../../authentication/authentication_service.mock'; +import { defineCommonRoutes } from './common'; describe('Common authentication routes', () => { let router: jest.Mocked; diff --git a/x-pack/plugins/security/server/routes/authentication/common.ts b/x-pack/plugins/security/server/routes/authentication/common.ts index f1d9aab74548a..28c344785da4b 100644 --- a/x-pack/plugins/security/server/routes/authentication/common.ts +++ b/x-pack/plugins/security/server/routes/authentication/common.ts @@ -5,20 +5,22 @@ * 2.0. */ -import { schema, TypeOf } from '@kbn/config-schema'; +import type { TypeOf } from '@kbn/config-schema'; +import { schema } from '@kbn/config-schema'; + +import type { RouteDefinitionParams } from '../'; import { parseNext } from '../../../common/parse_next'; import { - canRedirectRequest, - OIDCLogin, - SAMLLogin, BasicAuthenticationProvider, + canRedirectRequest, OIDCAuthenticationProvider, + OIDCLogin, SAMLAuthenticationProvider, + SAMLLogin, TokenAuthenticationProvider, } from '../../authentication'; import { wrapIntoCustomErrorResponse } from '../../errors'; import { createLicensedRouteHandler } from '../licensed_route_handler'; -import { RouteDefinitionParams } from '..'; /** * Defines routes that are common to various authentication mechanisms. diff --git a/x-pack/plugins/security/server/routes/authentication/index.test.ts b/x-pack/plugins/security/server/routes/authentication/index.test.ts index aba68de145a8c..d1648797d45bf 100644 --- a/x-pack/plugins/security/server/routes/authentication/index.test.ts +++ b/x-pack/plugins/security/server/routes/authentication/index.test.ts @@ -5,9 +5,8 @@ * 2.0. */ -import { defineAuthenticationRoutes } from '.'; - import { routeDefinitionParamsMock } from '../index.mock'; +import { defineAuthenticationRoutes } from './'; describe('Authentication routes', () => { it('does not register any SAML related routes if SAML auth provider is not enabled', () => { diff --git a/x-pack/plugins/security/server/routes/authentication/index.ts b/x-pack/plugins/security/server/routes/authentication/index.ts index 1a924063c7713..3b879eadf240b 100644 --- a/x-pack/plugins/security/server/routes/authentication/index.ts +++ b/x-pack/plugins/security/server/routes/authentication/index.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { defineSAMLRoutes } from './saml'; +import type { RouteDefinitionParams } from '../'; import { defineCommonRoutes } from './common'; import { defineOIDCRoutes } from './oidc'; -import { RouteDefinitionParams } from '..'; +import { defineSAMLRoutes } from './saml'; export function defineAuthenticationRoutes(params: RouteDefinitionParams) { defineCommonRoutes(params); diff --git a/x-pack/plugins/security/server/routes/authentication/oidc.ts b/x-pack/plugins/security/server/routes/authentication/oidc.ts index b0defe7662622..854b6721278ff 100644 --- a/x-pack/plugins/security/server/routes/authentication/oidc.ts +++ b/x-pack/plugins/security/server/routes/authentication/oidc.ts @@ -7,15 +7,14 @@ import { schema } from '@kbn/config-schema'; import { i18n } from '@kbn/i18n'; -import { KibanaRequest, KibanaResponseFactory } from '../../../../../../src/core/server'; +import type { KibanaRequest, KibanaResponseFactory } from 'src/core/server'; + +import type { RouteDefinitionParams } from '../'; import { OIDCLogin } from '../../authentication'; -import { createLicensedRouteHandler } from '../licensed_route_handler'; +import type { ProviderLoginAttempt } from '../../authentication/providers/oidc'; +import { OIDCAuthenticationProvider } from '../../authentication/providers/oidc'; import { wrapIntoCustomErrorResponse } from '../../errors'; -import { - OIDCAuthenticationProvider, - ProviderLoginAttempt, -} from '../../authentication/providers/oidc'; -import { RouteDefinitionParams } from '..'; +import { createLicensedRouteHandler } from '../licensed_route_handler'; /** * Defines routes required for SAML authentication. diff --git a/x-pack/plugins/security/server/routes/authentication/saml.test.ts b/x-pack/plugins/security/server/routes/authentication/saml.test.ts index 73cba46f46ea7..35fdcff295c1e 100644 --- a/x-pack/plugins/security/server/routes/authentication/saml.test.ts +++ b/x-pack/plugins/security/server/routes/authentication/saml.test.ts @@ -7,15 +7,16 @@ import { Type } from '@kbn/config-schema'; import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; -import { AuthenticationResult, AuthenticationServiceStart, SAMLLogin } from '../../authentication'; -import { defineSAMLRoutes } from './saml'; -import type { RequestHandler, RouteConfig } from '../../../../../../src/core/server'; -import type { SecurityRouter } from '../../types'; +import type { RequestHandler, RouteConfig } from 'src/core/server'; +import { httpServerMock } from 'src/core/server/mocks'; -import { httpServerMock } from '../../../../../../src/core/server/mocks'; import { mockAuthenticatedUser } from '../../../common/model/authenticated_user.mock'; -import { routeDefinitionParamsMock } from '../index.mock'; +import type { AuthenticationServiceStart } from '../../authentication'; +import { AuthenticationResult, SAMLLogin } from '../../authentication'; import { authenticationServiceMock } from '../../authentication/authentication_service.mock'; +import type { SecurityRouter } from '../../types'; +import { routeDefinitionParamsMock } from '../index.mock'; +import { defineSAMLRoutes } from './saml'; describe('SAML authentication routes', () => { let router: jest.Mocked; diff --git a/x-pack/plugins/security/server/routes/authentication/saml.ts b/x-pack/plugins/security/server/routes/authentication/saml.ts index 257b95ec707b4..5dac46354025a 100644 --- a/x-pack/plugins/security/server/routes/authentication/saml.ts +++ b/x-pack/plugins/security/server/routes/authentication/saml.ts @@ -6,9 +6,10 @@ */ import { schema } from '@kbn/config-schema'; + +import type { RouteDefinitionParams } from '../'; import { SAMLLogin } from '../../authentication'; import { SAMLAuthenticationProvider } from '../../authentication/providers'; -import { RouteDefinitionParams } from '..'; /** * Defines routes required for SAML authentication. diff --git a/x-pack/plugins/security/server/routes/authorization/index.ts b/x-pack/plugins/security/server/routes/authorization/index.ts index be79254d658c5..1fecd45f795a3 100644 --- a/x-pack/plugins/security/server/routes/authorization/index.ts +++ b/x-pack/plugins/security/server/routes/authorization/index.ts @@ -5,11 +5,11 @@ * 2.0. */ +import type { RouteDefinitionParams } from '../'; import { definePrivilegesRoutes } from './privileges'; -import { defineRolesRoutes } from './roles'; import { resetSessionPageRoutes } from './reset_session_page'; +import { defineRolesRoutes } from './roles'; import { defineShareSavedObjectPermissionRoutes } from './spaces'; -import { RouteDefinitionParams } from '..'; export function defineAuthorizationRoutes(params: RouteDefinitionParams) { defineRolesRoutes(params); diff --git a/x-pack/plugins/security/server/routes/authorization/privileges/get.test.ts b/x-pack/plugins/security/server/routes/authorization/privileges/get.test.ts index bc4d12134ac67..26afb602afc90 100644 --- a/x-pack/plugins/security/server/routes/authorization/privileges/get.test.ts +++ b/x-pack/plugins/security/server/routes/authorization/privileges/get.test.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { kibanaResponseFactory } from '../../../../../../../src/core/server'; -import { LicenseCheck } from '../../../../../licensing/server'; -import { RawKibanaPrivileges } from '../../../../common/model'; -import { defineGetPrivilegesRoutes } from './get'; -import type { SecurityRequestHandlerContext } from '../../../types'; +import { kibanaResponseFactory } from 'src/core/server'; +import { httpServerMock } from 'src/core/server/mocks'; -import { httpServerMock } from '../../../../../../../src/core/server/mocks'; +import type { LicenseCheck } from '../../../../../licensing/server'; +import type { RawKibanaPrivileges } from '../../../../common/model'; +import type { SecurityRequestHandlerContext } from '../../../types'; import { routeDefinitionParamsMock } from '../../index.mock'; +import { defineGetPrivilegesRoutes } from './get'; const createRawKibanaPrivileges: () => RawKibanaPrivileges = () => { return { diff --git a/x-pack/plugins/security/server/routes/authorization/privileges/get.ts b/x-pack/plugins/security/server/routes/authorization/privileges/get.ts index d7935989e6050..8724323fdf510 100644 --- a/x-pack/plugins/security/server/routes/authorization/privileges/get.ts +++ b/x-pack/plugins/security/server/routes/authorization/privileges/get.ts @@ -6,7 +6,8 @@ */ import { schema } from '@kbn/config-schema'; -import { RouteDefinitionParams } from '../..'; + +import type { RouteDefinitionParams } from '../..'; import { createLicensedRouteHandler } from '../../licensed_route_handler'; export function defineGetPrivilegesRoutes({ router, authz }: RouteDefinitionParams) { diff --git a/x-pack/plugins/security/server/routes/authorization/privileges/get_builtin.ts b/x-pack/plugins/security/server/routes/authorization/privileges/get_builtin.ts index 3720c4882669a..e2539695d54ee 100644 --- a/x-pack/plugins/security/server/routes/authorization/privileges/get_builtin.ts +++ b/x-pack/plugins/security/server/routes/authorization/privileges/get_builtin.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { BuiltinESPrivileges } from '../../../../common/model'; -import { RouteDefinitionParams } from '../..'; +import type { RouteDefinitionParams } from '../..'; +import type { BuiltinESPrivileges } from '../../../../common/model'; export function defineGetBuiltinPrivilegesRoutes({ router }: RouteDefinitionParams) { router.get( diff --git a/x-pack/plugins/security/server/routes/authorization/privileges/index.ts b/x-pack/plugins/security/server/routes/authorization/privileges/index.ts index ee24dcbbef835..572a7a2584dcc 100644 --- a/x-pack/plugins/security/server/routes/authorization/privileges/index.ts +++ b/x-pack/plugins/security/server/routes/authorization/privileges/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { RouteDefinitionParams } from '../..'; +import type { RouteDefinitionParams } from '../..'; import { defineGetPrivilegesRoutes } from './get'; import { defineGetBuiltinPrivilegesRoutes } from './get_builtin'; diff --git a/x-pack/plugins/security/server/routes/authorization/reset_session_page.ts b/x-pack/plugins/security/server/routes/authorization/reset_session_page.ts index 06d26467aad0c..05fe1a7d01175 100644 --- a/x-pack/plugins/security/server/routes/authorization/reset_session_page.ts +++ b/x-pack/plugins/security/server/routes/authorization/reset_session_page.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { RouteDefinitionParams } from '..'; +import type { RouteDefinitionParams } from '../'; export function resetSessionPageRoutes({ httpResources }: RouteDefinitionParams) { httpResources.register( diff --git a/x-pack/plugins/security/server/routes/authorization/roles/delete.test.ts b/x-pack/plugins/security/server/routes/authorization/roles/delete.test.ts index 44022691226b9..e2ecd92b9a942 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/delete.test.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/delete.test.ts @@ -6,12 +6,13 @@ */ import Boom from '@hapi/boom'; -import { kibanaResponseFactory } from '../../../../../../../src/core/server'; -import { LicenseCheck } from '../../../../../licensing/server'; -import { defineDeleteRolesRoutes } from './delete'; -import { coreMock, httpServerMock } from '../../../../../../../src/core/server/mocks'; +import { kibanaResponseFactory } from 'src/core/server'; +import { coreMock, httpServerMock } from 'src/core/server/mocks'; + +import type { LicenseCheck } from '../../../../../licensing/server'; import { routeDefinitionParamsMock } from '../../index.mock'; +import { defineDeleteRolesRoutes } from './delete'; interface TestOptions { licenseCheckResult?: LicenseCheck; 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 85a42aa3c6415..aa2fc0e417e4d 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/delete.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/delete.ts @@ -6,9 +6,10 @@ */ import { schema } from '@kbn/config-schema'; -import { RouteDefinitionParams } from '../../index'; -import { createLicensedRouteHandler } from '../../licensed_route_handler'; + import { wrapIntoCustomErrorResponse } from '../../../errors'; +import type { RouteDefinitionParams } from '../../index'; +import { createLicensedRouteHandler } from '../../licensed_route_handler'; export function defineDeleteRolesRoutes({ router }: RouteDefinitionParams) { router.delete( diff --git a/x-pack/plugins/security/server/routes/authorization/roles/get.test.ts b/x-pack/plugins/security/server/routes/authorization/roles/get.test.ts index 836d6c1ab4f45..24366a250cf11 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/get.test.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/get.test.ts @@ -6,12 +6,13 @@ */ import Boom from '@hapi/boom'; -import { kibanaResponseFactory } from '../../../../../../../src/core/server'; -import { LicenseCheck } from '../../../../../licensing/server'; -import { defineGetRolesRoutes } from './get'; -import { coreMock, httpServerMock } from '../../../../../../../src/core/server/mocks'; +import { kibanaResponseFactory } from 'src/core/server'; +import { coreMock, httpServerMock } from 'src/core/server/mocks'; + +import type { LicenseCheck } from '../../../../../licensing/server'; import { routeDefinitionParamsMock } from '../../index.mock'; +import { defineGetRolesRoutes } from './get'; const application = 'kibana-.kibana'; const reservedPrivilegesApplicationWildcard = 'kibana-*'; 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 354b286946a6e..3bfc5e5d4dda3 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/get.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/get.ts @@ -6,10 +6,12 @@ */ import { schema } from '@kbn/config-schema'; -import { RouteDefinitionParams } from '../..'; -import { createLicensedRouteHandler } from '../../licensed_route_handler'; + +import type { RouteDefinitionParams } from '../..'; import { wrapIntoCustomErrorResponse } from '../../../errors'; -import { ElasticsearchRole, transformElasticsearchRoleToRole } from './model'; +import { createLicensedRouteHandler } from '../../licensed_route_handler'; +import type { ElasticsearchRole } from './model'; +import { transformElasticsearchRoleToRole } from './model'; export function defineGetRolesRoutes({ router, authz }: RouteDefinitionParams) { router.get( diff --git a/x-pack/plugins/security/server/routes/authorization/roles/get_all.test.ts b/x-pack/plugins/security/server/routes/authorization/roles/get_all.test.ts index cc87d922fddac..d490153b30394 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/get_all.test.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/get_all.test.ts @@ -6,12 +6,13 @@ */ import Boom from '@hapi/boom'; -import { kibanaResponseFactory } from '../../../../../../../src/core/server'; -import { LicenseCheck } from '../../../../../licensing/server'; -import { defineGetAllRolesRoutes } from './get_all'; -import { coreMock, httpServerMock } from '../../../../../../../src/core/server/mocks'; +import { kibanaResponseFactory } from 'src/core/server'; +import { coreMock, httpServerMock } from 'src/core/server/mocks'; + +import type { LicenseCheck } from '../../../../../licensing/server'; import { routeDefinitionParamsMock } from '../../index.mock'; +import { defineGetAllRolesRoutes } from './get_all'; const application = 'kibana-.kibana'; const reservedPrivilegesApplicationWildcard = 'kibana-*'; 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 318e8e9fa2e86..2994afd40f880 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 @@ -5,10 +5,11 @@ * 2.0. */ -import { RouteDefinitionParams } from '../..'; -import { createLicensedRouteHandler } from '../../licensed_route_handler'; +import type { RouteDefinitionParams } from '../..'; import { wrapIntoCustomErrorResponse } from '../../../errors'; -import { ElasticsearchRole, transformElasticsearchRoleToRole } from './model'; +import { createLicensedRouteHandler } from '../../licensed_route_handler'; +import type { ElasticsearchRole } from './model'; +import { transformElasticsearchRoleToRole } from './model'; export function defineGetAllRolesRoutes({ router, authz }: RouteDefinitionParams) { router.get( diff --git a/x-pack/plugins/security/server/routes/authorization/roles/index.ts b/x-pack/plugins/security/server/routes/authorization/roles/index.ts index e0f8675a5530a..e3ea1a3889b1f 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/index.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/index.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { RouteDefinitionParams } from '../..'; +import type { RouteDefinitionParams } from '../..'; +import { defineDeleteRolesRoutes } from './delete'; import { defineGetRolesRoutes } from './get'; import { defineGetAllRolesRoutes } from './get_all'; -import { defineDeleteRolesRoutes } from './delete'; import { definePutRolesRoutes } from './put'; export function defineRolesRoutes(params: RouteDefinitionParams) { diff --git a/x-pack/plugins/security/server/routes/authorization/roles/model/elasticsearch_role.ts b/x-pack/plugins/security/server/routes/authorization/roles/model/elasticsearch_role.ts index b5ec2bbbe426f..f033b66805067 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/model/elasticsearch_role.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/model/elasticsearch_role.ts @@ -5,11 +5,11 @@ * 2.0. */ -import { Role, RoleKibanaPrivilege } from '../../../../../common/model'; import { GLOBAL_RESOURCE, RESERVED_PRIVILEGES_APPLICATION_WILDCARD, } from '../../../../../common/constants'; +import type { Role, RoleKibanaPrivilege } from '../../../../../common/model'; import { PrivilegeSerializer } from '../../../../authorization/privilege_serializer'; import { ResourceSerializer } from '../../../../authorization/resource_serializer'; 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 6003c8028891b..8a560d7b6dd87 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 @@ -6,11 +6,14 @@ */ import _ from 'lodash'; -import { schema, TypeOf } from '@kbn/config-schema'; + +import type { TypeOf } from '@kbn/config-schema'; +import { schema } from '@kbn/config-schema'; + import { GLOBAL_RESOURCE } from '../../../../../common/constants'; import { PrivilegeSerializer } from '../../../../authorization/privilege_serializer'; import { ResourceSerializer } from '../../../../authorization/resource_serializer'; -import { ElasticsearchRole } from './elasticsearch_role'; +import type { ElasticsearchRole } from './elasticsearch_role'; /** * Elasticsearch specific portion of the role definition. diff --git a/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts b/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts index 0ca4b7e33a975..ae4647ca4f515 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/put.test.ts @@ -5,16 +5,16 @@ * 2.0. */ -import { Type } from '@kbn/config-schema'; -import { kibanaResponseFactory } from '../../../../../../../src/core/server'; -import { LicenseCheck } from '../../../../../licensing/server'; -import { GLOBAL_RESOURCE } from '../../../../common/constants'; -import { definePutRolesRoutes } from './put'; +import type { Type } from '@kbn/config-schema'; +import { kibanaResponseFactory } from 'src/core/server'; +import { coreMock, httpServerMock } from 'src/core/server/mocks'; -import { coreMock, httpServerMock } from '../../../../../../../src/core/server/mocks'; -import { routeDefinitionParamsMock } from '../../index.mock'; import { KibanaFeature } from '../../../../../features/server'; +import type { LicenseCheck } from '../../../../../licensing/server'; +import { GLOBAL_RESOURCE } from '../../../../common/constants'; import { securityFeatureUsageServiceMock } from '../../../feature_usage/index.mock'; +import { routeDefinitionParamsMock } from '../../index.mock'; +import { definePutRolesRoutes } from './put'; const application = 'kibana-.kibana'; const privilegeMap = { 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 f45aca8e0af19..aefcc0c72c6db 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/put.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/put.ts @@ -5,16 +5,15 @@ * 2.0. */ -import { schema, TypeOf } from '@kbn/config-schema'; -import { KibanaFeature } from '../../../../../features/common'; -import { RouteDefinitionParams } from '../../index'; -import { createLicensedRouteHandler } from '../../licensed_route_handler'; +import type { TypeOf } from '@kbn/config-schema'; +import { schema } from '@kbn/config-schema'; + +import type { KibanaFeature } from '../../../../../features/common'; import { wrapIntoCustomErrorResponse } from '../../../errors'; -import { - ElasticsearchRole, - getPutPayloadSchema, - transformPutPayloadToElasticsearchRole, -} from './model'; +import type { RouteDefinitionParams } from '../../index'; +import { createLicensedRouteHandler } from '../../licensed_route_handler'; +import type { ElasticsearchRole } from './model'; +import { getPutPayloadSchema, transformPutPayloadToElasticsearchRole } from './model'; const roleGrantsSubFeaturePrivileges = ( features: KibanaFeature[], diff --git a/x-pack/plugins/security/server/routes/authorization/spaces/share_saved_object_permissions.test.ts b/x-pack/plugins/security/server/routes/authorization/spaces/share_saved_object_permissions.test.ts index 69cb5e7f17af6..03736c3bfb4bc 100644 --- a/x-pack/plugins/security/server/routes/authorization/spaces/share_saved_object_permissions.test.ts +++ b/x-pack/plugins/security/server/routes/authorization/spaces/share_saved_object_permissions.test.ts @@ -5,19 +5,16 @@ * 2.0. */ -import { - kibanaResponseFactory, - RequestHandler, - RouteConfig, -} from '../../../../../../../src/core/server'; -import { defineShareSavedObjectPermissionRoutes } from './share_saved_object_permissions'; +import type { DeeplyMockedKeys } from '@kbn/utility-types/target/jest'; +import type { RequestHandler, RouteConfig } from 'src/core/server'; +import { kibanaResponseFactory } from 'src/core/server'; +import { httpServerMock } from 'src/core/server/mocks'; -import { httpServerMock } from '../../../../../../../src/core/server/mocks'; -import { routeDefinitionParamsMock } from '../../index.mock'; -import { RouteDefinitionParams } from '../..'; -import { DeeplyMockedKeys } from '@kbn/utility-types/target/jest'; -import { CheckPrivileges } from '../../../authorization/types'; +import type { RouteDefinitionParams } from '../..'; +import type { CheckPrivileges } from '../../../authorization/types'; import type { SecurityRequestHandlerContext, SecurityRouter } from '../../../types'; +import { routeDefinitionParamsMock } from '../../index.mock'; +import { defineShareSavedObjectPermissionRoutes } from './share_saved_object_permissions'; describe('Share Saved Object Permissions', () => { let router: jest.Mocked; diff --git a/x-pack/plugins/security/server/routes/authorization/spaces/share_saved_object_permissions.ts b/x-pack/plugins/security/server/routes/authorization/spaces/share_saved_object_permissions.ts index 849ab66d03bb0..07e4ac087f591 100644 --- a/x-pack/plugins/security/server/routes/authorization/spaces/share_saved_object_permissions.ts +++ b/x-pack/plugins/security/server/routes/authorization/spaces/share_saved_object_permissions.ts @@ -6,9 +6,10 @@ */ import { schema } from '@kbn/config-schema'; -import { RouteDefinitionParams } from '../../index'; -import { createLicensedRouteHandler } from '../../licensed_route_handler'; + import { wrapIntoCustomErrorResponse } from '../../../errors'; +import type { RouteDefinitionParams } from '../../index'; +import { createLicensedRouteHandler } from '../../licensed_route_handler'; export function defineShareSavedObjectPermissionRoutes({ router, authz }: RouteDefinitionParams) { router.get( diff --git a/x-pack/plugins/security/server/routes/index.mock.ts b/x-pack/plugins/security/server/routes/index.mock.ts index 9077f35b9efae..956de8c4036d3 100644 --- a/x-pack/plugins/security/server/routes/index.mock.ts +++ b/x-pack/plugins/security/server/routes/index.mock.ts @@ -6,17 +6,14 @@ */ import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; -import { - httpServiceMock, - loggingSystemMock, - httpResourcesMock, -} from '../../../../../src/core/server/mocks'; -import { authorizationMock } from '../authorization/index.mock'; -import { ConfigSchema, createConfig } from '../config'; +import { httpResourcesMock, httpServiceMock, loggingSystemMock } from 'src/core/server/mocks'; + import { licenseMock } from '../../common/licensing/index.mock'; import { authenticationServiceMock } from '../authentication/authentication_service.mock'; +import { authorizationMock } from '../authorization/index.mock'; +import { ConfigSchema, createConfig } from '../config'; import { sessionMock } from '../session_management/session.mock'; -import type { RouteDefinitionParams } from '.'; +import type { RouteDefinitionParams } from './'; export const routeDefinitionParamsMock = { create: (config: Record = {}) => diff --git a/x-pack/plugins/security/server/routes/index.ts b/x-pack/plugins/security/server/routes/index.ts index ba59d0f39692b..cdb3a2fa289fd 100644 --- a/x-pack/plugins/security/server/routes/index.ts +++ b/x-pack/plugins/security/server/routes/index.ts @@ -6,8 +6,9 @@ */ import type { PublicMethodsOf } from '@kbn/utility-types'; +import type { HttpResources, IBasePath, Logger } from 'src/core/server'; + import type { KibanaFeature } from '../../../features/server'; -import type { HttpResources, IBasePath, Logger } from '../../../../../src/core/server'; import type { SecurityLicense } from '../../common/licensing'; import type { AuthenticationServiceStart } from '../authentication'; import type { AuthorizationServiceSetup } from '../authorization'; @@ -15,14 +16,13 @@ import type { ConfigType } from '../config'; import type { SecurityFeatureUsageServiceStart } from '../feature_usage'; import type { Session } from '../session_management'; import type { SecurityRouter } from '../types'; - +import { defineApiKeysRoutes } from './api_keys'; import { defineAuthenticationRoutes } from './authentication'; import { defineAuthorizationRoutes } from './authorization'; -import { defineApiKeysRoutes } from './api_keys'; import { defineIndicesRoutes } from './indices'; -import { defineUsersRoutes } from './users'; import { defineRoleMappingRoutes } from './role_mapping'; import { defineSessionManagementRoutes } from './session_management'; +import { defineUsersRoutes } from './users'; import { defineViewRoutes } from './views'; /** diff --git a/x-pack/plugins/security/server/routes/indices/get_fields.test.ts b/x-pack/plugins/security/server/routes/indices/get_fields.test.ts index 33f2059dd0b35..20f9949f615cb 100644 --- a/x-pack/plugins/security/server/routes/indices/get_fields.test.ts +++ b/x-pack/plugins/security/server/routes/indices/get_fields.test.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { httpServerMock, coreMock } from '../../../../../../src/core/server/mocks'; -import { kibanaResponseFactory } from '../../../../../../src/core/server'; +import { kibanaResponseFactory } from 'src/core/server'; +import { coreMock, httpServerMock } from 'src/core/server/mocks'; import { routeDefinitionParamsMock } from '../index.mock'; import { defineGetFieldsRoutes } from './get_fields'; diff --git a/x-pack/plugins/security/server/routes/indices/get_fields.ts b/x-pack/plugins/security/server/routes/indices/get_fields.ts index 4df62df385db1..3ed7493ea1f0e 100644 --- a/x-pack/plugins/security/server/routes/indices/get_fields.ts +++ b/x-pack/plugins/security/server/routes/indices/get_fields.ts @@ -6,8 +6,9 @@ */ import { schema } from '@kbn/config-schema'; -import { RouteDefinitionParams } from '../index'; + import { wrapIntoCustomErrorResponse } from '../../errors'; +import type { RouteDefinitionParams } from '../index'; interface FieldMappingResponse { [indexName: string]: { diff --git a/x-pack/plugins/security/server/routes/indices/index.ts b/x-pack/plugins/security/server/routes/indices/index.ts index c26197c6045f1..bfc1d341b9f2f 100644 --- a/x-pack/plugins/security/server/routes/indices/index.ts +++ b/x-pack/plugins/security/server/routes/indices/index.ts @@ -5,8 +5,8 @@ * 2.0. */ +import type { RouteDefinitionParams } from '../'; import { defineGetFieldsRoutes } from './get_fields'; -import { RouteDefinitionParams } from '..'; export function defineIndicesRoutes(params: RouteDefinitionParams) { defineGetFieldsRoutes(params); diff --git a/x-pack/plugins/security/server/routes/licensed_route_handler.ts b/x-pack/plugins/security/server/routes/licensed_route_handler.ts index b03ee8ca8ae62..b4e6871c7a963 100644 --- a/x-pack/plugins/security/server/routes/licensed_route_handler.ts +++ b/x-pack/plugins/security/server/routes/licensed_route_handler.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { KibanaResponseFactory, RequestHandler, RouteMethod } from 'kibana/server'; +import type { KibanaResponseFactory, RequestHandler, RouteMethod } from 'src/core/server'; + import type { SecurityRequestHandlerContext } from '../types'; export const createLicensedRouteHandler = < diff --git a/x-pack/plugins/security/server/routes/role_mapping/delete.test.ts b/x-pack/plugins/security/server/routes/role_mapping/delete.test.ts index c780dc6e5b4fc..64b1ae8af13c6 100644 --- a/x-pack/plugins/security/server/routes/role_mapping/delete.test.ts +++ b/x-pack/plugins/security/server/routes/role_mapping/delete.test.ts @@ -5,9 +5,10 @@ * 2.0. */ -import { routeDefinitionParamsMock } from '../index.mock'; +import { kibanaResponseFactory } from 'src/core/server'; import { coreMock, httpServerMock } from 'src/core/server/mocks'; -import { kibanaResponseFactory } from '../../../../../../src/core/server'; + +import { routeDefinitionParamsMock } from '../index.mock'; import { defineRoleMappingDeleteRoutes } from './delete'; describe('DELETE role mappings', () => { diff --git a/x-pack/plugins/security/server/routes/role_mapping/delete.ts b/x-pack/plugins/security/server/routes/role_mapping/delete.ts index f106a065b225f..c7266353eb235 100644 --- a/x-pack/plugins/security/server/routes/role_mapping/delete.ts +++ b/x-pack/plugins/security/server/routes/role_mapping/delete.ts @@ -6,9 +6,10 @@ */ import { schema } from '@kbn/config-schema'; -import { createLicensedRouteHandler } from '../licensed_route_handler'; + +import type { RouteDefinitionParams } from '../'; import { wrapError } from '../../errors'; -import { RouteDefinitionParams } from '..'; +import { createLicensedRouteHandler } from '../licensed_route_handler'; export function defineRoleMappingDeleteRoutes({ router }: RouteDefinitionParams) { router.delete( diff --git a/x-pack/plugins/security/server/routes/role_mapping/feature_check.test.ts b/x-pack/plugins/security/server/routes/role_mapping/feature_check.test.ts index 5ac386e5e75d6..a015fcd293e35 100644 --- a/x-pack/plugins/security/server/routes/role_mapping/feature_check.test.ts +++ b/x-pack/plugins/security/server/routes/role_mapping/feature_check.test.ts @@ -5,10 +5,11 @@ * 2.0. */ -import { routeDefinitionParamsMock } from '../index.mock'; +import { kibanaResponseFactory } from 'src/core/server'; import { coreMock, httpServerMock } from 'src/core/server/mocks'; -import { kibanaResponseFactory } from '../../../../../../src/core/server'; -import { LicenseCheck } from '../../../../licensing/server'; + +import type { LicenseCheck } from '../../../../licensing/server'; +import { routeDefinitionParamsMock } from '../index.mock'; import { defineRoleMappingFeatureCheckRoute } from './feature_check'; interface TestOptions { diff --git a/x-pack/plugins/security/server/routes/role_mapping/feature_check.ts b/x-pack/plugins/security/server/routes/role_mapping/feature_check.ts index 562e5f891ec37..95b5d56be9937 100644 --- a/x-pack/plugins/security/server/routes/role_mapping/feature_check.ts +++ b/x-pack/plugins/security/server/routes/role_mapping/feature_check.ts @@ -5,9 +5,10 @@ * 2.0. */ -import { ElasticsearchClient, Logger } from 'src/core/server'; +import type { ElasticsearchClient, Logger } from 'src/core/server'; + +import type { RouteDefinitionParams } from '../'; import { createLicensedRouteHandler } from '../licensed_route_handler'; -import { RouteDefinitionParams } from '..'; interface NodeSettingsResponse { nodes: { diff --git a/x-pack/plugins/security/server/routes/role_mapping/get.test.ts b/x-pack/plugins/security/server/routes/role_mapping/get.test.ts index dfd50be2d1356..b9511eac70af7 100644 --- a/x-pack/plugins/security/server/routes/role_mapping/get.test.ts +++ b/x-pack/plugins/security/server/routes/role_mapping/get.test.ts @@ -6,10 +6,12 @@ */ import Boom from '@hapi/boom'; -import { routeDefinitionParamsMock } from '../index.mock'; + +import { kibanaResponseFactory } from 'src/core/server'; import { coreMock, httpServerMock } from 'src/core/server/mocks'; + +import { routeDefinitionParamsMock } from '../index.mock'; import { defineRoleMappingGetRoutes } from './get'; -import { kibanaResponseFactory } from '../../../../../../src/core/server'; const mockRoleMappingResponse = { mapping1: { diff --git a/x-pack/plugins/security/server/routes/role_mapping/get.ts b/x-pack/plugins/security/server/routes/role_mapping/get.ts index ff4567d5d67a5..d060825a989d5 100644 --- a/x-pack/plugins/security/server/routes/role_mapping/get.ts +++ b/x-pack/plugins/security/server/routes/role_mapping/get.ts @@ -6,10 +6,11 @@ */ import { schema } from '@kbn/config-schema'; -import { RoleMapping } from '../../../common/model'; -import { createLicensedRouteHandler } from '../licensed_route_handler'; + +import type { RouteDefinitionParams } from '../'; +import type { RoleMapping } from '../../../common/model'; import { wrapError } from '../../errors'; -import { RouteDefinitionParams } from '..'; +import { createLicensedRouteHandler } from '../licensed_route_handler'; interface RoleMappingsResponse { [roleMappingName: string]: Omit; diff --git a/x-pack/plugins/security/server/routes/role_mapping/index.ts b/x-pack/plugins/security/server/routes/role_mapping/index.ts index f09909bc3bf86..acb14a072ef3f 100644 --- a/x-pack/plugins/security/server/routes/role_mapping/index.ts +++ b/x-pack/plugins/security/server/routes/role_mapping/index.ts @@ -5,11 +5,11 @@ * 2.0. */ +import type { RouteDefinitionParams } from '../'; +import { defineRoleMappingDeleteRoutes } from './delete'; import { defineRoleMappingFeatureCheckRoute } from './feature_check'; import { defineRoleMappingGetRoutes } from './get'; import { defineRoleMappingPostRoutes } from './post'; -import { defineRoleMappingDeleteRoutes } from './delete'; -import { RouteDefinitionParams } from '..'; export function defineRoleMappingRoutes(params: RouteDefinitionParams) { defineRoleMappingFeatureCheckRoute(params); diff --git a/x-pack/plugins/security/server/routes/role_mapping/post.test.ts b/x-pack/plugins/security/server/routes/role_mapping/post.test.ts index a0c4e481d467a..727f3ba597336 100644 --- a/x-pack/plugins/security/server/routes/role_mapping/post.test.ts +++ b/x-pack/plugins/security/server/routes/role_mapping/post.test.ts @@ -5,9 +5,10 @@ * 2.0. */ -import { routeDefinitionParamsMock } from '../index.mock'; +import { kibanaResponseFactory } from 'src/core/server'; import { coreMock, httpServerMock } from 'src/core/server/mocks'; -import { kibanaResponseFactory } from '../../../../../../src/core/server'; + +import { routeDefinitionParamsMock } from '../index.mock'; import { defineRoleMappingPostRoutes } from './post'; describe('POST role mappings', () => { diff --git a/x-pack/plugins/security/server/routes/role_mapping/post.ts b/x-pack/plugins/security/server/routes/role_mapping/post.ts index e986599309a53..c76a169137053 100644 --- a/x-pack/plugins/security/server/routes/role_mapping/post.ts +++ b/x-pack/plugins/security/server/routes/role_mapping/post.ts @@ -6,9 +6,10 @@ */ import { schema } from '@kbn/config-schema'; -import { createLicensedRouteHandler } from '../licensed_route_handler'; + +import type { RouteDefinitionParams } from '../'; import { wrapError } from '../../errors'; -import { RouteDefinitionParams } from '..'; +import { createLicensedRouteHandler } from '../licensed_route_handler'; export function defineRoleMappingPostRoutes({ router }: RouteDefinitionParams) { router.post( diff --git a/x-pack/plugins/security/server/routes/session_management/extend.test.ts b/x-pack/plugins/security/server/routes/session_management/extend.test.ts index 34696e63a309e..4286cbfd0ed30 100644 --- a/x-pack/plugins/security/server/routes/session_management/extend.test.ts +++ b/x-pack/plugins/security/server/routes/session_management/extend.test.ts @@ -5,16 +5,13 @@ * 2.0. */ -import { - kibanaResponseFactory, - RequestHandler, - RouteConfig, -} from '../../../../../../src/core/server'; -import { defineSessionExtendRoutes } from './extend'; +import type { RequestHandler, RouteConfig } from 'src/core/server'; +import { kibanaResponseFactory } from 'src/core/server'; +import { httpServerMock } from 'src/core/server/mocks'; -import { httpServerMock } from '../../../../../../src/core/server/mocks'; import type { SecurityRequestHandlerContext, SecurityRouter } from '../../types'; import { routeDefinitionParamsMock } from '../index.mock'; +import { defineSessionExtendRoutes } from './extend'; describe('Extend session routes', () => { let router: jest.Mocked; diff --git a/x-pack/plugins/security/server/routes/session_management/extend.ts b/x-pack/plugins/security/server/routes/session_management/extend.ts index 8d438c351e7ee..0e89d6cb67981 100644 --- a/x-pack/plugins/security/server/routes/session_management/extend.ts +++ b/x-pack/plugins/security/server/routes/session_management/extend.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { RouteDefinitionParams } from '..'; +import type { RouteDefinitionParams } from '../'; /** * Defines routes required for the session extension. diff --git a/x-pack/plugins/security/server/routes/session_management/index.ts b/x-pack/plugins/security/server/routes/session_management/index.ts index 0778cc0f0b2f6..1348179386ce0 100644 --- a/x-pack/plugins/security/server/routes/session_management/index.ts +++ b/x-pack/plugins/security/server/routes/session_management/index.ts @@ -5,9 +5,9 @@ * 2.0. */ +import type { RouteDefinitionParams } from '../'; import { defineSessionExtendRoutes } from './extend'; import { defineSessionInfoRoutes } from './info'; -import { RouteDefinitionParams } from '..'; export function defineSessionManagementRoutes(params: RouteDefinitionParams) { defineSessionInfoRoutes(params); diff --git a/x-pack/plugins/security/server/routes/session_management/info.test.ts b/x-pack/plugins/security/server/routes/session_management/info.test.ts index 84db94f38d582..29c0865b8c561 100644 --- a/x-pack/plugins/security/server/routes/session_management/info.test.ts +++ b/x-pack/plugins/security/server/routes/session_management/info.test.ts @@ -5,19 +5,16 @@ * 2.0. */ -import { - kibanaResponseFactory, - RequestHandler, - RouteConfig, -} from '../../../../../../src/core/server'; import type { PublicMethodsOf } from '@kbn/utility-types'; -import { Session } from '../../session_management'; -import { defineSessionInfoRoutes } from './info'; -import type { SecurityRequestHandlerContext, SecurityRouter } from '../../types'; +import type { RequestHandler, RouteConfig } from 'src/core/server'; +import { kibanaResponseFactory } from 'src/core/server'; +import { httpServerMock } from 'src/core/server/mocks'; -import { httpServerMock } from '../../../../../../src/core/server/mocks'; +import type { Session } from '../../session_management'; import { sessionMock } from '../../session_management/session.mock'; +import type { SecurityRequestHandlerContext, SecurityRouter } from '../../types'; import { routeDefinitionParamsMock } from '../index.mock'; +import { defineSessionInfoRoutes } from './info'; describe('Info session routes', () => { let router: jest.Mocked; diff --git a/x-pack/plugins/security/server/routes/session_management/info.ts b/x-pack/plugins/security/server/routes/session_management/info.ts index 6cab44509f162..cfd76bb8abbc0 100644 --- a/x-pack/plugins/security/server/routes/session_management/info.ts +++ b/x-pack/plugins/security/server/routes/session_management/info.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { SessionInfo } from '../../../common/types'; -import { RouteDefinitionParams } from '..'; +import type { RouteDefinitionParams } from '../'; +import type { SessionInfo } from '../../../common/types'; /** * Defines routes required for the session info. diff --git a/x-pack/plugins/security/server/routes/users/change_password.test.ts b/x-pack/plugins/security/server/routes/users/change_password.test.ts index 0258b1af051d4..a97fce7ea4b19 100644 --- a/x-pack/plugins/security/server/routes/users/change_password.test.ts +++ b/x-pack/plugins/security/server/routes/users/change_password.test.ts @@ -6,25 +6,23 @@ */ import { errors } from 'elasticsearch'; -import { ObjectType } from '@kbn/config-schema'; + +import type { ObjectType } from '@kbn/config-schema'; import type { PublicMethodsOf } from '@kbn/utility-types'; import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; -import type { SecurityRequestHandlerContext, SecurityRouter } from '../../types'; -import { - Headers, - kibanaResponseFactory, - RequestHandler, - RouteConfig, -} from '../../../../../../src/core/server'; -import { AuthenticationResult, AuthenticationServiceStart } from '../../authentication'; -import { Session } from '../../session_management'; -import { defineChangeUserPasswordRoutes } from './change_password'; +import type { Headers, RequestHandler, RouteConfig } from 'src/core/server'; +import { kibanaResponseFactory } from 'src/core/server'; +import { coreMock, httpServerMock } from 'src/core/server/mocks'; -import { coreMock, httpServerMock } from '../../../../../../src/core/server/mocks'; import { mockAuthenticatedUser } from '../../../common/model/authenticated_user.mock'; +import type { AuthenticationServiceStart } from '../../authentication'; +import { AuthenticationResult } from '../../authentication'; +import { authenticationServiceMock } from '../../authentication/authentication_service.mock'; +import type { Session } from '../../session_management'; import { sessionMock } from '../../session_management/session.mock'; +import type { SecurityRequestHandlerContext, SecurityRouter } from '../../types'; import { routeDefinitionParamsMock } from '../index.mock'; -import { authenticationServiceMock } from '../../authentication/authentication_service.mock'; +import { defineChangeUserPasswordRoutes } from './change_password'; describe('Change password', () => { let router: jest.Mocked; diff --git a/x-pack/plugins/security/server/routes/users/change_password.ts b/x-pack/plugins/security/server/routes/users/change_password.ts index a3d0295f08d6a..d9863b5061391 100644 --- a/x-pack/plugins/security/server/routes/users/change_password.ts +++ b/x-pack/plugins/security/server/routes/users/change_password.ts @@ -6,14 +6,15 @@ */ import { schema } from '@kbn/config-schema'; + +import type { RouteDefinitionParams } from '../'; import { canUserChangePassword } from '../../../common/model'; -import { getErrorStatusCode, wrapIntoCustomErrorResponse } from '../../errors'; -import { createLicensedRouteHandler } from '../licensed_route_handler'; import { - HTTPAuthorizationHeader, BasicHTTPAuthorizationHeaderCredentials, + HTTPAuthorizationHeader, } from '../../authentication'; -import { RouteDefinitionParams } from '..'; +import { getErrorStatusCode, wrapIntoCustomErrorResponse } from '../../errors'; +import { createLicensedRouteHandler } from '../licensed_route_handler'; export function defineChangeUserPasswordRoutes({ getAuthenticationService, diff --git a/x-pack/plugins/security/server/routes/users/create_or_update.ts b/x-pack/plugins/security/server/routes/users/create_or_update.ts index a68fadd7622a1..6527d9afc9842 100644 --- a/x-pack/plugins/security/server/routes/users/create_or_update.ts +++ b/x-pack/plugins/security/server/routes/users/create_or_update.ts @@ -6,9 +6,10 @@ */ import { schema } from '@kbn/config-schema'; + +import type { RouteDefinitionParams } from '../'; import { wrapIntoCustomErrorResponse } from '../../errors'; import { createLicensedRouteHandler } from '../licensed_route_handler'; -import { RouteDefinitionParams } from '..'; export function defineCreateOrUpdateUserRoutes({ router }: RouteDefinitionParams) { router.post( diff --git a/x-pack/plugins/security/server/routes/users/delete.ts b/x-pack/plugins/security/server/routes/users/delete.ts index 34e02c9167700..767cda4b566a5 100644 --- a/x-pack/plugins/security/server/routes/users/delete.ts +++ b/x-pack/plugins/security/server/routes/users/delete.ts @@ -6,8 +6,9 @@ */ import { schema } from '@kbn/config-schema'; -import { RouteDefinitionParams } from '../index'; + import { wrapIntoCustomErrorResponse } from '../../errors'; +import type { RouteDefinitionParams } from '../index'; import { createLicensedRouteHandler } from '../licensed_route_handler'; export function defineDeleteUserRoutes({ router }: RouteDefinitionParams) { diff --git a/x-pack/plugins/security/server/routes/users/disable.ts b/x-pack/plugins/security/server/routes/users/disable.ts index 4f5ed71010f9a..0a5c4c03f4fb0 100644 --- a/x-pack/plugins/security/server/routes/users/disable.ts +++ b/x-pack/plugins/security/server/routes/users/disable.ts @@ -6,8 +6,9 @@ */ import { schema } from '@kbn/config-schema'; -import { RouteDefinitionParams } from '../index'; + import { wrapIntoCustomErrorResponse } from '../../errors'; +import type { RouteDefinitionParams } from '../index'; import { createLicensedRouteHandler } from '../licensed_route_handler'; export function defineDisableUserRoutes({ router }: RouteDefinitionParams) { diff --git a/x-pack/plugins/security/server/routes/users/enable.ts b/x-pack/plugins/security/server/routes/users/enable.ts index 749688e084d19..8f8d91cf42aca 100644 --- a/x-pack/plugins/security/server/routes/users/enable.ts +++ b/x-pack/plugins/security/server/routes/users/enable.ts @@ -6,8 +6,9 @@ */ import { schema } from '@kbn/config-schema'; -import { RouteDefinitionParams } from '../index'; + import { wrapIntoCustomErrorResponse } from '../../errors'; +import type { RouteDefinitionParams } from '../index'; import { createLicensedRouteHandler } from '../licensed_route_handler'; export function defineEnableUserRoutes({ router }: RouteDefinitionParams) { diff --git a/x-pack/plugins/security/server/routes/users/get.ts b/x-pack/plugins/security/server/routes/users/get.ts index 252a9778dae0e..28165ef32356d 100644 --- a/x-pack/plugins/security/server/routes/users/get.ts +++ b/x-pack/plugins/security/server/routes/users/get.ts @@ -6,9 +6,10 @@ */ import { schema } from '@kbn/config-schema'; + +import type { RouteDefinitionParams } from '../'; import { wrapIntoCustomErrorResponse } from '../../errors'; import { createLicensedRouteHandler } from '../licensed_route_handler'; -import { RouteDefinitionParams } from '..'; export function defineGetUserRoutes({ router }: RouteDefinitionParams) { router.get( diff --git a/x-pack/plugins/security/server/routes/users/get_all.ts b/x-pack/plugins/security/server/routes/users/get_all.ts index 8c17f4bfcbb51..5d28d98b684ec 100644 --- a/x-pack/plugins/security/server/routes/users/get_all.ts +++ b/x-pack/plugins/security/server/routes/users/get_all.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { RouteDefinitionParams } from '../index'; import { wrapIntoCustomErrorResponse } from '../../errors'; +import type { RouteDefinitionParams } from '../index'; import { createLicensedRouteHandler } from '../licensed_route_handler'; export function defineGetAllUsersRoutes({ router }: RouteDefinitionParams) { diff --git a/x-pack/plugins/security/server/routes/users/index.ts b/x-pack/plugins/security/server/routes/users/index.ts index 312086914cbc6..b6bb694b5efe6 100644 --- a/x-pack/plugins/security/server/routes/users/index.ts +++ b/x-pack/plugins/security/server/routes/users/index.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { RouteDefinitionParams } from '../index'; -import { defineGetUserRoutes } from './get'; -import { defineGetAllUsersRoutes } from './get_all'; +import type { RouteDefinitionParams } from '../index'; +import { defineChangeUserPasswordRoutes } from './change_password'; import { defineCreateOrUpdateUserRoutes } from './create_or_update'; import { defineDeleteUserRoutes } from './delete'; import { defineDisableUserRoutes } from './disable'; import { defineEnableUserRoutes } from './enable'; -import { defineChangeUserPasswordRoutes } from './change_password'; +import { defineGetUserRoutes } from './get'; +import { defineGetAllUsersRoutes } from './get_all'; export function defineUsersRoutes(params: RouteDefinitionParams) { defineGetUserRoutes(params); diff --git a/x-pack/plugins/security/server/routes/views/access_agreement.test.ts b/x-pack/plugins/security/server/routes/views/access_agreement.test.ts index e4b4a6232d5e9..2679616b2be16 100644 --- a/x-pack/plugins/security/server/routes/views/access_agreement.test.ts +++ b/x-pack/plugins/security/server/routes/views/access_agreement.test.ts @@ -6,23 +6,23 @@ */ import type { PublicMethodsOf } from '@kbn/utility-types'; -import { - RequestHandler, - RouteConfig, - kibanaResponseFactory, +import type { HttpResources, HttpResourcesRequestHandler, -} from '../../../../../../src/core/server'; -import { SecurityLicense, SecurityLicenseFeatures } from '../../../common/licensing'; -import type { AuthenticationProvider } from '../../../common/model'; -import { ConfigType } from '../../config'; -import { Session } from '../../session_management'; -import { defineAccessAgreementRoutes } from './access_agreement'; -import type { SecurityRouter, SecurityRequestHandlerContext } from '../../types'; + RequestHandler, + RouteConfig, +} from 'src/core/server'; +import { kibanaResponseFactory } from 'src/core/server'; +import { httpResourcesMock, httpServerMock } from 'src/core/server/mocks'; -import { httpResourcesMock, httpServerMock } from '../../../../../../src/core/server/mocks'; +import type { SecurityLicense, SecurityLicenseFeatures } from '../../../common/licensing'; +import type { AuthenticationProvider } from '../../../common/model'; +import type { ConfigType } from '../../config'; +import type { Session } from '../../session_management'; import { sessionMock } from '../../session_management/session.mock'; +import type { SecurityRequestHandlerContext, SecurityRouter } from '../../types'; import { routeDefinitionParamsMock } from '../index.mock'; +import { defineAccessAgreementRoutes } from './access_agreement'; describe('Access agreement view routes', () => { let httpResources: jest.Mocked; diff --git a/x-pack/plugins/security/server/routes/views/access_agreement.ts b/x-pack/plugins/security/server/routes/views/access_agreement.ts index daf697bd23448..292c484690ec8 100644 --- a/x-pack/plugins/security/server/routes/views/access_agreement.ts +++ b/x-pack/plugins/security/server/routes/views/access_agreement.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { ConfigType } from '../../config'; +import type { RouteDefinitionParams } from '../'; +import type { ConfigType } from '../../config'; import { createLicensedRouteHandler } from '../licensed_route_handler'; -import { RouteDefinitionParams } from '..'; /** * Defines routes required for the Access Agreement view. diff --git a/x-pack/plugins/security/server/routes/views/account_management.ts b/x-pack/plugins/security/server/routes/views/account_management.ts index 55d9dd1603602..bab0faedcd9cc 100644 --- a/x-pack/plugins/security/server/routes/views/account_management.ts +++ b/x-pack/plugins/security/server/routes/views/account_management.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { RouteDefinitionParams } from '..'; +import type { RouteDefinitionParams } from '../'; /** * Defines routes required for the Account Management view. diff --git a/x-pack/plugins/security/server/routes/views/capture_url.test.ts b/x-pack/plugins/security/server/routes/views/capture_url.test.ts index fb9fa4031f51a..0393a69276ff3 100644 --- a/x-pack/plugins/security/server/routes/views/capture_url.test.ts +++ b/x-pack/plugins/security/server/routes/views/capture_url.test.ts @@ -6,16 +6,12 @@ */ import { Type } from '@kbn/config-schema'; -import { - RouteConfig, - HttpResources, - HttpResourcesRequestHandler, -} from '../../../../../../src/core/server'; -import { defineCaptureURLRoutes } from './capture_url'; +import type { HttpResources, HttpResourcesRequestHandler, RouteConfig } from 'src/core/server'; +import { httpResourcesMock, httpServerMock } from 'src/core/server/mocks'; -import { httpResourcesMock, httpServerMock } from '../../../../../../src/core/server/mocks'; -import { routeDefinitionParamsMock } from '../index.mock'; import type { SecurityRequestHandlerContext } from '../../types'; +import { routeDefinitionParamsMock } from '../index.mock'; +import { defineCaptureURLRoutes } from './capture_url'; describe('Capture URL view routes', () => { let httpResources: jest.Mocked; diff --git a/x-pack/plugins/security/server/routes/views/capture_url.ts b/x-pack/plugins/security/server/routes/views/capture_url.ts index 92a1984160c3d..1ea1c8ad620e4 100644 --- a/x-pack/plugins/security/server/routes/views/capture_url.ts +++ b/x-pack/plugins/security/server/routes/views/capture_url.ts @@ -6,7 +6,8 @@ */ import { schema } from '@kbn/config-schema'; -import { RouteDefinitionParams } from '..'; + +import type { RouteDefinitionParams } from '../'; /** * Defines routes required for the Capture URL view. diff --git a/x-pack/plugins/security/server/routes/views/index.test.ts b/x-pack/plugins/security/server/routes/views/index.test.ts index 57d0e9ffffcbd..be85498f0bb1e 100644 --- a/x-pack/plugins/security/server/routes/views/index.test.ts +++ b/x-pack/plugins/security/server/routes/views/index.test.ts @@ -5,9 +5,8 @@ * 2.0. */ -import { defineViewRoutes } from '.'; - import { routeDefinitionParamsMock } from '../index.mock'; +import { defineViewRoutes } from './'; describe('View routes', () => { it('does not register Login routes if both `basic` and `token` providers are disabled', () => { diff --git a/x-pack/plugins/security/server/routes/views/index.ts b/x-pack/plugins/security/server/routes/views/index.ts index 8cd6798ae58b0..5993808d0cfb0 100644 --- a/x-pack/plugins/security/server/routes/views/index.ts +++ b/x-pack/plugins/security/server/routes/views/index.ts @@ -5,14 +5,14 @@ * 2.0. */ +import type { RouteDefinitionParams } from '../'; import { defineAccessAgreementRoutes } from './access_agreement'; import { defineAccountManagementRoutes } from './account_management'; +import { defineCaptureURLRoutes } from './capture_url'; import { defineLoggedOutRoutes } from './logged_out'; import { defineLoginRoutes } from './login'; import { defineLogoutRoutes } from './logout'; import { defineOverwrittenSessionRoutes } from './overwritten_session'; -import { defineCaptureURLRoutes } from './capture_url'; -import { RouteDefinitionParams } from '..'; export function defineViewRoutes(params: RouteDefinitionParams) { if ( diff --git a/x-pack/plugins/security/server/routes/views/logged_out.test.ts b/x-pack/plugins/security/server/routes/views/logged_out.test.ts index 5c665b6737fae..af973d1e060db 100644 --- a/x-pack/plugins/security/server/routes/views/logged_out.test.ts +++ b/x-pack/plugins/security/server/routes/views/logged_out.test.ts @@ -6,13 +6,13 @@ */ import type { PublicMethodsOf } from '@kbn/utility-types'; -import { HttpResourcesRequestHandler, RouteConfig } from '../../../../../../src/core/server'; -import { Session } from '../../session_management'; -import { defineLoggedOutRoutes } from './logged_out'; +import type { HttpResourcesRequestHandler, RouteConfig } from 'src/core/server'; +import { httpResourcesMock, httpServerMock } from 'src/core/server/mocks'; -import { httpServerMock, httpResourcesMock } from '../../../../../../src/core/server/mocks'; +import type { Session } from '../../session_management'; import { sessionMock } from '../../session_management/session.mock'; import { routeDefinitionParamsMock } from '../index.mock'; +import { defineLoggedOutRoutes } from './logged_out'; describe('LoggedOut view routes', () => { let session: jest.Mocked>; diff --git a/x-pack/plugins/security/server/routes/views/logged_out.ts b/x-pack/plugins/security/server/routes/views/logged_out.ts index 6f7a92a4229ca..8d22e4efc3ddc 100644 --- a/x-pack/plugins/security/server/routes/views/logged_out.ts +++ b/x-pack/plugins/security/server/routes/views/logged_out.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { RouteDefinitionParams } from '..'; +import type { RouteDefinitionParams } from '../'; /** * Defines routes required for the Logged Out view. diff --git a/x-pack/plugins/security/server/routes/views/login.test.ts b/x-pack/plugins/security/server/routes/views/login.test.ts index 96b3b5379d44f..6def1b7d77df3 100644 --- a/x-pack/plugins/security/server/routes/views/login.test.ts +++ b/x-pack/plugins/security/server/routes/views/login.test.ts @@ -6,26 +6,23 @@ */ import { URL } from 'url'; + import { Type } from '@kbn/config-schema'; -import { +import type { HttpResources, HttpResourcesRequestHandler, RequestHandler, - kibanaResponseFactory, RouteConfig, -} from '../../../../../../src/core/server'; -import { SecurityLicense } from '../../../common/licensing'; -import { LoginSelectorProvider } from '../../../common/login_state'; -import { ConfigType } from '../../config'; -import { defineLoginRoutes } from './login'; -import type { SecurityRouter, SecurityRequestHandlerContext } from '../../types'; - -import { - coreMock, - httpServerMock, - httpResourcesMock, -} from '../../../../../../src/core/server/mocks'; +} from 'src/core/server'; +import { kibanaResponseFactory } from 'src/core/server'; +import { coreMock, httpResourcesMock, httpServerMock } from 'src/core/server/mocks'; + +import type { SecurityLicense } from '../../../common/licensing'; +import type { LoginSelectorProvider } from '../../../common/login_state'; +import type { ConfigType } from '../../config'; +import type { SecurityRequestHandlerContext, SecurityRouter } from '../../types'; import { routeDefinitionParamsMock } from '../index.mock'; +import { defineLoginRoutes } from './login'; describe('Login view routes', () => { let httpResources: jest.Mocked; diff --git a/x-pack/plugins/security/server/routes/views/login.ts b/x-pack/plugins/security/server/routes/views/login.ts index 607e11a8379c5..990ac4075efe0 100644 --- a/x-pack/plugins/security/server/routes/views/login.ts +++ b/x-pack/plugins/security/server/routes/views/login.ts @@ -6,14 +6,15 @@ */ import { schema } from '@kbn/config-schema'; -import { parseNext } from '../../../common/parse_next'; -import { LoginState } from '../../../common/login_state'; -import { shouldProviderUseLoginForm } from '../../../common/model'; + +import type { RouteDefinitionParams } from '../'; import { LOGOUT_REASON_QUERY_STRING_PARAMETER, NEXT_URL_QUERY_STRING_PARAMETER, } from '../../../common/constants'; -import { RouteDefinitionParams } from '..'; +import type { LoginState } from '../../../common/login_state'; +import { shouldProviderUseLoginForm } from '../../../common/model'; +import { parseNext } from '../../../common/parse_next'; /** * Defines routes required for the Login view. diff --git a/x-pack/plugins/security/server/routes/views/logout.ts b/x-pack/plugins/security/server/routes/views/logout.ts index 8c41a8443b497..5e5d5c0bb6f01 100644 --- a/x-pack/plugins/security/server/routes/views/logout.ts +++ b/x-pack/plugins/security/server/routes/views/logout.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { RouteDefinitionParams } from '..'; +import type { RouteDefinitionParams } from '../'; /** * Defines routes required for the Logout out view. diff --git a/x-pack/plugins/security/server/routes/views/overwritten_session.ts b/x-pack/plugins/security/server/routes/views/overwritten_session.ts index 9115044a77687..7ed5cffbc56f8 100644 --- a/x-pack/plugins/security/server/routes/views/overwritten_session.ts +++ b/x-pack/plugins/security/server/routes/views/overwritten_session.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { RouteDefinitionParams } from '..'; +import type { RouteDefinitionParams } from '../'; /** * Defines routes required for the Overwritten Session view. diff --git a/x-pack/plugins/security/server/saved_objects/index.ts b/x-pack/plugins/security/server/saved_objects/index.ts index 494adbd15c0df..e052fd1c7ab6a 100644 --- a/x-pack/plugins/security/server/saved_objects/index.ts +++ b/x-pack/plugins/security/server/saved_objects/index.ts @@ -5,16 +5,13 @@ * 2.0. */ -import { - CoreSetup, - KibanaRequest, - LegacyRequest, - SavedObjectsClient, -} from '../../../../../src/core/server'; +import type { CoreSetup, LegacyRequest } from 'src/core/server'; + +import { KibanaRequest, SavedObjectsClient } from '../../../../../src/core/server'; +import type { AuditServiceSetup, SecurityAuditLogger } from '../audit'; +import type { AuthorizationServiceSetup } from '../authorization'; +import type { SpacesService } from '../plugin'; import { SecureSavedObjectsClientWrapper } from './secure_saved_objects_client_wrapper'; -import { AuthorizationServiceSetup } from '../authorization'; -import { SecurityAuditLogger, AuditServiceSetup } from '../audit'; -import { SpacesService } from '../plugin'; interface SetupSavedObjectsParams { legacyAuditLogger: SecurityAuditLogger; diff --git a/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.test.ts b/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.test.ts index 1293d3f2c84a3..803b36e520a2f 100644 --- a/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.test.ts +++ b/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.test.ts @@ -5,17 +5,19 @@ * 2.0. */ -import { SecureSavedObjectsClientWrapper } from './secure_saved_objects_client_wrapper'; +import type { SavedObjectsClientContract } from 'src/core/server'; +import { httpServerMock, savedObjectsClientMock } from 'src/core/server/mocks'; + +import type { AuditEvent } from '../audit'; +import { EventOutcome } from '../audit'; +import { auditServiceMock, securityAuditLoggerMock } from '../audit/index.mock'; import { Actions } from '../authorization'; -import { securityAuditLoggerMock, auditServiceMock } from '../audit/index.mock'; -import { savedObjectsClientMock, httpServerMock } from '../../../../../src/core/server/mocks'; -import { SavedObjectsClientContract } from 'kibana/server'; -import { SavedObjectActions } from '../authorization/actions/saved_object'; -import { AuditEvent, EventOutcome } from '../audit'; +import type { SavedObjectActions } from '../authorization/actions/saved_object'; +import { SecureSavedObjectsClientWrapper } from './secure_saved_objects_client_wrapper'; -jest.mock('../../../../../src/core/server/saved_objects/service/lib/utils', () => { +jest.mock('src/core/server/saved_objects/service/lib/utils', () => { const { SavedObjectsUtils } = jest.requireActual( - '../../../../../src/core/server/saved_objects/service/lib/utils' + 'src/core/server/saved_objects/service/lib/utils' ); return { SavedObjectsUtils: { diff --git a/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.ts b/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.ts index 73bee302363ab..1858bc7108dc9 100644 --- a/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.ts +++ b/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.ts @@ -6,7 +6,7 @@ */ import type { PublicMethodsOf } from '@kbn/utility-types'; -import { +import type { SavedObjectsAddToNamespacesOptions, SavedObjectsBaseOptions, SavedObjectsBulkCreateObject, @@ -14,26 +14,22 @@ import { SavedObjectsBulkUpdateObject, SavedObjectsCheckConflictsObject, SavedObjectsClientContract, + SavedObjectsClosePointInTimeOptions, SavedObjectsCreateOptions, SavedObjectsDeleteFromNamespacesOptions, SavedObjectsFindOptions, SavedObjectsOpenPointInTimeOptions, - SavedObjectsClosePointInTimeOptions, SavedObjectsRemoveReferencesToOptions, SavedObjectsUpdateOptions, - SavedObjectsUtils, -} from '../../../../../src/core/server'; +} from 'src/core/server'; + +import { SavedObjectsUtils } from '../../../../../src/core/server'; import { ALL_SPACES_ID, UNKNOWN_SPACE } from '../../common/constants'; -import { - AuditLogger, - EventOutcome, - SavedObjectAction, - savedObjectEvent, - SecurityAuditLogger, -} from '../audit'; -import { Actions, CheckSavedObjectsPrivileges } from '../authorization'; -import { CheckPrivilegesResponse } from '../authorization/types'; -import { SpacesService } from '../plugin'; +import type { AuditLogger, SecurityAuditLogger } from '../audit'; +import { EventOutcome, SavedObjectAction, savedObjectEvent } from '../audit'; +import type { Actions, CheckSavedObjectsPrivileges } from '../authorization'; +import type { CheckPrivilegesResponse } from '../authorization/types'; +import type { SpacesService } from '../plugin'; interface SecureSavedObjectsClientWrapperOptions { actions: Actions; diff --git a/x-pack/plugins/security/server/session_management/session.mock.ts b/x-pack/plugins/security/server/session_management/session.mock.ts index 1be8adb94acbb..dfe1293f57e92 100644 --- a/x-pack/plugins/security/server/session_management/session.mock.ts +++ b/x-pack/plugins/security/server/session_management/session.mock.ts @@ -6,8 +6,9 @@ */ import type { PublicMethodsOf } from '@kbn/utility-types'; + import { mockAuthenticatedUser } from '../../common/model/authenticated_user.mock'; -import { Session, SessionValue } from './session'; +import type { Session, SessionValue } from './session'; import { sessionIndexMock } from './session_index.mock'; export const sessionMock = { diff --git a/x-pack/plugins/security/server/session_management/session.test.ts b/x-pack/plugins/security/server/session_management/session.test.ts index f3e3be79af655..bd94c9483d561 100644 --- a/x-pack/plugins/security/server/session_management/session.test.ts +++ b/x-pack/plugins/security/server/session_management/session.test.ts @@ -5,17 +5,19 @@ * 2.0. */ -import crypto from 'crypto'; import nodeCrypto from '@elastic/node-crypto'; +import crypto from 'crypto'; + import type { PublicMethodsOf } from '@kbn/utility-types'; -import { ConfigSchema, createConfig } from '../config'; -import { Session, SessionValueContentToEncrypt } from './session'; -import { SessionIndex } from './session_index'; -import { SessionCookie } from './session_cookie'; +import { httpServerMock, loggingSystemMock } from 'src/core/server/mocks'; -import { loggingSystemMock, httpServerMock } from '../../../../../src/core/server/mocks'; -import { sessionMock, sessionCookieMock, sessionIndexMock } from './index.mock'; import { mockAuthenticatedUser } from '../../common/model/authenticated_user.mock'; +import { ConfigSchema, createConfig } from '../config'; +import { sessionCookieMock, sessionIndexMock, sessionMock } from './index.mock'; +import type { SessionValueContentToEncrypt } from './session'; +import { Session } from './session'; +import type { SessionCookie } from './session_cookie'; +import type { SessionIndex } from './session_index'; describe('Session', () => { const now = 123456; diff --git a/x-pack/plugins/security/server/session_management/session.ts b/x-pack/plugins/security/server/session_management/session.ts index eaffe44976c7f..7fada4d1730cd 100644 --- a/x-pack/plugins/security/server/session_management/session.ts +++ b/x-pack/plugins/security/server/session_management/session.ts @@ -5,15 +5,18 @@ * 2.0. */ +import type { Crypto } from '@elastic/node-crypto'; +import nodeCrypto from '@elastic/node-crypto'; +import { createHash, randomBytes } from 'crypto'; import { promisify } from 'util'; -import { randomBytes, createHash } from 'crypto'; -import nodeCrypto, { Crypto } from '@elastic/node-crypto'; + import type { PublicMethodsOf } from '@kbn/utility-types'; -import type { KibanaRequest, Logger } from '../../../../../src/core/server'; +import type { KibanaRequest, Logger } from 'src/core/server'; + import type { AuthenticationProvider } from '../../common/model'; import type { ConfigType } from '../config'; -import type { SessionIndex, SessionIndexValue } from './session_index'; import type { SessionCookie } from './session_cookie'; +import type { SessionIndex, SessionIndexValue } from './session_index'; /** * The shape of the value that represents user's session information. diff --git a/x-pack/plugins/security/server/session_management/session_cookie.mock.ts b/x-pack/plugins/security/server/session_management/session_cookie.mock.ts index dc8a9ce1c717b..ff3b6e717e65c 100644 --- a/x-pack/plugins/security/server/session_management/session_cookie.mock.ts +++ b/x-pack/plugins/security/server/session_management/session_cookie.mock.ts @@ -6,7 +6,8 @@ */ import type { PublicMethodsOf } from '@kbn/utility-types'; -import { SessionCookie, SessionCookieValue } from './session_cookie'; + +import type { SessionCookie, SessionCookieValue } from './session_cookie'; export const sessionCookieMock = { create: (): jest.Mocked> => ({ diff --git a/x-pack/plugins/security/server/session_management/session_cookie.test.ts b/x-pack/plugins/security/server/session_management/session_cookie.test.ts index fe6ae61daa0dc..cb14fb03ec85d 100644 --- a/x-pack/plugins/security/server/session_management/session_cookie.test.ts +++ b/x-pack/plugins/security/server/session_management/session_cookie.test.ts @@ -5,15 +5,16 @@ * 2.0. */ -import { SessionStorage } from '../../../../../src/core/server'; -import { SessionCookie, SessionCookieOptions } from './session_cookie'; - +import type { SessionStorage } from 'src/core/server'; import { - loggingSystemMock, + httpServerMock, httpServiceMock, + loggingSystemMock, sessionStorageMock, - httpServerMock, -} from '../../../../../src/core/server/mocks'; +} from 'src/core/server/mocks'; + +import type { SessionCookieOptions } from './session_cookie'; +import { SessionCookie } from './session_cookie'; import { sessionCookieMock } from './session_cookie.mock'; describe('Session cookie', () => { diff --git a/x-pack/plugins/security/server/session_management/session_cookie.ts b/x-pack/plugins/security/server/session_management/session_cookie.ts index d4a5da46acc2e..964d3d07a39a2 100644 --- a/x-pack/plugins/security/server/session_management/session_cookie.ts +++ b/x-pack/plugins/security/server/session_management/session_cookie.ts @@ -5,13 +5,14 @@ * 2.0. */ -import { +import type { HttpServiceSetup, KibanaRequest, Logger, SessionStorageFactory, -} from '../../../../../src/core/server'; -import { ConfigType } from '../config'; +} from 'src/core/server'; + +import type { ConfigType } from '../config'; /** * Represents shape of the session value stored in the cookie. diff --git a/x-pack/plugins/security/server/session_management/session_index.mock.ts b/x-pack/plugins/security/server/session_management/session_index.mock.ts index ca727f1213048..56049a3ae9205 100644 --- a/x-pack/plugins/security/server/session_management/session_index.mock.ts +++ b/x-pack/plugins/security/server/session_management/session_index.mock.ts @@ -6,7 +6,8 @@ */ import type { PublicMethodsOf } from '@kbn/utility-types'; -import { SessionIndex, SessionIndexValue } from './session_index'; + +import type { SessionIndex, SessionIndexValue } from './session_index'; export const sessionIndexMock = { create: (): jest.Mocked> => ({ diff --git a/x-pack/plugins/security/server/session_management/session_index.test.ts b/x-pack/plugins/security/server/session_management/session_index.test.ts index b9d0f9506fec8..2b3ec0adeb51e 100644 --- a/x-pack/plugins/security/server/session_management/session_index.test.ts +++ b/x-pack/plugins/security/server/session_management/session_index.test.ts @@ -6,13 +6,14 @@ */ import { errors } from '@elastic/elasticsearch'; -import { DeeplyMockedKeys } from '@kbn/utility-types/jest'; -import { ElasticsearchClient } from '../../../../../src/core/server'; -import { ConfigSchema, createConfig } from '../config'; -import { getSessionIndexTemplate, SessionIndex } from './session_index'; -import { loggingSystemMock, elasticsearchServiceMock } from '../../../../../src/core/server/mocks'; +import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; +import type { ElasticsearchClient } from 'src/core/server'; +import { elasticsearchServiceMock, loggingSystemMock } from 'src/core/server/mocks'; + +import { ConfigSchema, createConfig } from '../config'; import { securityMock } from '../mocks'; +import { getSessionIndexTemplate, SessionIndex } from './session_index'; import { sessionIndexMock } from './session_index.mock'; describe('Session index', () => { diff --git a/x-pack/plugins/security/server/session_management/session_index.ts b/x-pack/plugins/security/server/session_management/session_index.ts index 934d43924c787..828c8fa11acdd 100644 --- a/x-pack/plugins/security/server/session_management/session_index.ts +++ b/x-pack/plugins/security/server/session_management/session_index.ts @@ -5,7 +5,8 @@ * 2.0. */ -import type { ElasticsearchClient, Logger } from '../../../../../src/core/server'; +import type { ElasticsearchClient, Logger } from 'src/core/server'; + import type { AuthenticationProvider } from '../../common/model'; import type { ConfigType } from '../config'; diff --git a/x-pack/plugins/security/server/session_management/session_management_service.test.ts b/x-pack/plugins/security/server/session_management/session_management_service.test.ts index baee05dce4585..7e99181981e85 100644 --- a/x-pack/plugins/security/server/session_management/session_management_service.test.ts +++ b/x-pack/plugins/security/server/session_management/session_management_service.test.ts @@ -6,23 +6,23 @@ */ import { Subject } from 'rxjs'; + +import { nextTick } from '@kbn/test/jest'; +import { coreMock, elasticsearchServiceMock, loggingSystemMock } from 'src/core/server/mocks'; + +import type { + TaskManagerStartContract, + TaskRunCreatorFunction, +} from '../../../task_manager/server'; +import { taskManagerMock } from '../../../task_manager/server/mocks'; import { ConfigSchema, createConfig } from '../config'; -import { OnlineStatusRetryScheduler } from '../elasticsearch'; -import { - SessionManagementService, - SESSION_INDEX_CLEANUP_TASK_NAME, -} from './session_management_service'; +import type { OnlineStatusRetryScheduler } from '../elasticsearch'; import { Session } from './session'; import { SessionIndex } from './session_index'; - -import { nextTick } from '@kbn/test/jest'; import { - coreMock, - elasticsearchServiceMock, - loggingSystemMock, -} from '../../../../../src/core/server/mocks'; -import { taskManagerMock } from '../../../task_manager/server/mocks'; -import { TaskManagerStartContract, TaskRunCreatorFunction } from '../../../task_manager/server'; + SESSION_INDEX_CLEANUP_TASK_NAME, + SessionManagementService, +} from './session_management_service'; describe('SessionManagementService', () => { let service: SessionManagementService; diff --git a/x-pack/plugins/security/server/session_management/session_management_service.ts b/x-pack/plugins/security/server/session_management/session_management_service.ts index a3b2c999115fd..fcd8e8c53cbe5 100644 --- a/x-pack/plugins/security/server/session_management/session_management_service.ts +++ b/x-pack/plugins/security/server/session_management/session_management_service.ts @@ -5,19 +5,20 @@ * 2.0. */ -import { Observable, Subscription } from 'rxjs'; -import { - ElasticsearchClient, - HttpServiceSetup, - Logger, - SavedObjectsErrorHelpers, -} from '../../../../../src/core/server'; -import { TaskManagerSetupContract, TaskManagerStartContract } from '../../../task_manager/server'; -import { ConfigType } from '../config'; -import { OnlineStatusRetryScheduler } from '../elasticsearch'; +import type { Observable, Subscription } from 'rxjs'; + +import type { ElasticsearchClient, HttpServiceSetup, Logger } from 'src/core/server'; + +import { SavedObjectsErrorHelpers } from '../../../../../src/core/server'; +import type { + TaskManagerSetupContract, + TaskManagerStartContract, +} from '../../../task_manager/server'; +import type { ConfigType } from '../config'; +import type { OnlineStatusRetryScheduler } from '../elasticsearch'; +import { Session } from './session'; import { SessionCookie } from './session_cookie'; import { SessionIndex } from './session_index'; -import { Session } from './session'; export interface SessionManagementServiceSetupParams { readonly http: Pick; diff --git a/x-pack/plugins/security/server/spaces/legacy_audit_logger.ts b/x-pack/plugins/security/server/spaces/legacy_audit_logger.ts index 0e36b29a5ba32..3ac4859eb7c8a 100644 --- a/x-pack/plugins/security/server/spaces/legacy_audit_logger.ts +++ b/x-pack/plugins/security/server/spaces/legacy_audit_logger.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { LegacyAuditLogger } from '../audit'; +import type { LegacyAuditLogger } from '../audit'; /** * @deprecated will be removed in 8.0 diff --git a/x-pack/plugins/security/server/spaces/secure_spaces_client_wrapper.test.ts b/x-pack/plugins/security/server/spaces/secure_spaces_client_wrapper.test.ts index fad839215392f..3f17d18bbe5f7 100644 --- a/x-pack/plugins/security/server/spaces/secure_spaces_client_wrapper.test.ts +++ b/x-pack/plugins/security/server/spaces/secure_spaces_client_wrapper.test.ts @@ -5,21 +5,20 @@ * 2.0. */ -import { httpServerMock } from '../../../../../src/core/server/mocks'; - -import { SecureSpacesClientWrapper } from './secure_spaces_client_wrapper'; +import { deepFreeze } from '@kbn/std'; +import { SavedObjectsErrorHelpers } from 'src/core/server'; +import { httpServerMock } from 'src/core/server/mocks'; +import type { GetAllSpacesPurpose, Space } from '../../../spaces/server'; import { spacesClientMock } from '../../../spaces/server/mocks'; +import type { AuditEvent, AuditLogger } from '../audit'; +import { EventOutcome, SpaceAuditAction } from '../audit'; import { auditServiceMock } from '../audit/index.mock'; -import { deepFreeze } from '@kbn/std'; -import { Space } from '../../../spaces/server'; +import type { AuthorizationServiceSetup } from '../authorization'; import { authorizationMock } from '../authorization/index.mock'; -import { AuthorizationServiceSetup } from '../authorization'; -import { GetAllSpacesPurpose } from '../../../spaces/server'; -import { CheckPrivilegesResponse } from '../authorization/types'; -import { LegacySpacesAuditLogger } from './legacy_audit_logger'; -import { SavedObjectsErrorHelpers } from 'src/core/server'; -import { AuditLogger, AuditEvent, EventOutcome, SpaceAuditAction } from '../audit'; +import type { CheckPrivilegesResponse } from '../authorization/types'; +import type { LegacySpacesAuditLogger } from './legacy_audit_logger'; +import { SecureSpacesClientWrapper } from './secure_spaces_client_wrapper'; interface Opts { securityEnabled?: boolean; diff --git a/x-pack/plugins/security/server/spaces/secure_spaces_client_wrapper.ts b/x-pack/plugins/security/server/spaces/secure_spaces_client_wrapper.ts index b25131e209fcf..7257dc625d4b4 100644 --- a/x-pack/plugins/security/server/spaces/secure_spaces_client_wrapper.ts +++ b/x-pack/plugins/security/server/spaces/secure_spaces_client_wrapper.ts @@ -6,18 +6,21 @@ */ import Boom from '@hapi/boom'; -import { KibanaRequest } from 'src/core/server'; -import { - Space, - ISpacesClient, + +import type { KibanaRequest } from 'src/core/server'; + +import type { GetAllSpacesOptions, GetAllSpacesPurpose, GetSpaceResult, + ISpacesClient, + Space, } from '../../../spaces/server'; -import { LegacySpacesAuditLogger } from './legacy_audit_logger'; -import { AuthorizationServiceSetup } from '../authorization'; -import { AuditLogger, EventOutcome, SpaceAuditAction, spaceAuditEvent } from '../audit'; -import { SecurityPluginSetup } from '..'; +import type { AuditLogger } from '../audit'; +import { EventOutcome, SpaceAuditAction, spaceAuditEvent } from '../audit'; +import type { AuthorizationServiceSetup } from '../authorization'; +import type { SecurityPluginSetup } from '../plugin'; +import type { LegacySpacesAuditLogger } from './legacy_audit_logger'; const PURPOSE_PRIVILEGE_MAP: Record< GetAllSpacesPurpose, diff --git a/x-pack/plugins/security/server/spaces/setup_spaces_client.test.ts b/x-pack/plugins/security/server/spaces/setup_spaces_client.test.ts index b3ee39425cb44..a6849c7ea9a86 100644 --- a/x-pack/plugins/security/server/spaces/setup_spaces_client.test.ts +++ b/x-pack/plugins/security/server/spaces/setup_spaces_client.test.ts @@ -5,10 +5,9 @@ * 2.0. */ -import { coreMock, httpServerMock } from '../../../../../src/core/server/mocks'; +import { coreMock, httpServerMock } from 'src/core/server/mocks'; import { spacesMock } from '../../../spaces/server/mocks'; - import { auditServiceMock } from '../audit/index.mock'; import { authorizationMock } from '../authorization/index.mock'; import { setupSpacesClient } from './setup_spaces_client'; diff --git a/x-pack/plugins/security/server/spaces/setup_spaces_client.ts b/x-pack/plugins/security/server/spaces/setup_spaces_client.ts index 6952117a82b32..2344d3e8c69d6 100644 --- a/x-pack/plugins/security/server/spaces/setup_spaces_client.ts +++ b/x-pack/plugins/security/server/spaces/setup_spaces_client.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { SpacesPluginSetup } from '../../../spaces/server'; -import { AuditServiceSetup } from '../audit'; -import { AuthorizationServiceSetup } from '../authorization'; +import type { SpacesPluginSetup } from '../../../spaces/server'; +import type { AuditServiceSetup } from '../audit'; +import type { AuthorizationServiceSetup } from '../authorization'; import { LegacySpacesAuditLogger } from './legacy_audit_logger'; import { SecureSpacesClientWrapper } from './secure_spaces_client_wrapper'; diff --git a/x-pack/plugins/security/server/types.ts b/x-pack/plugins/security/server/types.ts index 5329b1721f226..1ce8a19d46180 100644 --- a/x-pack/plugins/security/server/types.ts +++ b/x-pack/plugins/security/server/types.ts @@ -6,6 +6,7 @@ */ import type { IRouter, RequestHandlerContext } from 'src/core/server'; + import type { LicensingApiRequestHandlerContext } from '../../licensing/server'; /** diff --git a/x-pack/plugins/security/server/usage_collector/security_usage_collector.test.ts b/x-pack/plugins/security/server/usage_collector/security_usage_collector.test.ts index b1fa04cc4e32b..6a1f6662e796e 100644 --- a/x-pack/plugins/security/server/usage_collector/security_usage_collector.test.ts +++ b/x-pack/plugins/security/server/usage_collector/security_usage_collector.test.ts @@ -5,16 +5,17 @@ * 2.0. */ -import { createConfig, ConfigSchema } from '../config'; +import type { TypeOf } from '@kbn/config-schema'; import { loggingSystemMock } from 'src/core/server/mocks'; -import { TypeOf } from '@kbn/config-schema'; import { - usageCollectionPluginMock, createCollectorFetchContextMock, + usageCollectionPluginMock, } from 'src/plugins/usage_collection/server/mocks'; -import { registerSecurityUsageCollector } from './security_usage_collector'; + +import type { SecurityLicenseFeatures } from '../../common/licensing'; import { licenseMock } from '../../common/licensing/index.mock'; -import { SecurityLicenseFeatures } from '../../common/licensing'; +import { ConfigSchema, createConfig } from '../config'; +import { registerSecurityUsageCollector } from './security_usage_collector'; describe('Security UsageCollector', () => { const createSecurityConfig = (config: TypeOf) => { diff --git a/x-pack/plugins/security/server/usage_collector/security_usage_collector.ts b/x-pack/plugins/security/server/usage_collector/security_usage_collector.ts index fd7be38f2ea36..a59951f5fcfe2 100644 --- a/x-pack/plugins/security/server/usage_collector/security_usage_collector.ts +++ b/x-pack/plugins/security/server/usage_collector/security_usage_collector.ts @@ -5,9 +5,10 @@ * 2.0. */ -import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; -import { ConfigType } from '../config'; -import { SecurityLicense } from '../../common/licensing'; +import type { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; + +import type { SecurityLicense } from '../../common/licensing'; +import type { ConfigType } from '../config'; interface Usage { auditLoggingEnabled: boolean; diff --git a/x-pack/plugins/security_solution/common/search_strategy/timeline/events/details/index.ts b/x-pack/plugins/security_solution/common/search_strategy/timeline/events/details/index.ts index 5d6bc33ec49f8..1f9820f8e5c2b 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/timeline/events/details/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/timeline/events/details/index.ts @@ -16,6 +16,7 @@ export interface TimelineEventsDetailsItem { values?: Maybe; // eslint-disable-next-line @typescript-eslint/no-explicit-any originalValue?: Maybe; + isObjectArray: boolean; } export interface TimelineEventsDetailsStrategyResponse extends IEsSearchResponse { diff --git a/x-pack/plugins/security_solution/cypress/integration/cases/creation.spec.ts b/x-pack/plugins/security_solution/cypress/integration/cases/creation.spec.ts index 64ce6be9ec457..f46feae946242 100644 --- a/x-pack/plugins/security_solution/cypress/integration/cases/creation.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/cases/creation.spec.ts @@ -46,6 +46,7 @@ import { backToCases, createCase, fillCasesMandatoryfields, + filterStatusOpen, } from '../../tasks/create_new_case'; import { loginAndWaitForPageWithoutDateRange } from '../../tasks/login'; @@ -74,6 +75,7 @@ describe('Cases', () => { attachTimeline(this.mycase); createCase(); backToCases(); + filterStatusOpen(); cy.get(ALL_CASES_PAGE_TITLE).should('have.text', 'Cases'); cy.get(ALL_CASES_OPEN_CASES_STATS).should('have.text', 'Open cases1'); diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_rules/custom_query_rule.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_rules/custom_query_rule.spec.ts index ecfa96d59170f..201a3c3a5563e 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_rules/custom_query_rule.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_rules/custom_query_rule.spec.ts @@ -108,6 +108,7 @@ import { } from '../../tasks/create_new_rule'; import { saveEditedRule, waitForKibana } from '../../tasks/edit_rule'; import { loginAndWaitForPageWithoutDateRange } from '../../tasks/login'; +import { activatesRule } from '../../tasks/rule_details'; import { DETECTIONS_URL } from '../../urls/navigation'; @@ -308,6 +309,21 @@ describe('Custom detection rules deletion and edition', () => { reload(); }); + it('Only modifies rule active status on enable/disable', () => { + activatesRule(); + + cy.intercept('GET', `/api/detection_engine/rules?id=`).as('fetchRuleDetails'); + + goToRuleDetails(); + + cy.wait('@fetchRuleDetails').then(({ response }) => { + cy.wrap(response!.statusCode).should('eql', 200); + + cy.wrap(response!.body.max_signals).should('eql', existingRule.maxSignals); + cy.wrap(response!.body.enabled).should('eql', false); + }); + }); + it('Allows a rule to be edited', () => { editFirstRule(); waitForKibana(); @@ -347,8 +363,17 @@ describe('Custom detection rules deletion and edition', () => { goToAboutStepTab(); cy.get(TAGS_CLEAR_BUTTON).click({ force: true }); fillAboutRule(editedRule); + + cy.intercept('GET', '/api/detection_engine/rules?id').as('getRule'); + saveEditedRule(); + cy.wait('@getRule').then(({ response }) => { + cy.wrap(response!.statusCode).should('eql', 200); + // ensure that editing rule does not modify max_signals + cy.wrap(response!.body.max_signals).should('eql', existingRule.maxSignals); + }); + cy.get(RULE_NAME_HEADER).should('have.text', `${editedRule.name}`); cy.get(ABOUT_RULE_DESCRIPTION).should('have.text', editedRule.description); cy.get(ABOUT_DETAILS).within(() => { diff --git a/x-pack/plugins/security_solution/cypress/objects/rule.ts b/x-pack/plugins/security_solution/cypress/objects/rule.ts index dadcb98cade8d..88dcd998fc06d 100644 --- a/x-pack/plugins/security_solution/cypress/objects/rule.ts +++ b/x-pack/plugins/security_solution/cypress/objects/rule.ts @@ -54,6 +54,7 @@ export interface CustomRule { runsEvery: Interval; lookBack: Interval; timeline: CompleteTimeline; + maxSignals: number; } export interface ThresholdRule extends CustomRule { @@ -174,6 +175,7 @@ export const newRule: CustomRule = { runsEvery, lookBack, timeline, + maxSignals: 100, }; export const existingRule: CustomRule = { @@ -192,6 +194,9 @@ export const existingRule: CustomRule = { runsEvery, lookBack, timeline, + // Please do not change, or if you do, needs + // to be any number other than default value + maxSignals: 500, }; export const newOverrideRule: OverrideRule = { @@ -213,6 +218,7 @@ export const newOverrideRule: OverrideRule = { runsEvery, lookBack, timeline, + maxSignals: 100, }; export const newThresholdRule: ThresholdRule = { @@ -232,6 +238,7 @@ export const newThresholdRule: ThresholdRule = { runsEvery, lookBack, timeline, + maxSignals: 100, }; export const machineLearningRule: MachineLearningRule = { @@ -265,6 +272,7 @@ export const eqlRule: CustomRule = { runsEvery, lookBack, timeline, + maxSignals: 100, }; export const eqlSequenceRule: CustomRule = { @@ -285,6 +293,7 @@ export const eqlSequenceRule: CustomRule = { runsEvery, lookBack, timeline, + maxSignals: 100, }; export const newThreatIndicatorRule: ThreatIndicatorRule = { @@ -304,6 +313,7 @@ export const newThreatIndicatorRule: ThreatIndicatorRule = { indicatorMapping: 'agent.id', indicatorIndexField: 'agent.threat', timeline, + maxSignals: 100, }; export const severitiesOverride = ['Low', 'Medium', 'High', 'Critical']; diff --git a/x-pack/plugins/security_solution/cypress/screens/all_cases.ts b/x-pack/plugins/security_solution/cypress/screens/all_cases.ts index e9c5ff89dd8c4..fa6b6add57bac 100644 --- a/x-pack/plugins/security_solution/cypress/screens/all_cases.ts +++ b/x-pack/plugins/security_solution/cypress/screens/all_cases.ts @@ -25,6 +25,8 @@ export const ALL_CASES_NAME = '[data-test-subj="case-details-link"]'; export const ALL_CASES_OPEN_CASES_COUNT = '[data-test-subj="case-status-filter"]'; +export const ALL_CASES_OPEN_FILTER = '[data-test-subj="case-status-filter-open"]'; + export const ALL_CASES_OPEN_CASES_STATS = '[data-test-subj="openStatsHeader"]'; export const ALL_CASES_OPENED_ON = '[data-test-subj="case-table-column-createdAt"]'; diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/rules.ts b/x-pack/plugins/security_solution/cypress/tasks/api_calls/rules.ts index 99f5bd9c20230..4bf5508c19aa9 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/api_calls/rules.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/api_calls/rules.ts @@ -85,6 +85,7 @@ export const createCustomRuleActivated = (rule: CustomRule, ruleId = '1') => language: 'kuery', enabled: true, tags: ['rule1'], + max_signals: 500, }, headers: { 'kbn-xsrf': 'cypress-creds' }, failOnStatusCode: false, diff --git a/x-pack/plugins/security_solution/cypress/tasks/create_new_case.ts b/x-pack/plugins/security_solution/cypress/tasks/create_new_case.ts index e67cee4f38734..ed9174e2a74bb 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/create_new_case.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/create_new_case.ts @@ -11,6 +11,7 @@ import { ServiceNowconnectorOptions, TestCase, } from '../objects/case'; +import { ALL_CASES_OPEN_CASES_COUNT, ALL_CASES_OPEN_FILTER } from '../screens/all_cases'; import { BACK_TO_CASES_BTN, @@ -40,6 +41,11 @@ export const backToCases = () => { cy.get(BACK_TO_CASES_BTN).click({ force: true }); }; +export const filterStatusOpen = () => { + cy.get(ALL_CASES_OPEN_CASES_COUNT).click(); + cy.get(ALL_CASES_OPEN_FILTER).click(); +}; + export const fillCasesMandatoryfields = (newCase: TestCase) => { cy.get(TITLE_INPUT).type(newCase.name, { force: true }); newCase.tags.forEach((tag) => { diff --git a/x-pack/plugins/security_solution/cypress/tasks/rule_details.ts b/x-pack/plugins/security_solution/cypress/tasks/rule_details.ts index 411f326a0ace6..21a2745395419 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/rule_details.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/rule_details.ts @@ -34,11 +34,6 @@ export const activatesRule = () => { }); }; -export const deactivatesRule = () => { - cy.get(RULE_SWITCH).should('be.visible'); - cy.get(RULE_SWITCH).click(); -}; - export const addsException = (exception: Exception) => { cy.get(LOADING_SPINNER).should('exist'); cy.get(LOADING_SPINNER).should('not.exist'); diff --git a/x-pack/plugins/security_solution/public/cases/components/all_cases/actions.tsx b/x-pack/plugins/security_solution/public/cases/components/all_cases/actions.tsx index 66563deae5422..046da5e833bf8 100644 --- a/x-pack/plugins/security_solution/public/cases/components/all_cases/actions.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/all_cases/actions.tsx @@ -13,6 +13,7 @@ import { Case, SubCase } from '../../containers/types'; import { UpdateCase } from '../../containers/use_get_cases'; import { statuses } from '../status'; import * as i18n from './translations'; +import { isIndividual } from './helpers'; interface GetActions { caseStatus: string; @@ -20,16 +21,14 @@ interface GetActions { deleteCaseOnClick: (deleteCase: Case) => void; } -const hasSubCases = (subCases: SubCase[] | null | undefined) => - subCases != null && subCases?.length > 0; - export const getActions = ({ caseStatus, dispatchUpdate, deleteCaseOnClick, }: GetActions): Array> => { const openCaseAction = { - available: (item: Case) => caseStatus !== CaseStatuses.open && !hasSubCases(item.subCases), + available: (item: Case | SubCase) => item.status !== CaseStatuses.open, + enabled: (item: Case | SubCase) => isIndividual(item), description: statuses[CaseStatuses.open].actions.single.title, icon: statuses[CaseStatuses.open].icon, name: statuses[CaseStatuses.open].actions.single.title, @@ -45,8 +44,8 @@ export const getActions = ({ }; const makeInProgressAction = { - available: (item: Case) => - caseStatus !== CaseStatuses['in-progress'] && !hasSubCases(item.subCases), + available: (item: Case) => item.status !== CaseStatuses['in-progress'], + enabled: (item: Case | SubCase) => isIndividual(item), description: statuses[CaseStatuses['in-progress']].actions.single.title, icon: statuses[CaseStatuses['in-progress']].icon, name: statuses[CaseStatuses['in-progress']].actions.single.title, @@ -62,7 +61,8 @@ export const getActions = ({ }; const closeCaseAction = { - available: (item: Case) => caseStatus !== CaseStatuses.closed && !hasSubCases(item.subCases), + available: (item: Case | SubCase) => item.status !== CaseStatuses.closed, + enabled: (item: Case | SubCase) => isIndividual(item), description: statuses[CaseStatuses.closed].actions.single.title, icon: statuses[CaseStatuses.closed].icon, name: statuses[CaseStatuses.closed].actions.single.title, @@ -78,6 +78,9 @@ export const getActions = ({ }; return [ + openCaseAction, + makeInProgressAction, + closeCaseAction, { description: i18n.DELETE_CASE, icon: 'trash', @@ -86,8 +89,5 @@ export const getActions = ({ type: 'icon', 'data-test-subj': 'action-delete', }, - openCaseAction, - makeInProgressAction, - closeCaseAction, ]; }; diff --git a/x-pack/plugins/security_solution/public/cases/components/all_cases/columns.tsx b/x-pack/plugins/security_solution/public/cases/components/all_cases/columns.tsx index 47db362c7b4bf..e69f85c862962 100644 --- a/x-pack/plugins/security_solution/public/cases/components/all_cases/columns.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/all_cases/columns.tsx @@ -19,7 +19,7 @@ import { RIGHT_ALIGNMENT } from '@elastic/eui/lib/services'; import styled from 'styled-components'; import { DefaultItemIconButtonAction } from '@elastic/eui/src/components/basic_table/action_types'; -import { CaseStatuses } from '../../../../../case/common/api'; +import { CaseStatuses, CaseType } from '../../../../../case/common/api'; import { getEmptyTagValue } from '../../../common/components/empty_value'; import { Case, SubCase } from '../../containers/types'; import { FormattedRelativePreferenceDate } from '../../../common/components/formatted_date'; @@ -204,7 +204,7 @@ export const getCasesColumns = ( name: i18n.STATUS, render: (theCase: Case) => { if (theCase?.subCases == null || theCase.subCases.length === 0) { - if (theCase.status == null) { + if (theCase.status == null || theCase.type === CaseType.collection) { return getEmptyTagValue(); } return ; diff --git a/x-pack/plugins/security_solution/public/cases/components/all_cases/helpers.ts b/x-pack/plugins/security_solution/public/cases/components/all_cases/helpers.ts index 1ab36d3c67225..519be95fcdfef 100644 --- a/x-pack/plugins/security_solution/public/cases/components/all_cases/helpers.ts +++ b/x-pack/plugins/security_solution/public/cases/components/all_cases/helpers.ts @@ -6,14 +6,24 @@ */ import { filter } from 'lodash/fp'; -import { AssociationType, CaseStatuses } from '../../../../../case/common/api'; +import { AssociationType, CaseStatuses, CaseType } from '../../../../../case/common/api'; import { Case, SubCase } from '../../containers/types'; import { statuses } from '../status'; +export const isSelectedCasesIncludeCollections = (selectedCases: Case[]) => + selectedCases.length > 0 && + selectedCases.some((caseObj: Case) => caseObj.type === CaseType.collection); + export const isSubCase = (theCase: Case | SubCase): theCase is SubCase => (theCase as SubCase).caseParentId !== undefined && (theCase as SubCase).associationType === AssociationType.subCase; +export const isCollection = (theCase: Case | SubCase | null | undefined) => + theCase != null && (theCase as Case).type === CaseType.collection; + +export const isIndividual = (theCase: Case | SubCase | null | undefined) => + theCase != null && (theCase as Case).type === CaseType.individual; + export const getSubCasesStatusCountsBadges = ( subCases: SubCase[] ): Array<{ name: CaseStatuses; color: string; count: number }> => { diff --git a/x-pack/plugins/security_solution/public/cases/components/all_cases/index.test.tsx b/x-pack/plugins/security_solution/public/cases/components/all_cases/index.test.tsx index a145bdf117813..9654681ce8e32 100644 --- a/x-pack/plugins/security_solution/public/cases/components/all_cases/index.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/all_cases/index.test.tsx @@ -24,6 +24,7 @@ import { useUpdateCases } from '../../containers/use_bulk_update_case'; import { useGetActionLicense } from '../../containers/use_get_action_license'; import { getCasesColumns } from './columns'; import { AllCases } from '.'; +import { StatusAll } from '../status'; jest.mock('../../containers/use_bulk_update_case'); jest.mock('../../containers/use_delete_cases'); @@ -111,6 +112,11 @@ describe('AllCases', () => { }); it('should render AllCases', async () => { + useGetCasesMock.mockReturnValue({ + ...defaultGetCases, + filterOptions: { ...defaultGetCases.filterOptions, status: CaseStatuses.open }, + }); + const wrapper = mount( @@ -144,6 +150,11 @@ describe('AllCases', () => { }); it('should render the stats', async () => { + useGetCasesMock.mockReturnValue({ + ...defaultGetCases, + filterOptions: { ...defaultGetCases.filterOptions, status: CaseStatuses.closed }, + }); + const wrapper = mount( @@ -202,6 +213,7 @@ describe('AllCases', () => { it('should render empty fields', async () => { useGetCasesMock.mockReturnValue({ ...defaultGetCases, + filterOptions: { ...defaultGetCases.filterOptions, status: CaseStatuses.open }, data: { ...defaultGetCases.data, cases: [ @@ -240,6 +252,78 @@ describe('AllCases', () => { }); }); + it('should render correct actions for case (with type individual and filter status open)', async () => { + useGetCasesMock.mockReturnValue({ + ...defaultGetCases, + filterOptions: { ...defaultGetCases.filterOptions, status: CaseStatuses.open }, + }); + const wrapper = mount( + + + + ); + wrapper.find('[data-test-subj="euiCollapsedItemActionsButton"]').first().simulate('click'); + await waitFor(() => { + expect(wrapper.find('[data-test-subj="action-open"]').exists()).toBeFalsy(); + expect( + wrapper.find('[data-test-subj="action-in-progress"]').first().props().disabled + ).toBeFalsy(); + expect(wrapper.find('[data-test-subj="action-close"]').first().props().disabled).toBeFalsy(); + expect(wrapper.find('[data-test-subj="action-delete"]').first().props().disabled).toBeFalsy(); + }); + }); + + it('should enable correct actions for sub cases', async () => { + useGetCasesMock.mockReturnValue({ + ...defaultGetCases, + data: { + ...defaultGetCases.data, + cases: [ + { + ...defaultGetCases.data.cases[0], + id: 'my-case-with-subcases', + createdAt: null, + createdBy: null, + status: null, + subCases: [ + { + id: 'sub-case-id', + }, + ], + tags: null, + title: null, + totalComment: null, + totalAlerts: null, + type: CaseType.collection, + }, + ], + }, + }); + const wrapper = mount( + + + + ); + await waitFor(() => { + wrapper + .find( + '[data-test-subj="sub-cases-table-my-case-with-subcases"] [data-test-subj="euiCollapsedItemActionsButton"]' + ) + .last() + .simulate('click'); + expect(wrapper.find('[data-test-subj="action-open"]').first().props().disabled).toEqual(true); + expect( + wrapper.find('[data-test-subj="action-in-progress"]').first().props().disabled + ).toEqual(true); + expect(wrapper.find('[data-test-subj="action-close"]').first().props().disabled).toEqual( + true + ); + expect(wrapper.find('[data-test-subj="action-delete"]').first().props().disabled).toEqual( + false + ); + }); + }); + it('should not render case link or actions on modal=true', async () => { const wrapper = mount( @@ -297,6 +381,15 @@ describe('AllCases', () => { it('opens case when row action icon clicked', async () => { useGetCasesMock.mockReturnValue({ ...defaultGetCases, + data: { + ...defaultGetCases.data, + cases: [ + { + ...defaultGetCases.data.cases[0], + status: CaseStatuses.closed, + }, + ], + }, filterOptions: { ...defaultGetCases.filterOptions, status: CaseStatuses.closed }, }); @@ -342,6 +435,7 @@ describe('AllCases', () => { it('Bulk delete', async () => { useGetCasesMock.mockReturnValue({ ...defaultGetCases, + filterOptions: { ...defaultGetCases.filterOptions, status: CaseStatuses.closed }, selectedCases: useGetCasesMockState.data.cases, }); @@ -377,9 +471,78 @@ describe('AllCases', () => { }); }); + it('Renders only bulk delete on status all', async () => { + useGetCasesMock.mockReturnValue({ + ...defaultGetCases, + filterOptions: { ...defaultGetCases.filterOptions, status: StatusAll }, + selectedCases: [...useGetCasesMockState.data.cases], + }); + + const wrapper = mount( + + + + ); + await waitFor(() => { + wrapper.find('[data-test-subj="case-table-bulk-actions"] button').first().simulate('click'); + expect(wrapper.find('[data-test-subj="cases-bulk-open-button"]').exists()).toEqual(false); + expect(wrapper.find('[data-test-subj="cases-bulk-in-progress-button"]').exists()).toEqual( + false + ); + expect(wrapper.find('[data-test-subj="cases-bulk-close-button"]').exists()).toEqual(false); + expect( + wrapper.find('[data-test-subj="cases-bulk-delete-button"]').first().props().disabled + ).toEqual(false); + }); + }); + + it('Renders correct bulk actoins for case collection when filter status is set to all - enable only bulk delete if any collection is selected', async () => { + useGetCasesMock.mockReturnValue({ + ...defaultGetCases, + filterOptions: { ...defaultGetCases.filterOptions, status: CaseStatuses.open }, + selectedCases: [ + ...useGetCasesMockState.data.cases, + { + ...useGetCasesMockState.data.cases[0], + type: CaseType.collection, + }, + ], + }); + + useDeleteCasesMock + .mockReturnValueOnce({ + ...defaultDeleteCases, + isDisplayConfirmDeleteModal: false, + }) + .mockReturnValue({ + ...defaultDeleteCases, + isDisplayConfirmDeleteModal: true, + }); + + const wrapper = mount( + + + + ); + await waitFor(() => { + wrapper.find('[data-test-subj="case-table-bulk-actions"] button').first().simulate('click'); + expect(wrapper.find('[data-test-subj="cases-bulk-open-button"]').exists()).toEqual(false); + expect( + wrapper.find('[data-test-subj="cases-bulk-in-progress-button"]').first().props().disabled + ).toEqual(true); + expect( + wrapper.find('[data-test-subj="cases-bulk-close-button"]').first().props().disabled + ).toEqual(true); + expect( + wrapper.find('[data-test-subj="cases-bulk-delete-button"]').first().props().disabled + ).toEqual(false); + }); + }); + it('Bulk close status update', async () => { useGetCasesMock.mockReturnValue({ ...defaultGetCases, + filterOptions: { ...defaultGetCases.filterOptions, status: CaseStatuses.open }, selectedCases: useGetCasesMockState.data.cases, }); @@ -420,6 +583,7 @@ describe('AllCases', () => { it('Bulk in-progress status update', async () => { useGetCasesMock.mockReturnValue({ ...defaultGetCases, + filterOptions: { ...defaultGetCases.filterOptions, status: CaseStatuses.open }, selectedCases: useGetCasesMockState.data.cases, }); diff --git a/x-pack/plugins/security_solution/public/cases/components/all_cases/index.tsx b/x-pack/plugins/security_solution/public/cases/components/all_cases/index.tsx index 56dcf3bc28757..5f0e72564f60e 100644 --- a/x-pack/plugins/security_solution/public/cases/components/all_cases/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/all_cases/index.tsx @@ -54,7 +54,9 @@ import { SecurityPageName } from '../../../app/types'; import { useKibana } from '../../../common/lib/kibana'; import { APP_ID } from '../../../../common/constants'; import { Stats } from '../status'; +import { SELECTABLE_MESSAGE_COLLECTIONS } from '../../translations'; import { getExpandedRowMap } from './expanded_row'; +import { isSelectedCasesIncludeCollections } from './helpers'; const Div = styled.div` margin-top: ${({ theme }) => theme.eui.paddingSizes.m}; @@ -268,10 +270,17 @@ export const AllCases = React.memo( deleteCasesAction: toggleBulkDeleteModal, selectedCaseIds, updateCaseStatus: handleUpdateCaseStatus, + includeCollections: isSelectedCasesIncludeCollections(selectedCases), })} /> ), - [selectedCaseIds, filterOptions.status, toggleBulkDeleteModal, handleUpdateCaseStatus] + [ + selectedCases, + selectedCaseIds, + filterOptions.status, + toggleBulkDeleteModal, + handleUpdateCaseStatus, + ] ); const handleDispatchUpdate = useCallback( (args: Omit) => { @@ -379,9 +388,8 @@ export const AllCases = React.memo( const euiBasicTableSelectionProps = useMemo>( () => ({ - selectable: (theCase) => isEmpty(theCase.subCases), onSelectionChange: setSelectedCases, - selectableMessage: (selectable) => (!selectable ? i18n.SELECTABLE_MESSAGE_COLLECTIONS : ''), + selectableMessage: (selectable) => (!selectable ? SELECTABLE_MESSAGE_COLLECTIONS : ''), }), [setSelectedCases] ); @@ -410,6 +418,8 @@ export const AllCases = React.memo( [isModal, onRowClick] ); + const enableBuckActions = userCanCrud && !isModal; + return ( <> {!isEmpty(actionsErrors) && ( @@ -506,10 +516,12 @@ export const AllCases = React.memo( {!isModal && ( - - {i18n.SHOWING_SELECTED_CASES(selectedCases.length)} - - {userCanCrud && ( + {enableBuckActions && ( + + {i18n.SHOWING_SELECTED_CASES(selectedCases.length)} + + )} + {enableBuckActions && ( ( ( onChange={tableOnChangeCallback} pagination={memoizedPagination} rowProps={tableRowProps} - selection={userCanCrud && !isModal ? euiBasicTableSelectionProps : undefined} + selection={enableBuckActions ? euiBasicTableSelectionProps : undefined} sorting={sorting} className={classnames({ isModal })} /> diff --git a/x-pack/plugins/security_solution/public/cases/components/all_cases/status_filter.test.tsx b/x-pack/plugins/security_solution/public/cases/components/all_cases/status_filter.test.tsx index 11d53b6609e74..9d5b36515182d 100644 --- a/x-pack/plugins/security_solution/public/cases/components/all_cases/status_filter.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/all_cases/status_filter.test.tsx @@ -11,8 +11,10 @@ import { waitFor } from '@testing-library/react'; import { CaseStatuses } from '../../../../../case/common/api'; import { StatusFilter } from './status_filter'; +import { StatusAll } from '../status'; const stats = { + [StatusAll]: 0, [CaseStatuses.open]: 2, [CaseStatuses['in-progress']]: 5, [CaseStatuses.closed]: 7, diff --git a/x-pack/plugins/security_solution/public/cases/components/all_cases/status_filter.tsx b/x-pack/plugins/security_solution/public/cases/components/all_cases/status_filter.tsx index 41997d6f38421..34186a201cc05 100644 --- a/x-pack/plugins/security_solution/public/cases/components/all_cases/status_filter.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/all_cases/status_filter.tsx @@ -7,14 +7,13 @@ import React, { memo } from 'react'; import { EuiSuperSelect, EuiSuperSelectOption, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { CaseStatuses } from '../../../../../case/common/api'; -import { Status, statuses } from '../status'; +import { Status, statuses, StatusAll, CaseStatusWithAllStatus } from '../status'; interface Props { - stats: Record; - selectedStatus: CaseStatuses; - onStatusChanged: (status: CaseStatuses) => void; - disabledStatuses?: CaseStatuses[]; + stats: Record; + selectedStatus: CaseStatusWithAllStatus; + onStatusChanged: (status: CaseStatusWithAllStatus) => void; + disabledStatuses?: CaseStatusWithAllStatus[]; } const StatusFilterComponent: React.FC = ({ @@ -23,15 +22,18 @@ const StatusFilterComponent: React.FC = ({ onStatusChanged, disabledStatuses = [], }) => { - const caseStatuses = Object.keys(statuses) as CaseStatuses[]; - const options: Array> = caseStatuses.map((status) => ({ + const caseStatuses = Object.keys(statuses) as CaseStatusWithAllStatus[]; + const options: Array> = [ + StatusAll, + ...caseStatuses, + ].map((status) => ({ value: status, inputDisplay: ( - {` (${stats[status]})`} + {status !== StatusAll && {` (${stats[status]})`}} ), disabled: disabledStatuses.includes(status), diff --git a/x-pack/plugins/security_solution/public/cases/components/all_cases/table_filters.tsx b/x-pack/plugins/security_solution/public/cases/components/all_cases/table_filters.tsx index 61bbbac5a1e84..84b032489f326 100644 --- a/x-pack/plugins/security_solution/public/cases/components/all_cases/table_filters.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/all_cases/table_filters.tsx @@ -15,6 +15,7 @@ import { FilterOptions } from '../../containers/types'; import { useGetTags } from '../../containers/use_get_tags'; import { useGetReporters } from '../../containers/use_get_reporters'; import { FilterPopover } from '../filter_popover'; +import { CaseStatusWithAllStatus, StatusAll } from '../status'; import { StatusFilter } from './status_filter'; import * as i18n from './translations'; @@ -42,7 +43,12 @@ const StatusFilterWrapper = styled(EuiFlexItem)` * @param onFilterChanged change listener to be notified on filter changes */ -const defaultInitial = { search: '', reporters: [], status: CaseStatuses.open, tags: [] }; +const defaultInitial = { + search: '', + reporters: [], + status: StatusAll, + tags: [], +}; const CasesTableFiltersComponent = ({ countClosedCases, @@ -126,7 +132,7 @@ const CasesTableFiltersComponent = ({ ); const onStatusChanged = useCallback( - (status: CaseStatuses) => { + (status: CaseStatusWithAllStatus) => { onFilterChanged({ status }); }, [onFilterChanged] @@ -134,6 +140,7 @@ const CasesTableFiltersComponent = ({ const stats = useMemo( () => ({ + [StatusAll]: null, [CaseStatuses.open]: countOpenCases ?? 0, [CaseStatuses['in-progress']]: countInProgressCases ?? 0, [CaseStatuses.closed]: countClosedCases ?? 0, diff --git a/x-pack/plugins/security_solution/public/cases/components/bulk_actions/index.tsx b/x-pack/plugins/security_solution/public/cases/components/bulk_actions/index.tsx index ec3b391cdcbfe..a6d5a0679df37 100644 --- a/x-pack/plugins/security_solution/public/cases/components/bulk_actions/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/bulk_actions/index.tsx @@ -9,15 +9,16 @@ import React from 'react'; import { EuiContextMenuItem } from '@elastic/eui'; import { CaseStatuses } from '../../../../../case/common/api'; -import { statuses } from '../status'; +import { statuses, CaseStatusWithAllStatus } from '../status'; import * as i18n from './translations'; interface GetBulkItems { - caseStatus: CaseStatuses; + caseStatus: CaseStatusWithAllStatus; closePopover: () => void; deleteCasesAction: (cases: string[]) => void; selectedCaseIds: string[]; updateCaseStatus: (status: string) => void; + includeCollections: boolean; } export const getBulkItems = ({ @@ -26,13 +27,14 @@ export const getBulkItems = ({ deleteCasesAction, selectedCaseIds, updateCaseStatus, + includeCollections, }: GetBulkItems) => { let statusMenuItems: JSX.Element[] = []; const openMenuItem = ( { @@ -47,7 +49,7 @@ export const getBulkItems = ({ const inProgressMenuItem = ( { @@ -62,7 +64,7 @@ export const getBulkItems = ({ const closeMenuItem = ( { diff --git a/x-pack/plugins/security_solution/public/cases/components/case_action_bar/status_context_menu.tsx b/x-pack/plugins/security_solution/public/cases/components/case_action_bar/status_context_menu.tsx index e0cdf9dc6d9eb..7f9ffbd8dc01d 100644 --- a/x-pack/plugins/security_solution/public/cases/components/case_action_bar/status_context_menu.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/case_action_bar/status_context_menu.tsx @@ -8,8 +8,8 @@ import React, { memo, useCallback, useMemo, useState } from 'react'; import { memoize } from 'lodash/fp'; import { EuiPopover, EuiContextMenuPanel, EuiContextMenuItem } from '@elastic/eui'; -import { CaseStatuses } from '../../../../../case/common/api'; -import { Status, statuses } from '../status'; +import { caseStatuses, CaseStatuses } from '../../../../../case/common/api'; +import { Status } from '../status'; interface Props { currentStatus: CaseStatuses; @@ -34,7 +34,6 @@ const StatusContextMenuComponent: React.FC = ({ currentStatus, onStatusCh [closePopover, onStatusChanged] ); - const caseStatuses = Object.keys(statuses) as CaseStatuses[]; const panelItems = caseStatuses.map((status: CaseStatuses) => ( ( caseFields={caseData.connector.fields} connectors={connectors} disabled={!userCanCrud} + hideConnectorServiceNowSir={ + subCaseId != null || caseData.type === CaseType.collection + } isLoading={isLoadingConnectors || (isLoading && updateKey === 'connector')} onSubmit={onSubmitConnector} selectedConnector={caseData.connector.id} diff --git a/x-pack/plugins/security_solution/public/cases/components/configure_cases/connectors_dropdown.test.tsx b/x-pack/plugins/security_solution/public/cases/components/configure_cases/connectors_dropdown.test.tsx index e8c074faed32e..1f1876756773d 100644 --- a/x-pack/plugins/security_solution/public/cases/components/configure_cases/connectors_dropdown.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/configure_cases/connectors_dropdown.test.tsx @@ -34,22 +34,122 @@ describe('ConnectorsDropdown', () => { test('it formats the connectors correctly', () => { const selectProps = wrapper.find(EuiSuperSelect).props(); - expect(selectProps.options).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - value: 'none', - 'data-test-subj': 'dropdown-connector-no-connector', - }), - expect.objectContaining({ - value: 'servicenow-1', - 'data-test-subj': 'dropdown-connector-servicenow-1', - }), - expect.objectContaining({ - value: 'resilient-2', - 'data-test-subj': 'dropdown-connector-resilient-2', - }), - ]) - ); + expect(selectProps.options).toMatchInlineSnapshot(` + Array [ + Object { + "data-test-subj": "dropdown-connector-no-connector", + "inputDisplay": + + + + + + No connector selected + + + , + "value": "none", + }, + Object { + "data-test-subj": "dropdown-connector-servicenow-1", + "inputDisplay": + + + + + + My Connector + + + , + "value": "servicenow-1", + }, + Object { + "data-test-subj": "dropdown-connector-resilient-2", + "inputDisplay": + + + + + + My Connector 2 + + + , + "value": "resilient-2", + }, + Object { + "data-test-subj": "dropdown-connector-jira-1", + "inputDisplay": + + + + + + Jira + + + , + "value": "jira-1", + }, + Object { + "data-test-subj": "dropdown-connector-servicenow-sir", + "inputDisplay": + + + + + + My Connector SIR + + + , + "value": "servicenow-sir", + }, + ] + `); }); test('it disables the dropdown', () => { @@ -79,4 +179,25 @@ describe('ConnectorsDropdown', () => { expect(newWrapper.find('button span:not([data-euiicon-type])').text()).toEqual('My Connector'); }); + + test('if the props hideConnectorServiceNowSir is true, the connector should not be part of the list of options ', () => { + const newWrapper = mount( + , + { + wrappingComponent: TestProviders, + } + ); + const selectProps = newWrapper.find(EuiSuperSelect).props(); + const options = selectProps.options as Array<{ 'data-test-subj': string }>; + expect( + options.some((o) => o['data-test-subj'] === 'dropdown-connector-servicenow-1') + ).toBeTruthy(); + expect( + options.some((o) => o['data-test-subj'] === 'dropdown-connector-servicenow-sir') + ).toBeFalsy(); + }); }); diff --git a/x-pack/plugins/security_solution/public/cases/components/configure_cases/connectors_dropdown.tsx b/x-pack/plugins/security_solution/public/cases/components/configure_cases/connectors_dropdown.tsx index ab4b9fcfe7093..b8eacb9dfdd91 100644 --- a/x-pack/plugins/security_solution/public/cases/components/configure_cases/connectors_dropdown.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/configure_cases/connectors_dropdown.tsx @@ -9,6 +9,7 @@ import React, { useMemo } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiSuperSelect } from '@elastic/eui'; import styled from 'styled-components'; +import { ConnectorTypes } from '../../../../../case/common/api'; import { ActionConnector } from '../../containers/configure/types'; import { connectorsConfiguration } from '../connectors'; import * as i18n from './translations'; @@ -20,6 +21,7 @@ export interface Props { onChange: (id: string) => void; selectedConnector: string; appendAddConnectorButton?: boolean; + hideConnectorServiceNowSir?: boolean; } const ICON_SIZE = 'm'; @@ -61,29 +63,36 @@ const ConnectorsDropdownComponent: React.FC = ({ onChange, selectedConnector, appendAddConnectorButton = false, + hideConnectorServiceNowSir = false, }) => { const connectorsAsOptions = useMemo(() => { const connectorsFormatted = connectors.reduce( - (acc, connector) => [ - ...acc, - { - value: connector.id, - inputDisplay: ( - - - - - - {connector.name} - - - ), - 'data-test-subj': `dropdown-connector-${connector.id}`, - }, - ], + (acc, connector) => { + if (hideConnectorServiceNowSir && connector.actionTypeId === ConnectorTypes.serviceNowSIR) { + return acc; + } + + return [ + ...acc, + { + value: connector.id, + inputDisplay: ( + + + + + + {connector.name} + + + ), + 'data-test-subj': `dropdown-connector-${connector.id}`, + }, + ]; + }, [noConnectorOption] ); diff --git a/x-pack/plugins/security_solution/public/cases/components/connector_selector/form.tsx b/x-pack/plugins/security_solution/public/cases/components/connector_selector/form.tsx index d5f5530acde9b..586a7c19cc532 100644 --- a/x-pack/plugins/security_solution/public/cases/components/connector_selector/form.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/connector_selector/form.tsx @@ -22,6 +22,7 @@ interface ConnectorSelectorProps { isEdit: boolean; isLoading: boolean; handleChange?: (newValue: string) => void; + hideConnectorServiceNowSir?: boolean; } export const ConnectorSelector = ({ connectors, @@ -32,6 +33,7 @@ export const ConnectorSelector = ({ isEdit = true, isLoading = false, handleChange, + hideConnectorServiceNowSir = false, }: ConnectorSelectorProps) => { const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field); const onChange = useCallback( @@ -58,6 +60,7 @@ export const ConnectorSelector = ({ ` - margin-top: ${theme.eui?.euiSize ?? '16px'}; + padding: ${theme.eui?.euiSizeS ?? '8px'} ${theme.eui?.euiSizeL ?? '24px'} ${ + theme.eui?.euiSizeL ?? '24px' + } ${theme.eui?.euiSizeL ?? '24px'}; `} `; const defaultAlertComment = { type: CommentType.generatedAlert, - alerts: `[{{#context.alerts}}{"_id": "{{_id}}", "_index": "{{_index}}", "ruleId": "{{rule.id}}", "ruleName": "{{rule.name}}"}__SEPARATOR__{{/context.alerts}}]`, + alerts: `[{{#context.alerts}}{"_id": "{{_id}}", "_index": "{{_index}}", "ruleId": "{{signal.rule.id}}", "ruleName": "{{signal.rule.name}}"}__SEPARATOR__{{/context.alerts}}]`, }; const CaseParamsFields: React.FunctionComponent> = ({ @@ -90,12 +92,13 @@ const CaseParamsFields: React.FunctionComponent - - - - - + + + + +

{i18n.CASE_CONNECTOR_CALL_OUT_MSG}

+
+
); }; diff --git a/x-pack/plugins/security_solution/public/cases/components/connectors/case/existing_case.tsx b/x-pack/plugins/security_solution/public/cases/components/connectors/case/existing_case.tsx index 5f564d7b62464..c1013718d5756 100644 --- a/x-pack/plugins/security_solution/public/cases/components/connectors/case/existing_case.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/connectors/case/existing_case.tsx @@ -5,22 +5,15 @@ * 2.0. */ -import { - EuiButton, - EuiButtonIcon, - EuiCallOut, - EuiTextColor, - EuiLoadingSpinner, -} from '@elastic/eui'; -import { isEmpty } from 'lodash'; -import React, { memo, useEffect, useCallback, useState } from 'react'; +import React, { memo, useMemo, useCallback } from 'react'; import { CaseType } from '../../../../../../case/common/api'; -import { Case } from '../../../containers/types'; -import { useDeleteCases } from '../../../containers/use_delete_cases'; -import { useGetCase } from '../../../containers/use_get_case'; -import { ConfirmDeleteCaseModal } from '../../confirm_delete_case'; +import { + useGetCases, + DEFAULT_QUERY_PARAMS, + DEFAULT_FILTER_OPTIONS, +} from '../../../containers/use_get_cases'; import { useCreateCaseModal } from '../../use_create_case_modal'; -import * as i18n from './translations'; +import { CasesDropdown, ADD_CASE_BUTTON_ID } from './cases_dropdown'; interface ExistingCaseProps { selectedCase: string | null; @@ -28,76 +21,53 @@ interface ExistingCaseProps { } const ExistingCaseComponent: React.FC = ({ onCaseChanged, selectedCase }) => { - const { data, isLoading, isError } = useGetCase(selectedCase ?? ''); - const [createdCase, setCreatedCase] = useState(null); + const { data: cases, loading: isLoadingCases, refetchCases } = useGetCases(DEFAULT_QUERY_PARAMS, { + ...DEFAULT_FILTER_OPTIONS, + onlyCollectionType: true, + }); const onCaseCreated = useCallback( - (newCase: Case) => { + (newCase) => { + refetchCases(); onCaseChanged(newCase.id); - setCreatedCase(newCase); }, - [onCaseChanged] + [onCaseChanged, refetchCases] ); - const { modal, openModal } = useCreateCaseModal({ caseType: CaseType.collection, onCaseCreated }); + const { modal, openModal } = useCreateCaseModal({ + onCaseCreated, + caseType: CaseType.collection, + // FUTURE DEVELOPER + // We are making the assumption that this component is only used in rules creation + // that's why we want to hide ServiceNow SIR + hideConnectorServiceNowSir: true, + }); - // Delete case - const { - dispatchResetIsDeleted, - handleOnDeleteConfirm, - handleToggleModal, - isLoading: isDeleting, - isDeleted, - isDisplayConfirmDeleteModal, - } = useDeleteCases(); + const onChange = useCallback( + (id: string) => { + if (id === ADD_CASE_BUTTON_ID) { + openModal(); + return; + } - useEffect(() => { - if (isDeleted) { - setCreatedCase(null); - onCaseChanged(''); - dispatchResetIsDeleted(); - } - // onCaseChanged and/or dispatchResetIsDeleted causes re-renders - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isDeleted]); + onCaseChanged(id); + }, + [onCaseChanged, openModal] + ); - useEffect(() => { - if (!isLoading && !isError && data != null) { - setCreatedCase(data); - onCaseChanged(data.id); - } - // onCaseChanged causes re-renders - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [data, isLoading, isError]); + const isCasesLoading = useMemo( + () => isLoadingCases.includes('cases') || isLoadingCases.includes('caseUpdate'), + [isLoadingCases] + ); return ( <> - {createdCase == null && isEmpty(selectedCase) && ( - - {i18n.CREATE_CASE} - - )} - {createdCase == null && isLoading && } - {createdCase != null && !isLoading && ( - <> - - - {createdCase.title}{' '} - {!isDeleting && ( - - )} - {isDeleting && } - - - - - )} + {modal} ); diff --git a/x-pack/plugins/security_solution/public/cases/components/connectors/case/translations.ts b/x-pack/plugins/security_solution/public/cases/components/connectors/case/translations.ts index 731e94a17d923..6ce5316d0eb88 100644 --- a/x-pack/plugins/security_solution/public/cases/components/connectors/case/translations.ts +++ b/x-pack/plugins/security_solution/public/cases/components/connectors/case/translations.ts @@ -40,7 +40,7 @@ export const CASE_CONNECTOR_COMMENT_REQUIRED = i18n.translate( export const CASE_CONNECTOR_CASES_DROPDOWN_ROW_LABEL = i18n.translate( 'xpack.securitySolution.case.components.connectors.case.casesDropdownRowLabel', { - defaultMessage: 'Case', + defaultMessage: 'Case allowing sub-cases', } ); @@ -72,10 +72,18 @@ export const CASE_CONNECTOR_CASE_REQUIRED = i18n.translate( } ); -export const CASE_CONNECTOR_CALL_OUT_INFO = i18n.translate( - 'xpack.securitySolution.case.components.connectors.case.callOutInfo', +export const CASE_CONNECTOR_CALL_OUT_TITLE = i18n.translate( + 'xpack.securitySolution.case.components.connectors.case.callOutTitle', { - defaultMessage: 'All alerts after rule creation will be appended to the selected case.', + defaultMessage: 'Generated alerts will be attached to sub-cases', + } +); + +export const CASE_CONNECTOR_CALL_OUT_MSG = i18n.translate( + 'xpack.securitySolution.case.components.connectors.case.callOutMsg', + { + defaultMessage: + 'A case can contain multiple sub-cases to allow grouping of generated alerts. Sub-cases will give more granular control over the status of these generated alerts and prevents having too many alerts attached to one case.', } ); diff --git a/x-pack/plugins/security_solution/public/cases/components/create/connector.tsx b/x-pack/plugins/security_solution/public/cases/components/create/connector.tsx index 5e7972aec9d4b..bfe0d8dd78e28 100644 --- a/x-pack/plugins/security_solution/public/cases/components/create/connector.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/create/connector.tsx @@ -8,6 +8,7 @@ import React, { memo, useCallback } from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { ConnectorTypes } from '../../../../../case/common/api'; import { UseField, useFormData, FieldHook, useFormContext } from '../../../shared_imports'; import { useConnectors } from '../../containers/configure/use_connectors'; import { ConnectorSelector } from '../connector_selector/form'; @@ -18,19 +19,32 @@ import { FormProps } from './schema'; interface Props { isLoading: boolean; + hideConnectorServiceNowSir?: boolean; } interface ConnectorsFieldProps { connectors: ActionConnector[]; field: FieldHook; isEdit: boolean; + hideConnectorServiceNowSir?: boolean; } -const ConnectorFields = ({ connectors, isEdit, field }: ConnectorsFieldProps) => { +const ConnectorFields = ({ + connectors, + isEdit, + field, + hideConnectorServiceNowSir = false, +}: ConnectorsFieldProps) => { const [{ connectorId }] = useFormData({ watch: ['connectorId'] }); const { setValue } = field; - const connector = getConnectorById(connectorId, connectors) ?? null; - + let connector = getConnectorById(connectorId, connectors) ?? null; + if ( + connector && + hideConnectorServiceNowSir && + connector.actionTypeId === ConnectorTypes.serviceNowSIR + ) { + connector = null; + } return ( ); }; -const ConnectorComponent: React.FC = ({ isLoading }) => { +const ConnectorComponent: React.FC = ({ hideConnectorServiceNowSir = false, isLoading }) => { const { getFields } = useFormContext(); const { loading: isLoadingConnectors, connectors } = useConnectors(); const handleConnectorChange = useCallback( @@ -61,6 +75,7 @@ const ConnectorComponent: React.FC = ({ isLoading }) => { componentProps={{ connectors, handleChange: handleConnectorChange, + hideConnectorServiceNowSir, dataTestSubj: 'caseConnectors', disabled: isLoading || isLoadingConnectors, idAria: 'caseConnectors', @@ -74,6 +89,7 @@ const ConnectorComponent: React.FC = ({ isLoading }) => { component={ConnectorFields} componentProps={{ connectors, + hideConnectorServiceNowSir, isEdit: true, }} /> diff --git a/x-pack/plugins/security_solution/public/cases/components/create/form.tsx b/x-pack/plugins/security_solution/public/cases/components/create/form.tsx index f5b113ae8e26f..09518c6f6adc1 100644 --- a/x-pack/plugins/security_solution/public/cases/components/create/form.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/create/form.tsx @@ -36,78 +36,84 @@ const MySpinner = styled(EuiLoadingSpinner)` `; interface Props { + hideConnectorServiceNowSir?: boolean; withSteps?: boolean; } -export const CreateCaseForm: React.FC = React.memo(({ withSteps = true }) => { - const { isSubmitting } = useFormContext(); +export const CreateCaseForm: React.FC = React.memo( + ({ hideConnectorServiceNowSir = false, withSteps = true }) => { + const { isSubmitting } = useFormContext(); - const firstStep = useMemo( - () => ({ - title: i18n.STEP_ONE_TITLE, - children: ( - <> - + const firstStep = useMemo( + () => ({ + title: i18n.STEP_ONE_TITLE, + children: ( + <> + <Title isLoading={isSubmitting} /> + <Container> + <Tags isLoading={isSubmitting} /> + </Container> + <Container big> + <Description isLoading={isSubmitting} /> + </Container> + </> + ), + }), + [isSubmitting] + ); + + const secondStep = useMemo( + () => ({ + title: i18n.STEP_TWO_TITLE, + children: ( <Container> - <Tags isLoading={isSubmitting} /> - </Container> - <Container big> - <Description isLoading={isSubmitting} /> + <SyncAlertsToggle isLoading={isSubmitting} /> </Container> - </> - ), - }), - [isSubmitting] - ); - - const secondStep = useMemo( - () => ({ - title: i18n.STEP_TWO_TITLE, - children: ( - <Container> - <SyncAlertsToggle isLoading={isSubmitting} /> - </Container> - ), - }), - [isSubmitting] - ); + ), + }), + [isSubmitting] + ); - const thirdStep = useMemo( - () => ({ - title: i18n.STEP_THREE_TITLE, - children: ( - <Container> - <Connector isLoading={isSubmitting} /> - </Container> - ), - }), - [isSubmitting] - ); + const thirdStep = useMemo( + () => ({ + title: i18n.STEP_THREE_TITLE, + children: ( + <Container> + <Connector + hideConnectorServiceNowSir={hideConnectorServiceNowSir} + isLoading={isSubmitting} + /> + </Container> + ), + }), + [hideConnectorServiceNowSir, isSubmitting] + ); - const allSteps = useMemo(() => [firstStep, secondStep, thirdStep], [ - firstStep, - secondStep, - thirdStep, - ]); + const allSteps = useMemo(() => [firstStep, secondStep, thirdStep], [ + firstStep, + secondStep, + thirdStep, + ]); - return ( - <> - {isSubmitting && <MySpinner data-test-subj="create-case-loading-spinner" size="xl" />} - {withSteps ? ( - <EuiSteps - headingElement="h2" - steps={allSteps} - data-test-subj={'case-creation-form-steps'} - /> - ) : ( - <> - {firstStep.children} - {secondStep.children} - {thirdStep.children} - </> - )} - </> - ); -}); + return ( + <> + {isSubmitting && <MySpinner data-test-subj="create-case-loading-spinner" size="xl" />} + {withSteps ? ( + <EuiSteps + headingElement="h2" + steps={allSteps} + data-test-subj={'case-creation-form-steps'} + /> + ) : ( + <> + {firstStep.children} + {secondStep.children} + {thirdStep.children} + </> + )} + </> + ); + } +); CreateCaseForm.displayName = 'CreateCaseForm'; diff --git a/x-pack/plugins/security_solution/public/cases/components/create/form_context.tsx b/x-pack/plugins/security_solution/public/cases/components/create/form_context.tsx index 26203d7268fd3..f56dcafdc95e4 100644 --- a/x-pack/plugins/security_solution/public/cases/components/create/form_context.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/create/form_context.tsx @@ -19,7 +19,7 @@ import { usePostPushToService } from '../../containers/use_post_push_to_service' import { useConnectors } from '../../containers/configure/use_connectors'; import { useCaseConfigure } from '../../containers/configure/use_configure'; import { Case } from '../../containers/types'; -import { CaseType } from '../../../../../case/common/api'; +import { CaseType, ConnectorTypes } from '../../../../../case/common/api'; const initialCaseValue: FormProps = { description: '', @@ -31,29 +31,40 @@ const initialCaseValue: FormProps = { }; interface Props { + afterCaseCreated?: (theCase: Case) => Promise<void>; caseType?: CaseType; + hideConnectorServiceNowSir?: boolean; onSuccess?: (theCase: Case) => Promise<void>; - afterCaseCreated?: (theCase: Case) => Promise<void>; } export const FormContext: React.FC<Props> = ({ + afterCaseCreated, caseType = CaseType.individual, children, + hideConnectorServiceNowSir, onSuccess, - afterCaseCreated, }) => { const { connectors } = useConnectors(); const { connector: configurationConnector } = useCaseConfigure(); const { postCase } = usePostCase(); const { pushCaseToExternalService } = usePostPushToService(); - const connectorId = useMemo( - () => - connectors.some((connector) => connector.id === configurationConnector.id) - ? configurationConnector.id - : 'none', - [configurationConnector.id, connectors] - ); + const connectorId = useMemo(() => { + if ( + hideConnectorServiceNowSir && + configurationConnector.type === ConnectorTypes.serviceNowSIR + ) { + return 'none'; + } + return connectors.some((connector) => connector.id === configurationConnector.id) + ? configurationConnector.id + : 'none'; + }, [ + configurationConnector.id, + configurationConnector.type, + connectors, + hideConnectorServiceNowSir, + ]); const submitCase = useCallback( async ( diff --git a/x-pack/plugins/security_solution/public/cases/components/edit_connector/index.tsx b/x-pack/plugins/security_solution/public/cases/components/edit_connector/index.tsx index 34dcacaf42a98..d0f478dc17f81 100644 --- a/x-pack/plugins/security_solution/public/cases/components/edit_connector/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/edit_connector/index.tsx @@ -34,7 +34,6 @@ import * as i18n from './translations'; interface EditConnectorProps { caseFields: ConnectorTypeFields['fields']; connectors: ActionConnector[]; - disabled?: boolean; isLoading: boolean; onSubmit: ( connectorId: string, @@ -44,6 +43,8 @@ interface EditConnectorProps { ) => void; selectedConnector: string; userActions: CaseUserActions[]; + disabled?: boolean; + hideConnectorServiceNowSir?: boolean; } const MyFlexGroup = styled(EuiFlexGroup)` @@ -105,6 +106,7 @@ export const EditConnector = React.memo( caseFields, connectors, disabled = false, + hideConnectorServiceNowSir = false, isLoading, onSubmit, selectedConnector, @@ -234,6 +236,7 @@ export const EditConnector = React.memo( dataTestSubj: 'caseConnectors', defaultValue: selectedConnector, disabled, + hideConnectorServiceNowSir, idAria: 'caseConnectors', isEdit: editConnector, isLoading, diff --git a/x-pack/plugins/security_solution/public/cases/components/status/config.ts b/x-pack/plugins/security_solution/public/cases/components/status/config.ts index 0eebef39859c7..eab4bebedf064 100644 --- a/x-pack/plugins/security_solution/public/cases/components/status/config.ts +++ b/x-pack/plugins/security_solution/public/cases/components/status/config.ts @@ -4,36 +4,13 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { EuiIconType } from '@elastic/eui/src/components/icon/icon'; import { CaseStatuses } from '../../../../../case/common/api'; import * as i18n from './translations'; +import { AllCaseStatus, Statuses, StatusAll } from './types'; -type Statuses = Record< - CaseStatuses, - { - color: string; - label: string; - icon: EuiIconType; - actions: { - bulk: { - title: string; - }; - single: { - title: string; - description?: string; - }; - }; - actionBar: { - title: string; - }; - button: { - label: string; - }; - stats: { - title: string; - }; - } ->; +export const allCaseStatus: AllCaseStatus = { + [StatusAll]: { color: 'hollow', label: i18n.ALL }, +}; export const statuses: Statuses = { [CaseStatuses.open]: { diff --git a/x-pack/plugins/security_solution/public/cases/components/status/index.ts b/x-pack/plugins/security_solution/public/cases/components/status/index.ts index 2da6cd26d5ab4..94d7cb6a31830 100644 --- a/x-pack/plugins/security_solution/public/cases/components/status/index.ts +++ b/x-pack/plugins/security_solution/public/cases/components/status/index.ts @@ -8,3 +8,4 @@ export * from './status'; export * from './config'; export * from './stats'; +export * from './types'; diff --git a/x-pack/plugins/security_solution/public/cases/components/status/status.tsx b/x-pack/plugins/security_solution/public/cases/components/status/status.tsx index ba0f9a9cfde00..de4c979daf4c1 100644 --- a/x-pack/plugins/security_solution/public/cases/components/status/status.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/status/status.tsx @@ -9,12 +9,12 @@ import React, { memo, useMemo } from 'react'; import { noop } from 'lodash/fp'; import { EuiBadge } from '@elastic/eui'; -import { CaseStatuses } from '../../../../../case/common/api'; -import { statuses } from './config'; +import { allCaseStatus, statuses } from './config'; +import { CaseStatusWithAllStatus, StatusAll } from './types'; import * as i18n from './translations'; interface Props { - type: CaseStatuses; + type: CaseStatusWithAllStatus; withArrow?: boolean; onClick?: () => void; } @@ -22,7 +22,7 @@ interface Props { const StatusComponent: React.FC<Props> = ({ type, withArrow = false, onClick = noop }) => { const props = useMemo( () => ({ - color: statuses[type].color, + color: type === StatusAll ? allCaseStatus[StatusAll].color : statuses[type].color, ...(withArrow ? { iconType: 'arrowDown', iconSide: 'right' as const } : {}), }), [withArrow, type] @@ -35,7 +35,7 @@ const StatusComponent: React.FC<Props> = ({ type, withArrow = false, onClick = n iconOnClickAriaLabel={i18n.STATUS_ICON_ARIA} data-test-subj={`status-badge-${type}`} > - {statuses[type].label} + {type === StatusAll ? allCaseStatus[StatusAll].label : statuses[type].label} </EuiBadge> ); }; diff --git a/x-pack/plugins/security_solution/public/cases/components/status/translations.ts b/x-pack/plugins/security_solution/public/cases/components/status/translations.ts index 1220b6beaeb65..00dc5d3333f15 100644 --- a/x-pack/plugins/security_solution/public/cases/components/status/translations.ts +++ b/x-pack/plugins/security_solution/public/cases/components/status/translations.ts @@ -8,6 +8,10 @@ import { i18n } from '@kbn/i18n'; export * from '../../translations'; +export const ALL = i18n.translate('xpack.securitySolution.case.status.all', { + defaultMessage: 'All', +}); + export const OPEN = i18n.translate('xpack.securitySolution.case.status.open', { defaultMessage: 'Open', }); diff --git a/x-pack/plugins/security_solution/public/cases/components/status/types.ts b/x-pack/plugins/security_solution/public/cases/components/status/types.ts new file mode 100644 index 0000000000000..6f642b281419b --- /dev/null +++ b/x-pack/plugins/security_solution/public/cases/components/status/types.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 { EuiIconType } from '@elastic/eui/src/components/icon/icon'; +import { CaseStatuses } from '../../../../../case/common/api'; + +export const StatusAll = 'all' as const; +type StatusAllType = typeof StatusAll; + +export type CaseStatusWithAllStatus = CaseStatuses | StatusAllType; + +export type AllCaseStatus = Record<StatusAllType, { color: string; label: string }>; + +export type Statuses = Record< + CaseStatuses, + { + color: string; + label: string; + icon: EuiIconType; + actions: { + bulk: { + title: string; + }; + single: { + title: string; + description?: string; + }; + }; + actionBar: { + title: string; + }; + button: { + label: string; + }; + stats: { + title: string; + }; + } +>; diff --git a/x-pack/plugins/security_solution/public/cases/components/use_create_case_modal/create_case_modal.tsx b/x-pack/plugins/security_solution/public/cases/components/use_create_case_modal/create_case_modal.tsx index 3e11ee526839c..b1edaa56cd348 100644 --- a/x-pack/plugins/security_solution/public/cases/components/use_create_case_modal/create_case_modal.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/use_create_case_modal/create_case_modal.tsx @@ -21,6 +21,7 @@ export interface CreateCaseModalProps { onCloseCaseModal: () => void; onSuccess: (theCase: Case) => Promise<void>; caseType?: CaseType; + hideConnectorServiceNowSir?: boolean; } const Container = styled.div` @@ -35,6 +36,7 @@ const CreateModalComponent: React.FC<CreateCaseModalProps> = ({ onCloseCaseModal, onSuccess, caseType = CaseType.individual, + hideConnectorServiceNowSir = false, }) => { return isModalOpen ? ( <EuiModal onClose={onCloseCaseModal} data-test-subj="all-cases-modal"> @@ -42,8 +44,15 @@ const CreateModalComponent: React.FC<CreateCaseModalProps> = ({ <EuiModalHeaderTitle>{i18n.CREATE_TITLE}</EuiModalHeaderTitle> </EuiModalHeader> <EuiModalBody> - <FormContext caseType={caseType} onSuccess={onSuccess}> - <CreateCaseForm withSteps={false} /> + <FormContext + hideConnectorServiceNowSir={hideConnectorServiceNowSir} + caseType={caseType} + onSuccess={onSuccess} + > + <CreateCaseForm + withSteps={false} + hideConnectorServiceNowSir={hideConnectorServiceNowSir} + /> <Container> <SubmitCaseButton /> </Container> diff --git a/x-pack/plugins/security_solution/public/cases/components/use_create_case_modal/index.tsx b/x-pack/plugins/security_solution/public/cases/components/use_create_case_modal/index.tsx index 1cef63ae9cfbf..50887f08dee6e 100644 --- a/x-pack/plugins/security_solution/public/cases/components/use_create_case_modal/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/use_create_case_modal/index.tsx @@ -13,6 +13,7 @@ import { CreateCaseModal } from './create_case_modal'; export interface UseCreateCaseModalProps { onCaseCreated: (theCase: Case) => void; caseType?: CaseType; + hideConnectorServiceNowSir?: boolean; } export interface UseCreateCaseModalReturnedValues { modal: JSX.Element; @@ -24,6 +25,7 @@ export interface UseCreateCaseModalReturnedValues { export const useCreateCaseModal = ({ caseType = CaseType.individual, onCaseCreated, + hideConnectorServiceNowSir = false, }: UseCreateCaseModalProps) => { const [isModalOpen, setIsModalOpen] = useState<boolean>(false); const closeModal = useCallback(() => setIsModalOpen(false), []); @@ -41,6 +43,7 @@ export const useCreateCaseModal = ({ modal: ( <CreateCaseModal caseType={caseType} + hideConnectorServiceNowSir={hideConnectorServiceNowSir} isModalOpen={isModalOpen} onCloseCaseModal={closeModal} onSuccess={onSuccess} @@ -50,7 +53,7 @@ export const useCreateCaseModal = ({ closeModal, openModal, }), - [caseType, closeModal, isModalOpen, onSuccess, openModal] + [caseType, closeModal, hideConnectorServiceNowSir, isModalOpen, onSuccess, openModal] ); return state; diff --git a/x-pack/plugins/security_solution/public/cases/containers/api.test.tsx b/x-pack/plugins/security_solution/public/cases/containers/api.test.tsx index ee63749b49435..01f1ba173d5be 100644 --- a/x-pack/plugins/security_solution/public/cases/containers/api.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/containers/api.test.tsx @@ -137,7 +137,6 @@ describe('Case Configuration API', () => { ...DEFAULT_QUERY_PARAMS, reporters: [], tags: [], - status: CaseStatuses.open, }, signal: abortCtrl.signal, }); diff --git a/x-pack/plugins/security_solution/public/cases/containers/api.ts b/x-pack/plugins/security_solution/public/cases/containers/api.ts index c87e210b42bc0..a064189854879 100644 --- a/x-pack/plugins/security_solution/public/cases/containers/api.ts +++ b/x-pack/plugins/security_solution/public/cases/containers/api.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { assign } from 'lodash'; +import { assign, omit } from 'lodash'; import { CasePatchRequest, @@ -14,7 +14,7 @@ import { CasesFindResponse, CasesResponse, CasesStatusResponse, - CaseStatuses, + CaseType, CaseUserActionsResponse, CommentRequest, CommentType, @@ -44,6 +44,7 @@ import { } from '../../../../case/common/api/helpers'; import { KibanaServices } from '../../common/lib/kibana'; +import { StatusAll } from '../components/status'; import { ActionLicense, @@ -165,9 +166,10 @@ export const getSubCaseUserActions = async ( export const getCases = async ({ filterOptions = { + onlyCollectionType: false, search: '', reporters: [], - status: CaseStatuses.open, + status: StatusAll, tags: [], }, queryParams = { @@ -183,11 +185,12 @@ export const getCases = async ({ tags: filterOptions.tags.map((t) => `"${t.replace(/"/g, '\\"')}"`), status: filterOptions.status, ...(filterOptions.search.length > 0 ? { search: filterOptions.search } : {}), + ...(filterOptions.onlyCollectionType ? { type: CaseType.collection } : {}), ...queryParams, }; const response = await KibanaServices.get().http.fetch<CasesFindResponse>(`${CASES_URL}/_find`, { method: 'GET', - query, + query: query.status === StatusAll ? omit(query, ['status']) : query, signal, }); return convertAllCasesToCamel(decodeCasesFindResponse(response)); diff --git a/x-pack/plugins/security_solution/public/cases/containers/types.ts b/x-pack/plugins/security_solution/public/cases/containers/types.ts index d2931a790bd79..09c911d93ea47 100644 --- a/x-pack/plugins/security_solution/public/cases/containers/types.ts +++ b/x-pack/plugins/security_solution/public/cases/containers/types.ts @@ -17,11 +17,10 @@ import { CaseType, AssociationType, } from '../../../../case/common/api'; +import { CaseStatusWithAllStatus } from '../components/status'; export { CaseConnector, ActionConnector, CaseStatuses } from '../../../../case/common/api'; -export type AllCaseType = AssociationType & CaseType; - export type Comment = CommentRequest & { associationType: AssociationType; id: string; @@ -96,9 +95,10 @@ export interface QueryParams { export interface FilterOptions { search: string; - status: CaseStatuses; + status: CaseStatusWithAllStatus; tags: string[]; reporters: User[]; + onlyCollectionType?: boolean; } export interface CasesStatus { diff --git a/x-pack/plugins/security_solution/public/cases/containers/use_get_cases.tsx b/x-pack/plugins/security_solution/public/cases/containers/use_get_cases.tsx index c83cc02dedb97..d27bb5ab1b462 100644 --- a/x-pack/plugins/security_solution/public/cases/containers/use_get_cases.tsx +++ b/x-pack/plugins/security_solution/public/cases/containers/use_get_cases.tsx @@ -6,12 +6,12 @@ */ import { useCallback, useEffect, useReducer, useRef } from 'react'; -import { CaseStatuses } from '../../../../case/common/api'; import { DEFAULT_TABLE_ACTIVE_PAGE, DEFAULT_TABLE_LIMIT } from './constants'; import { AllCases, SortFieldCase, FilterOptions, QueryParams, Case, UpdateByKey } from './types'; import { errorToToaster, useStateToaster } from '../../common/components/toasters'; import * as i18n from './translations'; import { getCases, patchCase } from './api'; +import { StatusAll } from '../components/status'; export interface UseGetCasesState { data: AllCases; @@ -95,8 +95,9 @@ const dataFetchReducer = (state: UseGetCasesState, action: Action): UseGetCasesS export const DEFAULT_FILTER_OPTIONS: FilterOptions = { search: '', reporters: [], - status: CaseStatuses.open, + status: StatusAll, tags: [], + onlyCollectionType: false, }; export const DEFAULT_QUERY_PARAMS: QueryParams = { @@ -129,10 +130,13 @@ export interface UseGetCases extends UseGetCasesState { setSelectedCases: (mySelectedCases: Case[]) => void; } -export const useGetCases = (initialQueryParams?: QueryParams): UseGetCases => { +export const useGetCases = ( + initialQueryParams?: QueryParams, + initialFilterOptions?: FilterOptions +): UseGetCases => { const [state, dispatch] = useReducer(dataFetchReducer, { data: initialData, - filterOptions: DEFAULT_FILTER_OPTIONS, + filterOptions: initialFilterOptions ?? DEFAULT_FILTER_OPTIONS, isError: false, loading: [], queryParams: initialQueryParams ?? DEFAULT_QUERY_PARAMS, diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/__snapshots__/json_view.test.tsx.snap b/x-pack/plugins/security_solution/public/common/components/event_details/__snapshots__/json_view.test.tsx.snap index 2b681870e92fe..0412b3074e3f1 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/__snapshots__/json_view.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/common/components/event_details/__snapshots__/json_view.test.tsx.snap @@ -15,8 +15,8 @@ exports[`JSON View rendering should match snapshot 1`] = ` value="{ \\"_id\\": \\"pEMaMmkBUV60JmNWmWVi\\", \\"_index\\": \\"filebeat-8.0.0-2019.02.19-000001\\", - \\"_type\\": \\"_doc\\", \\"_score\\": 1, + \\"_type\\": \\"_doc\\", \\"@timestamp\\": \\"2019-02-28T16:50:54.621Z\\", \\"agent\\": { \\"ephemeral_id\\": \\"9d391ef2-a734-4787-8891-67031178c641\\", diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/columns.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/columns.tsx index 8fc6633df247f..a62b652492c5f 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/columns.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/columns.tsx @@ -85,24 +85,28 @@ export const getColumns = ({ sortable: false, truncateText: false, width: '30px', - render: (field: string) => ( - <EuiToolTip content={i18n.VIEW_COLUMN(field)}> - <EuiCheckbox - aria-label={i18n.VIEW_COLUMN(field)} - checked={columnHeaders.findIndex((c) => c.id === field) !== -1} - data-test-subj={`toggle-field-${field}`} - data-colindex={1} - id={field} - onChange={() => - toggleColumn({ - columnHeaderType: defaultColumnHeaderType, - id: field, - width: DEFAULT_COLUMN_MIN_WIDTH, - }) - } - /> - </EuiToolTip> - ), + render: (field: string, data: EventFieldsData) => { + const label = data.isObjectArray ? i18n.NESTED_COLUMN(field) : i18n.VIEW_COLUMN(field); + return ( + <EuiToolTip content={label}> + <EuiCheckbox + aria-label={label} + checked={columnHeaders.findIndex((c) => c.id === field) !== -1} + data-test-subj={`toggle-field-${field}`} + data-colindex={1} + id={field} + onChange={() => + toggleColumn({ + columnHeaderType: defaultColumnHeaderType, + id: field, + width: DEFAULT_COLUMN_MIN_WIDTH, + }) + } + disabled={data.isObjectArray && data.type !== 'geo_point'} + /> + </EuiToolTip> + ); + }, }, { field: 'field', @@ -118,38 +122,42 @@ export const getColumns = ({ </EuiFlexItem> <EuiFlexItem grow={false}> - <DroppableWrapper - droppableId={getDroppableId( - `event-details-field-droppable-wrapper-${contextId}-${eventId}-${data.category}-${field}` - )} - key={getDroppableId( - `event-details-field-droppable-wrapper-${contextId}-${eventId}-${data.category}-${field}` - )} - isDropDisabled={true} - type={DRAG_TYPE_FIELD} - renderClone={(provided) => ( - <div - {...provided.draggableProps} - {...provided.dragHandleProps} - ref={provided.innerRef} - tabIndex={-1} - > - <DragEffects> - <DraggableFieldBadge fieldId={field} /> - </DragEffects> - </div> - )} - > - <DraggableFieldsBrowserField - browserFields={browserFields} - categoryId={data.category} - fieldName={field} - fieldCategory={data.category} - onUpdateColumns={onUpdateColumns} - timelineId={timelineId} - toggleColumn={toggleColumn} - /> - </DroppableWrapper> + {data.isObjectArray && data.type !== 'geo_point' ? ( + <>{field}</> + ) : ( + <DroppableWrapper + droppableId={getDroppableId( + `event-details-field-droppable-wrapper-${contextId}-${eventId}-${data.category}-${field}` + )} + key={getDroppableId( + `event-details-field-droppable-wrapper-${contextId}-${eventId}-${data.category}-${field}` + )} + isDropDisabled={true} + type={DRAG_TYPE_FIELD} + renderClone={(provided) => ( + <div + {...provided.draggableProps} + {...provided.dragHandleProps} + ref={provided.innerRef} + tabIndex={-1} + > + <DragEffects> + <DraggableFieldBadge fieldId={field} /> + </DragEffects> + </div> + )} + > + <DraggableFieldsBrowserField + browserFields={browserFields} + categoryId={data.category} + fieldName={field} + fieldCategory={data.category} + onUpdateColumns={onUpdateColumns} + timelineId={timelineId} + toggleColumn={toggleColumn} + /> + </DroppableWrapper> + )} </EuiFlexItem> <EuiFlexItem grow={false}> <EuiIconTip @@ -191,6 +199,7 @@ export const getColumns = ({ fieldFormat={data.format} fieldName={data.field} fieldType={data.type} + isObjectArray={data.isObjectArray} value={value} linkValue={getLinkValue(data.field)} /> diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/event_fields_browser.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/event_fields_browser.tsx index 497768785735b..93d0e6ccfbe3c 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/event_fields_browser.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/event_fields_browser.tsx @@ -108,7 +108,6 @@ export const EventFieldsBrowser = React.memo<Props>( const columnHeaders = useDeepEqualSelector((state) => { const { columns } = getTimeline(state, timelineId) ?? timelineDefaults; - return getColumnHeaders(columns, browserFields); }); diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/helpers.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/helpers.tsx index 7c7b8ba70f9bd..00e2ee276f181 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/helpers.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/helpers.tsx @@ -112,6 +112,7 @@ export const getIconFromType = (type: string | null) => { case 'date': return 'clock'; case 'ip': + case 'geo_point': return 'globe'; case 'object': return 'questionInCircle'; diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/json_view.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/json_view.tsx index 449010781d448..c9ca93582cd9a 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/json_view.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/json_view.tsx @@ -54,12 +54,14 @@ export const JsonView = React.memo<Props>(({ data }) => { JsonView.displayName = 'JsonView'; export const buildJsonView = (data: TimelineEventsDetailsItem[]) => - data.reduce( - (accumulator, item) => - set( - item.field, - Array.isArray(item.originalValue) ? item.originalValue.join() : item.originalValue, - accumulator - ), - {} - ); + data + .sort((a, b) => a.field.localeCompare(b.field)) + .reduce( + (accumulator, item) => + set( + item.field, + Array.isArray(item.originalValue) ? item.originalValue.join() : item.originalValue, + accumulator + ), + {} + ); diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/translations.ts b/x-pack/plugins/security_solution/public/common/components/event_details/translations.ts index c2b7bb4587dbd..3a599b174251a 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/translations.ts +++ b/x-pack/plugins/security_solution/public/common/components/event_details/translations.ts @@ -61,3 +61,10 @@ export const VIEW_COLUMN = (field: string) => values: { field }, defaultMessage: 'View {field} column', }); + +export const NESTED_COLUMN = (field: string) => + i18n.translate('xpack.securitySolution.eventDetails.nestedColumnCheckboxAriaLabel', { + values: { field }, + defaultMessage: + 'The {field} field is an object, and is broken down into nested fields which can be added as column', + }); diff --git a/x-pack/plugins/security_solution/public/common/components/overview_description_list/index.tsx b/x-pack/plugins/security_solution/public/common/components/overview_description_list/index.tsx index 570ac4e9577b7..606991bc08910 100644 --- a/x-pack/plugins/security_solution/public/common/components/overview_description_list/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/overview_description_list/index.tsx @@ -14,13 +14,11 @@ import { DescriptionListStyled } from '../../../common/components/page'; export const OverviewDescriptionList = ({ dataTestSubj, descriptionList, - isInDetailsSidePanel = false, }: { dataTestSubj?: string; descriptionList: DescriptionList[]; - isInDetailsSidePanel: boolean; }) => ( - <EuiFlexItem grow={!isInDetailsSidePanel}> + <EuiFlexItem grow={true}> <DescriptionListStyled data-test-subj={dataTestSubj} listItems={descriptionList} /> </EuiFlexItem> ); diff --git a/x-pack/plugins/security_solution/public/common/mock/mock_detail_item.ts b/x-pack/plugins/security_solution/public/common/mock/mock_detail_item.ts index ca84ef539bec3..198ab084ae0b8 100644 --- a/x-pack/plugins/security_solution/public/common/mock/mock_detail_item.ts +++ b/x-pack/plugins/security_solution/public/common/mock/mock_detail_item.ts @@ -14,105 +14,126 @@ export const mockDetailItemData: TimelineEventsDetailsItem[] = [ field: '_id', originalValue: 'pEMaMmkBUV60JmNWmWVi', values: ['pEMaMmkBUV60JmNWmWVi'], + isObjectArray: false, }, { field: '_index', originalValue: 'filebeat-8.0.0-2019.02.19-000001', values: ['filebeat-8.0.0-2019.02.19-000001'], + isObjectArray: false, }, { field: '_type', originalValue: '_doc', values: ['_doc'], + isObjectArray: false, }, { field: '_score', originalValue: 1, values: ['1'], + isObjectArray: false, }, { field: '@timestamp', originalValue: '2019-02-28T16:50:54.621Z', values: ['2019-02-28T16:50:54.621Z'], + isObjectArray: false, }, { field: 'agent.ephemeral_id', originalValue: '9d391ef2-a734-4787-8891-67031178c641', values: ['9d391ef2-a734-4787-8891-67031178c641'], + isObjectArray: false, }, { field: 'agent.hostname', originalValue: 'siem-kibana', values: ['siem-kibana'], + isObjectArray: false, }, { - field: 'agent.id', - originalValue: '5de03d5f-52f3-482e-91d4-853c7de073c3', - values: ['5de03d5f-52f3-482e-91d4-853c7de073c3'], + field: 'cloud.project.id', + originalValue: 'elastic-beats', + values: ['elastic-beats'], + isObjectArray: false, }, { - field: 'agent.type', - originalValue: 'filebeat', - values: ['filebeat'], + field: 'cloud.provider', + originalValue: 'gce', + values: ['gce'], + isObjectArray: false, }, { - field: 'agent.version', - originalValue: '8.0.0', - values: ['8.0.0'], + field: 'destination.bytes', + originalValue: 584, + values: ['584'], + isObjectArray: false, }, { - field: 'cloud.availability_zone', - originalValue: 'projects/189716325846/zones/us-east1-b', - values: ['projects/189716325846/zones/us-east1-b'], + field: 'destination.ip', + originalValue: '10.47.8.200', + values: ['10.47.8.200'], + isObjectArray: false, }, { - field: 'cloud.instance.id', - originalValue: '5412578377715150143', - values: ['5412578377715150143'], + field: 'agent.id', + originalValue: '5de03d5f-52f3-482e-91d4-853c7de073c3', + values: ['5de03d5f-52f3-482e-91d4-853c7de073c3'], + isObjectArray: false, }, { field: 'cloud.instance.name', originalValue: 'siem-kibana', values: ['siem-kibana'], + isObjectArray: false, }, { field: 'cloud.machine.type', originalValue: 'projects/189716325846/machineTypes/n1-standard-1', values: ['projects/189716325846/machineTypes/n1-standard-1'], + isObjectArray: false, }, { - field: 'cloud.project.id', - originalValue: 'elastic-beats', - values: ['elastic-beats'], - }, - { - field: 'cloud.provider', - originalValue: 'gce', - values: ['gce'], - }, - { - field: 'destination.bytes', - originalValue: 584, - values: ['584'], - }, - { - field: 'destination.ip', - originalValue: '10.47.8.200', - values: ['10.47.8.200'], + field: 'agent.type', + originalValue: 'filebeat', + values: ['filebeat'], + isObjectArray: false, }, { field: 'destination.packets', originalValue: 4, values: ['4'], + isObjectArray: false, }, { field: 'destination.port', originalValue: 902, values: ['902'], + isObjectArray: false, }, { field: 'event.kind', originalValue: 'event', values: ['event'], + isObjectArray: false, + }, + { + field: 'agent.version', + originalValue: '8.0.0', + values: ['8.0.0'], + isObjectArray: false, + }, + { + field: 'cloud.availability_zone', + originalValue: 'projects/189716325846/zones/us-east1-b', + values: ['projects/189716325846/zones/us-east1-b'], + isObjectArray: false, + }, + { + field: 'cloud.instance.id', + originalValue: '5412578377715150143', + values: ['5412578377715150143'], + isObjectArray: false, }, ]; diff --git a/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts b/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts index 70ed497ce0cac..26b30e0d1f89a 100644 --- a/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts +++ b/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts @@ -2287,11 +2287,13 @@ export const mockTimelineDetails: TimelineEventsDetailsItem[] = [ field: 'host.name', values: ['apache'], originalValue: 'apache', + isObjectArray: false, }, { field: 'user.id', values: ['1'], originalValue: 1, + isObjectArray: false, }, ]; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/helpers.test.ts b/x-pack/plugins/security_solution/public/detections/components/alerts_table/helpers.test.ts index 3eb00f8534979..c296b75a0a253 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/helpers.test.ts +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/helpers.test.ts @@ -29,6 +29,7 @@ describe('helpers', () => { { field: 'x', values: ['The nickname of the developer we all :heart:'], + isObjectArray: false, originalValue: 'The nickname of the developer we all :heart:', }, ]); @@ -40,6 +41,7 @@ describe('helpers', () => { { field: 'x', values: ['The nickname of the developer we all :heart:'], + isObjectArray: false, originalValue: 'The nickname of the developer we all :heart:', }, ]); @@ -51,6 +53,7 @@ describe('helpers', () => { { field: 'x', values: ['The nickname of the developer we all :heart:', 'We are all made of stars'], + isObjectArray: false, originalValue: 'The nickname of the developer we all :heart:', }, ]); @@ -65,6 +68,7 @@ describe('helpers', () => { { field: 'x.y.z', values: ['zed'], + isObjectArray: false, originalValue: 'zed', }, ]); @@ -76,6 +80,7 @@ describe('helpers', () => { { field: 'x.y.z', values: ['zed'], + isObjectArray: false, originalValue: 'zed', }, ]); @@ -90,6 +95,7 @@ describe('helpers', () => { { field: 'a', values: (5 as unknown) as string[], + isObjectArray: false, originalValue: 'zed', }, ], @@ -104,7 +110,7 @@ describe('helpers', () => { 'when trying to access field:', 'a', 'from data object of:', - [{ field: 'a', originalValue: 'zed', values: 5 }] + [{ field: 'a', isObjectArray: false, originalValue: 'zed', values: 5 }] ); }); @@ -116,6 +122,7 @@ describe('helpers', () => { { field: 'a', values: (['hi', 5] as unknown) as string[], + isObjectArray: false, originalValue: 'zed', }, ], @@ -130,7 +137,7 @@ describe('helpers', () => { 'when trying to access field:', 'a', 'from data object of:', - [{ field: 'a', originalValue: 'zed', values: ['hi', 5] }] + [{ field: 'a', isObjectArray: false, originalValue: 'zed', values: ['hi', 5] }] ); }); }); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_field/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_field/index.test.tsx index 7563c8d8f99f0..5dbe1f1cef5be 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_field/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_field/index.test.tsx @@ -8,10 +8,11 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { RuleActionsField } from './index'; +import { getSupportedActions, RuleActionsField } from './index'; import { useForm, Form } from '../../../../shared_imports'; import { useKibana } from '../../../../common/lib/kibana'; import { useFormFieldMock } from '../../../../common/mock'; +import { ActionType } from '../../../../../../actions/common'; jest.mock('../../../../common/lib/kibana'); describe('RuleActionsField', () => { @@ -45,7 +46,11 @@ describe('RuleActionsField', () => { return ( <Form form={form}> - <RuleActionsField field={field} messageVariables={messageVariables} /> + <RuleActionsField + field={field} + messageVariables={messageVariables} + hasErrorOnCreationCaseAction={false} + /> </Form> ); }; @@ -53,4 +58,63 @@ describe('RuleActionsField', () => { expect(wrapper.dive().find('ActionForm')).toHaveLength(0); }); + + describe('#getSupportedActions', () => { + const actions: ActionType[] = [ + { + id: '.jira', + name: 'My Jira', + enabled: true, + enabledInConfig: false, + enabledInLicense: true, + minimumLicenseRequired: 'gold', + }, + { + id: '.case', + name: 'Cases', + enabled: true, + enabledInConfig: false, + enabledInLicense: true, + minimumLicenseRequired: 'basic', + }, + ]; + + it('if we have an error on case action creation, we do not support case connector', () => { + expect(getSupportedActions(actions, true)).toMatchInlineSnapshot(` + Array [ + Object { + "enabled": true, + "enabledInConfig": false, + "enabledInLicense": true, + "id": ".jira", + "minimumLicenseRequired": "gold", + "name": "My Jira", + }, + ] + `); + }); + + it('if we do NOT have an error on case action creation, we are supporting case connector', () => { + expect(getSupportedActions(actions, false)).toMatchInlineSnapshot(` + Array [ + Object { + "enabled": true, + "enabledInConfig": false, + "enabledInLicense": true, + "id": ".jira", + "minimumLicenseRequired": "gold", + "name": "My Jira", + }, + Object { + "enabled": true, + "enabledInConfig": false, + "enabledInLicense": true, + "id": ".case", + "minimumLicenseRequired": "basic", + "name": "Cases", + }, + ] + `); + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_field/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_field/index.tsx index cee85df5db436..9fd9e910ee0f8 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_field/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_field/index.tsx @@ -26,6 +26,7 @@ import { FORM_ERRORS_TITLE } from './translations'; interface Props { field: FieldHook; + hasErrorOnCreationCaseAction: boolean; messageVariables: ActionVariables; } @@ -39,7 +40,44 @@ const FieldErrorsContainer = styled.div` } `; -export const RuleActionsField: React.FC<Props> = ({ field, messageVariables }) => { +const ContainerActions = styled.div.attrs( + ({ className = '', $caseIndexes = [] }: { className?: string; $caseIndexes: string[] }) => ({ + className, + }) +)<{ $caseIndexes: string[] }>` + ${({ $caseIndexes }) => + $caseIndexes.map( + (index) => ` + div[id="${index}"].euiAccordion__childWrapper .euiAccordion__padding--l { + padding: 0px; + .euiFlexGroup { + display: none; + } + .euiSpacer.euiSpacer--xl { + height: 0px; + } + } + ` + )} +`; + +export const getSupportedActions = ( + actionTypes: ActionType[], + hasErrorOnCreationCaseAction: boolean +): ActionType[] => { + return actionTypes.filter((actionType) => { + if (actionType.id === '.case' && hasErrorOnCreationCaseAction) { + return false; + } + return NOTIFICATION_SUPPORTED_ACTION_TYPES_IDS.includes(actionType.id); + }); +}; + +export const RuleActionsField: React.FC<Props> = ({ + field, + hasErrorOnCreationCaseAction, + messageVariables, +}) => { const [fieldErrors, setFieldErrors] = useState<string | null>(null); const [supportedActionTypes, setSupportedActionTypes] = useState<ActionType[] | undefined>(); const form = useFormContext(); @@ -54,6 +92,17 @@ export const RuleActionsField: React.FC<Props> = ({ field, messageVariables }) = [field.value] ); + const caseActionIndexes = useMemo( + () => + actions.reduce<string[]>((acc, action, actionIndex) => { + if (action.actionTypeId === '.case') { + return [...acc, `${actionIndex}`]; + } + return acc; + }, []), + [actions] + ); + const setActionIdByIndex = useCallback( (id: string, index: number) => { const updatedActions = [...(actions as Array<Partial<AlertAction>>)]; @@ -83,13 +132,11 @@ export const RuleActionsField: React.FC<Props> = ({ field, messageVariables }) = useEffect(() => { (async function () { const actionTypes = await loadActionTypes({ http }); - const supportedTypes = actionTypes.filter((actionType) => - NOTIFICATION_SUPPORTED_ACTION_TYPES_IDS.includes(actionType.id) - ); + const supportedTypes = getSupportedActions(actionTypes, hasErrorOnCreationCaseAction); setSupportedActionTypes(supportedTypes); })(); // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + }, [hasErrorOnCreationCaseAction]); useEffect(() => { if (isSubmitting || !field.errors.length) { @@ -104,7 +151,7 @@ export const RuleActionsField: React.FC<Props> = ({ field, messageVariables }) = if (!supportedActionTypes) return <></>; return ( - <> + <ContainerActions $caseIndexes={caseActionIndexes}> {fieldErrors ? ( <> <FieldErrorsContainer> @@ -126,6 +173,6 @@ export const RuleActionsField: React.FC<Props> = ({ field, messageVariables }) = actionTypes={supportedActionTypes} defaultActionMessage={DEFAULT_ACTION_MESSAGE} /> - </> + </ContainerActions> ); }; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/index.tsx index 30898cdeca4a3..a31371c31cbbb 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/index.tsx @@ -36,6 +36,7 @@ import { useKibana } from '../../../../common/lib/kibana'; import { getSchema } from './schema'; import * as I18n from './translations'; import { APP_ID } from '../../../../../common/constants'; +import { useManageCaseAction } from './use_manage_case_action'; interface StepRuleActionsProps extends RuleStepProps { defaultValues?: ActionsStepRule | null; @@ -70,6 +71,7 @@ const StepRuleActionsComponent: FC<StepRuleActionsProps> = ({ setForm, actionMessageParams, }) => { + const [isLoadingCaseAction, hasErrorOnCreationCaseAction] = useManageCaseAction(); const { services: { application, @@ -138,13 +140,14 @@ const StepRuleActionsComponent: FC<StepRuleActionsProps> = ({ () => ({ idAria: 'detectionEngineStepRuleActionsThrottle', isDisabled: isLoading, + isLoading: isLoadingCaseAction, dataTestSubj: 'detectionEngineStepRuleActionsThrottle', hasNoInitialSelection: false, euiFieldProps: { options: throttleOptions, }, }), - [isLoading, throttleOptions] + [isLoading, isLoadingCaseAction, throttleOptions] ); const displayActionsOptions = useMemo( @@ -157,13 +160,14 @@ const StepRuleActionsComponent: FC<StepRuleActionsProps> = ({ component={RuleActionsField} componentProps={{ messageVariables: actionMessageParams, + hasErrorOnCreationCaseAction, }} /> </> ) : ( <UseField path="actions" component={GhostFormField} /> ), - [throttle, actionMessageParams] + [throttle, actionMessageParams, hasErrorOnCreationCaseAction] ); // only display the actions dropdown if the user has "read" privileges for actions const displayActionsDropDown = useMemo(() => { diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/use_manage_case_action.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/use_manage_case_action.tsx new file mode 100644 index 0000000000000..55b2aefe21310 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/use_manage_case_action.tsx @@ -0,0 +1,63 @@ +/* + * 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, useRef, useState } from 'react'; +import { ACTION_URL } from '../../../../../../case/common/constants'; +import { KibanaServices } from '../../../../common/lib/kibana'; + +interface CaseAction { + actionTypeId: string; + id: string; + isPreconfigured: boolean; + name: string; + referencedByCount: number; +} + +const CASE_ACTION_NAME = 'Cases'; + +export const useManageCaseAction = () => { + const hasInit = useRef(true); + const [loading, setLoading] = useState(true); + const [hasError, setHasError] = useState(false); + + useEffect(() => { + const abortCtrl = new AbortController(); + const fetchActions = async () => { + try { + const actions = await KibanaServices.get().http.fetch<CaseAction[]>(ACTION_URL, { + method: 'GET', + signal: abortCtrl.signal, + }); + if (!actions.some((a) => a.actionTypeId === '.case' && a.name === CASE_ACTION_NAME)) { + await KibanaServices.get().http.post<CaseAction[]>(`${ACTION_URL}/action`, { + method: 'POST', + body: JSON.stringify({ + actionTypeId: '.case', + config: {}, + name: CASE_ACTION_NAME, + secrets: {}, + }), + signal: abortCtrl.signal, + }); + } + setLoading(false); + } catch { + setLoading(false); + setHasError(true); + } + }; + if (hasInit.current) { + hasInit.current = false; + fetchActions(); + } + + return () => { + abortCtrl.abort(); + }; + }, []); + return [loading, hasError]; +}; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/edit/index.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/edit/index.tsx index 74fe97d0c7210..da5cf720d5315 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/edit/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/edit/index.tsx @@ -251,6 +251,7 @@ const EditRulePageComponent: FC = () => { rule ), ...(ruleId ? { id: ruleId } : {}), + ...(rule != null ? { max_signals: rule.max_signals } : {}), }); } }, [ diff --git a/x-pack/plugins/security_solution/public/network/components/details/index.tsx b/x-pack/plugins/security_solution/public/network/components/details/index.tsx index e263d49e22fc0..851197a78520b 100644 --- a/x-pack/plugins/security_solution/public/network/components/details/index.tsx +++ b/x-pack/plugins/security_solution/public/network/components/details/index.tsx @@ -144,11 +144,7 @@ export const IpOverview = React.memo<IpOverviewProps>( <InspectButton queryId={id} title={i18n.INSPECT_TITLE} inspectIndex={0} /> )} {descriptionLists.map((descriptionList, index) => ( - <OverviewDescriptionList - descriptionList={descriptionList} - isInDetailsSidePanel={isInDetailsSidePanel} - key={index} - /> + <OverviewDescriptionList descriptionList={descriptionList} key={index} /> ))} {loading && ( diff --git a/x-pack/plugins/security_solution/public/overview/components/host_overview/endpoint_overview/index.tsx b/x-pack/plugins/security_solution/public/overview/components/host_overview/endpoint_overview/index.tsx index 0d8e763b649bf..4caf854278cc2 100644 --- a/x-pack/plugins/security_solution/public/overview/components/host_overview/endpoint_overview/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/host_overview/endpoint_overview/index.tsx @@ -20,79 +20,73 @@ import * as i18n from './translations'; interface Props { contextID?: string; data: EndpointFields | null; - isInDetailsSidePanel?: boolean; } -export const EndpointOverview = React.memo<Props>( - ({ contextID, data, isInDetailsSidePanel = false }) => { - const getDefaultRenderer = useCallback( - (fieldName: string, fieldData: EndpointFields, attrName: string) => ( - <DefaultFieldRenderer - rowItems={[getOr('', fieldName, fieldData)]} - attrName={attrName} - idPrefix={contextID ? `endpoint-overview-${contextID}` : 'endpoint-overview'} - /> - ), - [contextID] - ); - const descriptionLists: Readonly<DescriptionList[][]> = useMemo( - () => [ - [ - { - title: i18n.ENDPOINT_POLICY, - description: - data != null && data.endpointPolicy != null - ? data.endpointPolicy - : getEmptyTagValue(), - }, - ], - [ - { - title: i18n.POLICY_STATUS, - description: - data != null && data.policyStatus != null ? ( - <EuiHealth - aria-label={data.policyStatus} - color={ - data.policyStatus === HostPolicyResponseActionStatus.failure - ? 'danger' - : data.policyStatus - } - > - {data.policyStatus} - </EuiHealth> - ) : ( - getEmptyTagValue() - ), - }, - ], - [ - { - title: i18n.SENSORVERSION, - description: - data != null && data.sensorVersion != null - ? getDefaultRenderer('sensorVersion', data, 'agent.version') - : getEmptyTagValue(), - }, - ], - [], // needs 4 columns for design +export const EndpointOverview = React.memo<Props>(({ contextID, data }) => { + const getDefaultRenderer = useCallback( + (fieldName: string, fieldData: EndpointFields, attrName: string) => ( + <DefaultFieldRenderer + rowItems={[getOr('', fieldName, fieldData)]} + attrName={attrName} + idPrefix={contextID ? `endpoint-overview-${contextID}` : 'endpoint-overview'} + /> + ), + [contextID] + ); + const descriptionLists: Readonly<DescriptionList[][]> = useMemo( + () => [ + [ + { + title: i18n.ENDPOINT_POLICY, + description: + data != null && data.endpointPolicy != null ? data.endpointPolicy : getEmptyTagValue(), + }, + ], + [ + { + title: i18n.POLICY_STATUS, + description: + data != null && data.policyStatus != null ? ( + <EuiHealth + aria-label={data.policyStatus} + color={ + data.policyStatus === HostPolicyResponseActionStatus.failure + ? 'danger' + : data.policyStatus + } + > + {data.policyStatus} + </EuiHealth> + ) : ( + getEmptyTagValue() + ), + }, ], - [data, getDefaultRenderer] - ); + [ + { + title: i18n.SENSORVERSION, + description: + data != null && data.sensorVersion != null + ? getDefaultRenderer('sensorVersion', data, 'agent.version') + : getEmptyTagValue(), + }, + ], + [], // needs 4 columns for design + ], + [data, getDefaultRenderer] + ); - return ( - <> - {descriptionLists.map((descriptionList, index) => ( - <OverviewDescriptionList - dataTestSubj="endpoint-overview" - descriptionList={descriptionList} - isInDetailsSidePanel={isInDetailsSidePanel} - key={index} - /> - ))} - </> - ); - } -); + return ( + <> + {descriptionLists.map((descriptionList, index) => ( + <OverviewDescriptionList + dataTestSubj="endpoint-overview" + descriptionList={descriptionList} + key={index} + /> + ))} + </> + ); +}); EndpointOverview.displayName = 'EndpointOverview'; diff --git a/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx b/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx index de0d782b3ceb7..c5d51a9466235 100644 --- a/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx @@ -207,11 +207,7 @@ export const HostOverview = React.memo<HostSummaryProps>( <InspectButton queryId={id} title={i18n.INSPECT_TITLE} inspectIndex={0} /> )} {descriptionLists.map((descriptionList, index) => ( - <OverviewDescriptionList - descriptionList={descriptionList} - isInDetailsSidePanel={isInDetailsSidePanel} - key={index} - /> + <OverviewDescriptionList descriptionList={descriptionList} key={index} /> ))} {loading && ( @@ -229,11 +225,7 @@ export const HostOverview = React.memo<HostSummaryProps>( <> <EuiHorizontalRule /> <OverviewWrapper direction={isInDetailsSidePanel ? 'column' : 'row'}> - <EndpointOverview - contextID={contextID} - data={data.endpoint} - isInDetailsSidePanel={isInDetailsSidePanel} - /> + <EndpointOverview contextID={contextID} data={data.endpoint} /> {loading && ( <Loader diff --git a/x-pack/plugins/security_solution/public/resolver/view/resolver_no_process_events.tsx b/x-pack/plugins/security_solution/public/resolver/view/resolver_no_process_events.tsx index 7159b0bda468b..5a743896518c2 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/resolver_no_process_events.tsx +++ b/x-pack/plugins/security_solution/public/resolver/view/resolver_no_process_events.tsx @@ -49,7 +49,7 @@ export const ResolverNoProcessEvents = () => ( </EuiText> <EuiSpacer size="m" /> <StyledEuiCodeBlock language="html" paddingSize="s" isCopyable> - {"event.category: 'process'"} + {'event.category: "process"'} </StyledEuiCodeBlock> </StyledEuiFlexGroup> ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/index.tsx index e96bccd32618d..4dcc799d79111 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/index.tsx @@ -10,7 +10,6 @@ import { EuiButtonIcon, EuiText, EuiToolTip, - EuiOverlayMask, EuiModal, EuiModalHeader, EuiModalHeaderTitle, @@ -33,12 +32,12 @@ import { RowRenderersBrowser } from './row_renderers_browser'; import * as i18n from './translations'; const StyledEuiModal = styled(EuiModal)` - margin: 0 auto; + ${({ theme }) => `margin-top: ${theme.eui.euiSizeXXL};`} max-width: 95vw; - min-height: 95vh; + min-height: 90vh; > .euiModal__flex { - max-height: 95vh; + max-height: 90vh; } `; @@ -65,15 +64,6 @@ const StyledEuiModalBody = styled(EuiModalBody)` } `; -const StyledEuiOverlayMask = styled(EuiOverlayMask)` - z-index: 8001; - padding-bottom: 0; - - > div { - width: 100%; - } -`; - interface StatefulRowRenderersBrowserProps { timelineId: string; } @@ -125,54 +115,47 @@ const StatefulRowRenderersBrowserComponent: React.FC<StatefulRowRenderersBrowser </EuiToolTip> {show && ( - <StyledEuiOverlayMask> - <StyledEuiModal onClose={hideFieldBrowser}> - <EuiModalHeader> - <EuiFlexGroup - alignItems="center" - justifyContent="spaceBetween" - direction="row" - gutterSize="none" - > - <EuiFlexItem grow={false}> - <EuiModalHeaderTitle>{i18n.CUSTOMIZE_EVENT_RENDERERS_TITLE}</EuiModalHeaderTitle> - <EuiText size="s">{i18n.CUSTOMIZE_EVENT_RENDERERS_DESCRIPTION}</EuiText> - </EuiFlexItem> - <EuiFlexItem grow={false}> - <EuiFlexGroup> - <EuiFlexItem grow={false}> - <EuiButtonEmpty - size="s" - data-test-subj="disable-all" - onClick={handleDisableAll} - > - {i18n.DISABLE_ALL} - </EuiButtonEmpty> - </EuiFlexItem> - - <EuiFlexItem grow={false}> - <EuiButton - fill - size="s" - data-test-subj="enable-all" - onClick={handleEnableAll} - > - {i18n.ENABLE_ALL} - </EuiButton> - </EuiFlexItem> - </EuiFlexGroup> - </EuiFlexItem> - </EuiFlexGroup> - </EuiModalHeader> - - <StyledEuiModalBody> - <RowRenderersBrowser - excludedRowRendererIds={excludedRowRendererIds} - setExcludedRowRendererIds={setExcludedRowRendererIds} - /> - </StyledEuiModalBody> - </StyledEuiModal> - </StyledEuiOverlayMask> + <StyledEuiModal onClose={hideFieldBrowser}> + <EuiModalHeader> + <EuiFlexGroup + alignItems="center" + justifyContent="spaceBetween" + direction="row" + gutterSize="none" + > + <EuiFlexItem grow={false}> + <EuiModalHeaderTitle>{i18n.CUSTOMIZE_EVENT_RENDERERS_TITLE}</EuiModalHeaderTitle> + <EuiText size="s">{i18n.CUSTOMIZE_EVENT_RENDERERS_DESCRIPTION}</EuiText> + </EuiFlexItem> + <EuiFlexItem grow={false}> + <EuiFlexGroup> + <EuiFlexItem grow={false}> + <EuiButtonEmpty + size="s" + data-test-subj="disable-all" + onClick={handleDisableAll} + > + {i18n.DISABLE_ALL} + </EuiButtonEmpty> + </EuiFlexItem> + + <EuiFlexItem grow={false}> + <EuiButton fill size="s" data-test-subj="enable-all" onClick={handleEnableAll}> + {i18n.ENABLE_ALL} + </EuiButton> + </EuiFlexItem> + </EuiFlexGroup> + </EuiFlexItem> + </EuiFlexGroup> + </EuiModalHeader> + + <StyledEuiModalBody> + <RowRenderersBrowser + excludedRowRendererIds={excludedRowRendererIds} + setExcludedRowRendererIds={setExcludedRowRendererIds} + /> + </StyledEuiModalBody> + </StyledEuiModal> )} </> ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/side_panel/__snapshots__/index.test.tsx.snap index aece377ee4f2d..a55710f346141 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/__snapshots__/index.test.tsx.snap @@ -24,9 +24,9 @@ exports[`Details Panel Component DetailsPanel: rendering it should not render th exports[`Details Panel Component DetailsPanel:EventDetails: rendering it should render the Details Panel when the panelView is set and the associated params are set 1`] = ` .c0 { - -webkit-flex: 0; - -ms-flex: 0; - flex: 0; + -webkit-flex: 0 1 auto; + -ms-flex: 0 1 auto; + flex: 0 1 auto; } <DetailsPanel @@ -237,9 +237,9 @@ exports[`Details Panel Component DetailsPanel:EventDetails: rendering it should exports[`Details Panel Component DetailsPanel:EventDetails: rendering it should render the Event Details view of the Details Panel in the flyout when the panelView is eventDetail and the eventId is set 1`] = ` Array [ .c1 { - -webkit-flex: 0; - -ms-flex: 0; - flex: 0; + -webkit-flex: 0 1 auto; + -ms-flex: 0 1 auto; + flex: 0 1 auto; } .c2 .euiFlyoutBody__overflow { @@ -268,13 +268,13 @@ Array [ <Styled(EuiFlyout) data-test-subj="timeline:details-panel:flyout" onClose={[Function]} - size="s" + size="m" > <EuiFlyout className="c0" data-test-subj="timeline:details-panel:flyout" onClose={[Function]} - size="s" + size="m" > <EuiWindowEvent event="keydown" @@ -287,7 +287,7 @@ Array [ data-eui="EuiFocusTrap" > <div - className="euiFlyout euiFlyout--small euiFlyout--paddingLarge c0" + className="euiFlyout euiFlyout--medium euiFlyout--paddingLarge c0" data-test-subj="timeline:details-panel:flyout" role="dialog" tabIndex={0} @@ -509,9 +509,9 @@ Array [ </EuiFlyout> </Styled(EuiFlyout)>, .c1 { - -webkit-flex: 0; - -ms-flex: 0; - flex: 0; + -webkit-flex: 0 1 auto; + -ms-flex: 0 1 auto; + flex: 0 1 auto; } .c2 .euiFlyoutBody__overflow { @@ -541,7 +541,7 @@ Array [ className="c0" data-test-subj="timeline:details-panel:flyout" onClose={[Function]} - size="s" + size="m" > <EuiWindowEvent event="keydown" @@ -554,7 +554,7 @@ Array [ data-eui="EuiFocusTrap" > <div - className="euiFlyout euiFlyout--small euiFlyout--paddingLarge c0" + className="euiFlyout euiFlyout--medium euiFlyout--paddingLarge c0" data-test-subj="timeline:details-panel:flyout" role="dialog" tabIndex={0} @@ -775,9 +775,9 @@ Array [ </EuiFocusTrap> </EuiFlyout>, .c1 { - -webkit-flex: 0; - -ms-flex: 0; - flex: 0; + -webkit-flex: 0 1 auto; + -ms-flex: 0 1 auto; + flex: 0 1 auto; } .c2 .euiFlyoutBody__overflow { @@ -804,7 +804,7 @@ Array [ } <div - className="euiFlyout euiFlyout--small euiFlyout--paddingLarge c0" + className="euiFlyout euiFlyout--medium euiFlyout--paddingLarge c0" data-test-subj="timeline:details-panel:flyout" role="dialog" tabIndex={0} diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/expandable_event.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/expandable_event.tsx index 6e8238dfe4b25..76f141ae05345 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/expandable_event.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/expandable_event.tsx @@ -51,7 +51,7 @@ interface ExpandableEventTitleProps { } const StyledEuiFlexGroup = styled(EuiFlexGroup)` - flex: 0; + flex: 0 1 auto; `; const StyledFlexGroup = styled(EuiFlexGroup)` diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/__snapshots__/expandable_host.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/__snapshots__/expandable_host.test.tsx.snap new file mode 100644 index 0000000000000..e42b5263189dc --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/__snapshots__/expandable_host.test.tsx.snap @@ -0,0 +1,669 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Expandable Host Component ExpandableHostDetails: rendering it should render the HostOverview of the ExpandableHostDetails 1`] = ` +<ExpandableHostDetails + contextID="text-context" + hostName="testHostName" +> + <Connect(HostOverviewByNameComponentQuery) + endDate="2020-07-08T08:20:18.966Z" + hostName="testHostName" + indexNames={ + Array [ + "IShouldBeUsed", + ] + } + skip={false} + sourceId="default" + startDate="2020-07-07T08:20:18.966Z" + > + <HostOverviewByNameComponentQuery + dispatch={[Function]} + endDate="2020-07-08T08:20:18.966Z" + hostName="testHostName" + indexNames={ + Array [ + "IShouldBeUsed", + ] + } + isInspected={false} + skip={false} + sourceId="default" + startDate="2020-07-07T08:20:18.966Z" + > + <Query + fetchPolicy="cache-and-network" + notifyOnNetworkStatusChange={true} + query={ + Object { + "definitions": Array [ + Object { + "directives": Array [], + "kind": "OperationDefinition", + "name": Object { + "kind": "Name", + "value": "GetHostOverviewQuery", + }, + "operation": "query", + "selectionSet": Object { + "kind": "SelectionSet", + "selections": Array [ + Object { + "alias": undefined, + "arguments": Array [ + Object { + "kind": "Argument", + "name": Object { + "kind": "Name", + "value": "id", + }, + "value": Object { + "kind": "Variable", + "name": Object { + "kind": "Name", + "value": "sourceId", + }, + }, + }, + ], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "source", + }, + "selectionSet": Object { + "kind": "SelectionSet", + "selections": Array [ + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "id", + }, + "selectionSet": undefined, + }, + Object { + "alias": undefined, + "arguments": Array [ + Object { + "kind": "Argument", + "name": Object { + "kind": "Name", + "value": "hostName", + }, + "value": Object { + "kind": "Variable", + "name": Object { + "kind": "Name", + "value": "hostName", + }, + }, + }, + Object { + "kind": "Argument", + "name": Object { + "kind": "Name", + "value": "timerange", + }, + "value": Object { + "kind": "Variable", + "name": Object { + "kind": "Name", + "value": "timerange", + }, + }, + }, + Object { + "kind": "Argument", + "name": Object { + "kind": "Name", + "value": "defaultIndex", + }, + "value": Object { + "kind": "Variable", + "name": Object { + "kind": "Name", + "value": "defaultIndex", + }, + }, + }, + ], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "HostOverview", + }, + "selectionSet": Object { + "kind": "SelectionSet", + "selections": Array [ + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "_id", + }, + "selectionSet": undefined, + }, + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "agent", + }, + "selectionSet": Object { + "kind": "SelectionSet", + "selections": Array [ + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "id", + }, + "selectionSet": undefined, + }, + ], + }, + }, + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "host", + }, + "selectionSet": Object { + "kind": "SelectionSet", + "selections": Array [ + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "architecture", + }, + "selectionSet": undefined, + }, + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "id", + }, + "selectionSet": undefined, + }, + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "ip", + }, + "selectionSet": undefined, + }, + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "mac", + }, + "selectionSet": undefined, + }, + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "name", + }, + "selectionSet": undefined, + }, + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "os", + }, + "selectionSet": Object { + "kind": "SelectionSet", + "selections": Array [ + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "family", + }, + "selectionSet": undefined, + }, + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "name", + }, + "selectionSet": undefined, + }, + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "platform", + }, + "selectionSet": undefined, + }, + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "version", + }, + "selectionSet": undefined, + }, + ], + }, + }, + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "type", + }, + "selectionSet": undefined, + }, + ], + }, + }, + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "cloud", + }, + "selectionSet": Object { + "kind": "SelectionSet", + "selections": Array [ + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "instance", + }, + "selectionSet": Object { + "kind": "SelectionSet", + "selections": Array [ + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "id", + }, + "selectionSet": undefined, + }, + ], + }, + }, + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "machine", + }, + "selectionSet": Object { + "kind": "SelectionSet", + "selections": Array [ + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "type", + }, + "selectionSet": undefined, + }, + ], + }, + }, + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "provider", + }, + "selectionSet": undefined, + }, + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "region", + }, + "selectionSet": undefined, + }, + ], + }, + }, + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [ + Object { + "arguments": Array [ + Object { + "kind": "Argument", + "name": Object { + "kind": "Name", + "value": "if", + }, + "value": Object { + "kind": "Variable", + "name": Object { + "kind": "Name", + "value": "inspect", + }, + }, + }, + ], + "kind": "Directive", + "name": Object { + "kind": "Name", + "value": "include", + }, + }, + ], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "inspect", + }, + "selectionSet": Object { + "kind": "SelectionSet", + "selections": Array [ + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "dsl", + }, + "selectionSet": undefined, + }, + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "response", + }, + "selectionSet": undefined, + }, + ], + }, + }, + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "endpoint", + }, + "selectionSet": Object { + "kind": "SelectionSet", + "selections": Array [ + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "endpointPolicy", + }, + "selectionSet": undefined, + }, + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "policyStatus", + }, + "selectionSet": undefined, + }, + Object { + "alias": undefined, + "arguments": Array [], + "directives": Array [], + "kind": "Field", + "name": Object { + "kind": "Name", + "value": "sensorVersion", + }, + "selectionSet": undefined, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + "variableDefinitions": Array [ + Object { + "defaultValue": undefined, + "kind": "VariableDefinition", + "type": Object { + "kind": "NonNullType", + "type": Object { + "kind": "NamedType", + "name": Object { + "kind": "Name", + "value": "ID", + }, + }, + }, + "variable": Object { + "kind": "Variable", + "name": Object { + "kind": "Name", + "value": "sourceId", + }, + }, + }, + Object { + "defaultValue": undefined, + "kind": "VariableDefinition", + "type": Object { + "kind": "NonNullType", + "type": Object { + "kind": "NamedType", + "name": Object { + "kind": "Name", + "value": "String", + }, + }, + }, + "variable": Object { + "kind": "Variable", + "name": Object { + "kind": "Name", + "value": "hostName", + }, + }, + }, + Object { + "defaultValue": undefined, + "kind": "VariableDefinition", + "type": Object { + "kind": "NonNullType", + "type": Object { + "kind": "NamedType", + "name": Object { + "kind": "Name", + "value": "TimerangeInput", + }, + }, + }, + "variable": Object { + "kind": "Variable", + "name": Object { + "kind": "Name", + "value": "timerange", + }, + }, + }, + Object { + "defaultValue": undefined, + "kind": "VariableDefinition", + "type": Object { + "kind": "NonNullType", + "type": Object { + "kind": "ListType", + "type": Object { + "kind": "NonNullType", + "type": Object { + "kind": "NamedType", + "name": Object { + "kind": "Name", + "value": "String", + }, + }, + }, + }, + }, + "variable": Object { + "kind": "Variable", + "name": Object { + "kind": "Name", + "value": "defaultIndex", + }, + }, + }, + Object { + "defaultValue": undefined, + "kind": "VariableDefinition", + "type": Object { + "kind": "NonNullType", + "type": Object { + "kind": "NamedType", + "name": Object { + "kind": "Name", + "value": "Boolean", + }, + }, + }, + "variable": Object { + "kind": "Variable", + "name": Object { + "kind": "Name", + "value": "inspect", + }, + }, + }, + ], + }, + ], + "kind": "Document", + "loc": Object { + "end": 930, + "start": 0, + }, + } + } + skip={false} + variables={ + Object { + "defaultIndex": Array [ + "IShouldBeUsed", + ], + "hostName": "testHostName", + "inspect": false, + "sourceId": "default", + "timerange": Object { + "from": "2020-07-07T08:20:18.966Z", + "interval": "12h", + "to": "2020-07-08T08:20:18.966Z", + }, + } + } + /> + </HostOverviewByNameComponentQuery> + </Connect(HostOverviewByNameComponentQuery)> +</ExpandableHostDetails> +`; diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/expandable_host.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/expandable_host.test.tsx new file mode 100644 index 0000000000000..2ce7090a5b83a --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/expandable_host.test.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 { mount } from 'enzyme'; +import React from 'react'; + +import '../../../../common/mock/match_media'; +import { + apolloClientObservable, + mockGlobalState, + TestProviders, + SUB_PLUGINS_REDUCER, + kibanaObservable, + createSecuritySolutionStorageMock, +} from '../../../../common/mock'; +import { createStore, State } from '../../../../common/store'; +import { ExpandableHostDetails } from './expandable_host'; + +jest.mock('react-apollo', () => { + const original = jest.requireActual('react-apollo'); + return { + ...original, + // eslint-disable-next-line react/display-name + Query: () => <></>, + }; +}); + +describe('Expandable Host Component', () => { + const state: State = { + ...mockGlobalState, + sourcerer: { + ...mockGlobalState.sourcerer, + configIndexPatterns: ['IShouldBeUsed'], + }, + }; + + const { storage } = createSecuritySolutionStorageMock(); + const store = createStore( + state, + SUB_PLUGINS_REDUCER, + apolloClientObservable, + kibanaObservable, + storage + ); + + const mockProps = { + contextID: 'text-context', + hostName: 'testHostName', + }; + + describe('ExpandableHostDetails: rendering', () => { + test('it should render the HostOverview of the ExpandableHostDetails', () => { + const wrapper = mount( + <TestProviders store={store}> + <ExpandableHostDetails {...mockProps} /> + </TestProviders> + ); + + expect(wrapper.find('ExpandableHostDetails')).toMatchSnapshot(); + }); + + test('it should render the HostOverview of the ExpandableHostDetails with the correct indices', () => { + const wrapper = mount( + <TestProviders store={store}> + <ExpandableHostDetails {...mockProps} /> + </TestProviders> + ); + + expect(wrapper.find('HostOverviewByNameComponentQuery').prop('indexNames')).toStrictEqual([ + 'IShouldBeUsed', + ]); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/expandable_host.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/expandable_host.tsx index 8fce9a186bbd4..78367d17d7b62 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/expandable_host.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/expandable_host.tsx @@ -5,10 +5,11 @@ * 2.0. */ -import React from 'react'; +import React, { useMemo } from 'react'; import styled from 'styled-components'; import { i18n } from '@kbn/i18n'; import { EuiTitle } from '@elastic/eui'; +import { sourcererSelectors } from '../../../../common/store/sourcerer'; import { HostDetailsLink } from '../../../../common/components/links'; import { useGlobalTime } from '../../../../common/containers/use_global_time'; import { useSourcererScope } from '../../../../common/containers/sourcerer'; @@ -19,6 +20,7 @@ import { AnomalyTableProvider } from '../../../../common/components/ml/anomaly/a import { hostToCriteria } from '../../../../common/components/ml/criteria/host_to_criteria'; import { scoreIntervalToDateTime } from '../../../../common/components/ml/score/score_interval_to_datetime'; import { HostOverviewByNameQuery } from '../../../../hosts/containers/hosts/details'; +import { useDeepEqualSelector } from '../../../../common/hooks/use_selector'; interface ExpandableHostProps { hostName: string; @@ -54,10 +56,25 @@ export const ExpandableHostDetails = ({ hostName, }: ExpandableHostProps & { contextID: string }) => { const { to, from, isInitializing } = useGlobalTime(); - const { docValueFields, selectedPatterns } = useSourcererScope(); + const { docValueFields } = useSourcererScope(); + /* + Normally `selectedPatterns` from useSourcerScope would be where we obtain the indices, + but those indices are only loaded when viewing the pages where the sourcerer is initialized (i.e. Hosts and Overview) + When a user goes directly to the detections page, the patterns have not been loaded yet + as that information isn't used for the detections page. With this details component being accessible + from the detections page, the decision was made to get all existing index names to account for this. + Otherwise, an empty array is defaulted for the `indexNames` in the query which leads to inconsistencies in the data returned + (i.e. extraneous endpoint data is retrieved from the backend leading to endpoint data not being returned) + */ + const allExistingIndexNamesSelector = useMemo( + () => sourcererSelectors.getAllExistingIndexNamesSelector(), + [] + ); + const allPatterns = useDeepEqualSelector<string[]>(allExistingIndexNamesSelector); + return ( <HostOverviewByNameQuery - indexNames={selectedPatterns} + indexNames={allPatterns} sourceId="default" hostName={hostName} skip={isInitializing} @@ -80,7 +97,7 @@ export const ExpandableHostDetails = ({ data={hostOverview as HostItem} anomaliesData={anomaliesData} isLoadingAnomaliesData={isLoadingAnomaliesData} - indexNames={selectedPatterns} + indexNames={allPatterns} loading={loading} startDate={from} endDate={to} diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/index.tsx index 39064cda16001..d8bb9c8d27d09 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/host_details/index.tsx @@ -35,25 +35,26 @@ const StyledEuiFlyoutBody = styled(EuiFlyoutBody)` flex: 1; overflow-x: hidden; overflow-y: scroll; - padding: ${({ theme }) => `${theme.eui.paddingSizes.xs} ${theme.eui.paddingSizes.m} 64px`}; + margin-bottom: ${({ theme }) => `${theme.eui.paddingSizes.l}`}; + padding: ${({ theme }) => `${theme.eui.paddingSizes.xs} ${theme.eui.paddingSizes.m} 0px`}; } } `; const StyledEuiFlexGroup = styled(EuiFlexGroup)` - flex: 0; -`; - -const StyledEuiFlexItem = styled(EuiFlexItem)` - &.euiFlexItem { - flex: 1 0 0; - overflow-y: scroll; - overflow-x: hidden; - } + flex: 1 0 auto; `; const StyledEuiFlexButtonWrapper = styled(EuiFlexItem)` align-self: flex-start; + flex: 1 0 auto; +`; + +const StyledPanelContent = styled.div` + display: block; + height: 100%; + overflow-y: scroll; + overflow-x: hidden; `; interface HostDetailsProps { @@ -107,9 +108,9 @@ export const HostDetailsPanel: React.FC<HostDetailsProps> = React.memo( <ExpandableHostDetailsPageLink hostName={hostName} /> </StyledEuiFlexButtonWrapper> <EuiSpacer size="m" /> - <StyledEuiFlexItem grow={true}> + <StyledPanelContent> <ExpandableHostDetails contextID={contextID} hostName={hostName} /> - </StyledEuiFlexItem> + </StyledPanelContent> </> ); } diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.tsx index 0482491562f57..177cd2e5ded41 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.tsx @@ -7,7 +7,7 @@ import React, { useCallback, useMemo } from 'react'; import { useDispatch } from 'react-redux'; -import { EuiFlyout } from '@elastic/eui'; +import { EuiFlyout, EuiFlyoutProps } from '@elastic/eui'; import styled from 'styled-components'; import { timelineActions, timelineSelectors } from '../../store/timeline'; import { timelineDefaults } from '../../store/timeline/defaults'; @@ -69,9 +69,10 @@ export const DetailsPanel = React.memo( if (!currentTabDetail?.panelView) return null; let visiblePanel = null; // store in variable to make return statement more readable + let panelSize: EuiFlyoutProps['size'] = 's'; const contextID = `${timelineId}-${activeTab}`; - if (currentTabDetail?.panelView === 'eventDetail' && currentTabDetail?.params?.eventId) { + panelSize = 'm'; visiblePanel = ( <EventDetailsPanel browserFields={browserFields} @@ -108,7 +109,11 @@ export const DetailsPanel = React.memo( } return isFlyoutView ? ( - <StyledEuiFlyout data-test-subj="timeline:details-panel:flyout" size="s" onClose={closePanel}> + <StyledEuiFlyout + data-test-subj="timeline:details-panel:flyout" + size={panelSize} + onClose={closePanel} + > {visiblePanel} </StyledEuiFlyout> ) : ( diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/index.tsx index e05c9435fc456..ea857da926f84 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/index.tsx @@ -42,19 +42,19 @@ const StyledEuiFlyoutBody = styled(EuiFlyoutBody)` `; const StyledEuiFlexGroup = styled(EuiFlexGroup)` - flex: 0; -`; - -const StyledEuiFlexItem = styled(EuiFlexItem)` - &.euiFlexItem { - flex: 1 0 0; - overflow-y: scroll; - overflow-x: hidden; - } + flex: 1 0 auto; `; const StyledEuiFlexButtonWrapper = styled(EuiFlexItem)` align-self: flex-start; + flex: 1 0 auto; +`; + +const StyledPanelContent = styled.div` + display: block; + height: 100%; + overflow-y: scroll; + overflow-x: hidden; `; interface NetworkDetailsProps { @@ -104,9 +104,9 @@ export const NetworkDetailsPanel = React.memo( <ExpandableNetworkDetailsPageLink expandedNetwork={expandedNetwork} /> </StyledEuiFlexButtonWrapper> <EuiSpacer size="m" /> - <StyledEuiFlexItem grow={true}> + <StyledPanelContent> <ExpandableNetworkDetails contextID={contextID} expandedNetwork={expandedNetwork} /> - </StyledEuiFlexItem> + </StyledPanelContent> </> ); } diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.tsx index bec241e10d613..ece28faedb951 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.tsx @@ -86,6 +86,7 @@ export const HeaderComponent: React.FC<Props> = ({ getManageTimelineById, timelineId, ]); + const showSortingCapability = !isEqlOn && !(header.subType && header.subType.nested); return ( <> @@ -94,7 +95,7 @@ export const HeaderComponent: React.FC<Props> = ({ isLoading={isLoading} isResizing={false} onClick={onColumnSort} - showSortingCapability={!isEqlOn} + showSortingCapability={showSortingCapability} sort={sort} > <Actions diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/__snapshots__/index.test.tsx.snap index 8f514ca49e848..72d2956bd4086 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/__snapshots__/index.test.tsx.snap @@ -69,7 +69,7 @@ exports[`Columns it renders the expected columns 1`] = ` fieldFormat="" fieldName="event.category" fieldType="" - key="plain-column-renderer-formatted-field-value-test-event.category-1-event.category-Access" + key="plain-column-renderer-formatted-field-value-test-event.category-1-event.category-Access-0" truncate={true} value="Access" /> @@ -99,7 +99,7 @@ exports[`Columns it renders the expected columns 1`] = ` fieldFormat="" fieldName="event.action" fieldType="" - key="plain-column-renderer-formatted-field-value-test-event.action-1-event.action-Action" + key="plain-column-renderer-formatted-field-value-test-event.action-1-event.action-Action-0" truncate={true} value="Action" /> @@ -129,7 +129,7 @@ exports[`Columns it renders the expected columns 1`] = ` fieldFormat="" fieldName="host.name" fieldType="" - key="plain-column-renderer-formatted-field-value-test-host.name-1-host.name-apache" + key="plain-column-renderer-formatted-field-value-test-host.name-1-host.name-apache-0" truncate={true} value="apache" /> @@ -159,7 +159,7 @@ exports[`Columns it renders the expected columns 1`] = ` fieldFormat="" fieldName="source.ip" fieldType="" - key="plain-column-renderer-formatted-field-value-test-source.ip-1-source.ip-192.168.0.1" + key="plain-column-renderer-formatted-field-value-test-source.ip-1-source.ip-192.168.0.1-0" truncate={true} value="192.168.0.1" /> @@ -189,7 +189,7 @@ exports[`Columns it renders the expected columns 1`] = ` fieldFormat="" fieldName="destination.ip" fieldType="" - key="plain-column-renderer-formatted-field-value-test-destination.ip-1-destination.ip-192.168.0.3" + key="plain-column-renderer-formatted-field-value-test-destination.ip-1-destination.ip-192.168.0.3-0" truncate={true} value="192.168.0.3" /> @@ -219,7 +219,7 @@ exports[`Columns it renders the expected columns 1`] = ` fieldFormat="" fieldName="user.name" fieldType="" - key="plain-column-renderer-formatted-field-value-test-user.name-1-user.name-john.dee" + key="plain-column-renderer-formatted-field-value-test-user.name-1-user.name-john.dee-0" truncate={true} value="john.dee" /> diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/__snapshots__/get_column_renderer.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/__snapshots__/get_column_renderer.test.tsx.snap index e2c46a07af8cc..4da4e12e0f7b3 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/__snapshots__/get_column_renderer.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/__snapshots__/get_column_renderer.test.tsx.snap @@ -8,7 +8,7 @@ exports[`get_column_renderer renders correctly against snapshot 1`] = ` fieldFormat="" fieldName="event.severity" fieldType="" - key="plain-column-renderer-formatted-field-value-test-event.severity-1-message-3" + key="plain-column-renderer-formatted-field-value-test-event.severity-1-message-3-0" value="3" /> </span> diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/__snapshots__/plain_column_renderer.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/__snapshots__/plain_column_renderer.test.tsx.snap index 8ea7708bf5907..13912e6ad3da9 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/__snapshots__/plain_column_renderer.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/__snapshots__/plain_column_renderer.test.tsx.snap @@ -8,7 +8,7 @@ exports[`plain_column_renderer rendering renders correctly against snapshot 1`] fieldFormat="" fieldName="event.category" fieldType="keyword" - key="plain-column-renderer-formatted-field-value-test-event.category-1-event.category-Access" + key="plain-column-renderer-formatted-field-value-test-event.category-1-event.category-Access-0" value="Access" /> </span> diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/formatted_field.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/formatted_field.tsx index fa3612f08204d..3032f556251f3 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/formatted_field.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/formatted_field.tsx @@ -41,14 +41,27 @@ const columnNamesNotDraggable = [MESSAGE_FIELD_NAME]; const FormattedFieldValueComponent: React.FC<{ contextId: string; eventId: string; + isObjectArray?: boolean; fieldFormat?: string; fieldName: string; fieldType: string; truncate?: boolean; value: string | number | undefined | null; linkValue?: string | null | undefined; -}> = ({ contextId, eventId, fieldFormat, fieldName, fieldType, truncate, value, linkValue }) => { - if (fieldType === IP_FIELD_TYPE) { +}> = ({ + contextId, + eventId, + fieldFormat, + fieldName, + fieldType, + isObjectArray = false, + truncate, + value, + linkValue, +}) => { + if (isObjectArray) { + return <>{value}</>; + } else if (fieldType === IP_FIELD_TYPE) { return ( <FormattedIp eventId={eventId} diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/plain_column_renderer.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/plain_column_renderer.tsx index 27caf5c974387..a2b7750d9bb59 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/plain_column_renderer.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/plain_column_renderer.tsx @@ -40,9 +40,9 @@ export const plainColumnRenderer: ColumnRenderer = { linkValues?: string[] | null | undefined; }) => values != null - ? values.map((value) => ( + ? values.map((value, i) => ( <FormattedFieldValue - key={`plain-column-renderer-formatted-field-value-${timelineId}-${columnName}-${eventId}-${field.id}-${value}`} + key={`plain-column-renderer-formatted-field-value-${timelineId}-${columnName}-${eventId}-${field.id}-${value}-${i}`} contextId={`plain-column-renderer-formatted-field-value-${timelineId}`} eventId={eventId} fieldFormat={field.format || ''} diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/model.ts b/x-pack/plugins/security_solution/public/timelines/store/timeline/model.ts index eb7da5fa679d0..b1ff4a1e89729 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/model.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/model.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Filter } from '../../../../../../../src/plugins/data/public'; +import { Filter, IFieldSubType } from '../../../../../../../src/plugins/data/public'; import { DataProvider } from '../../components/timeline/data_providers/data_provider'; import { Sort } from '../../components/timeline/body/sort'; @@ -43,6 +43,7 @@ export interface ColumnHeaderOptions { label?: string; linkField?: string; placeholder?: string; + subType?: IFieldSubType; type?: string; width: number; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/queries/query_with_max_signals.json b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/queries/query_with_max_signals.json new file mode 100644 index 0000000000000..d03eb8e2366ae --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/queries/query_with_max_signals.json @@ -0,0 +1,9 @@ +{ + "name": "Query With Max Signals", + "description": "Simplest query with max signals set to something other than default", + "risk_score": 1, + "severity": "high", + "type": "query", + "query": "user.name: root or user.name: admin", + "max_signals": 500 +} diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts index 4bded347c32ea..f81f4c5a2c537 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts @@ -215,6 +215,7 @@ export const signalRulesAlertType = ({ hasTimestampFields( wroteStatus, hasTimestampOverride ? (timestampOverride as string) : '@timestamp', + name, timestampFieldCaps, inputIndices, ruleStatusService, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts index 0a581816ee82f..375f8c4ccc824 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts @@ -814,6 +814,7 @@ describe('utils', () => { const res = await hasTimestampFields( false, timestampField, + 'myfakerulename', // eslint-disable-next-line @typescript-eslint/no-explicit-any timestampFieldCapsResponse as ApiResponse<Record<string, any>>, ['myfa*'], @@ -854,6 +855,7 @@ describe('utils', () => { const res = await hasTimestampFields( false, timestampField, + 'myfakerulename', // eslint-disable-next-line @typescript-eslint/no-explicit-any timestampFieldCapsResponse as ApiResponse<Record<string, any>>, ['myfa*'], @@ -866,6 +868,60 @@ describe('utils', () => { ); expect(res).toBeTruthy(); }); + + test('returns true when missing logs-endpoint.alerts-* index and rule name is Endpoint Security', async () => { + const timestampField = '@timestamp'; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const timestampFieldCapsResponse: Partial<ApiResponse<Record<string, any>, Context>> = { + body: { + indices: [], + fields: {}, + }, + }; + mockLogger.error.mockClear(); + const res = await hasTimestampFields( + false, + timestampField, + 'Endpoint Security', + // eslint-disable-next-line @typescript-eslint/no-explicit-any + timestampFieldCapsResponse as ApiResponse<Record<string, any>>, + ['logs-endpoint.alerts-*'], + ruleStatusServiceMock, + mockLogger, + buildRuleMessage + ); + expect(mockLogger.error).toHaveBeenCalledWith( + 'This rule is attempting to query data from Elasticsearch indices listed in the "Index pattern" section of the rule definition, however no index matching: ["logs-endpoint.alerts-*"] was found. This warning will continue to appear until a matching index is created or this rule is de-activated. If you have recently enrolled agents enabled with Endpoint Security through Fleet, this warning should stop once an alert is sent from an agent. name: "fake name" id: "fake id" rule id: "fake rule id" signals index: "fakeindex"' + ); + expect(res).toBeTruthy(); + }); + + test('returns true when missing logs-endpoint.alerts-* index and rule name is NOT Endpoint Security', async () => { + const timestampField = '@timestamp'; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const timestampFieldCapsResponse: Partial<ApiResponse<Record<string, any>, Context>> = { + body: { + indices: [], + fields: {}, + }, + }; + mockLogger.error.mockClear(); + const res = await hasTimestampFields( + false, + timestampField, + 'NOT Endpoint Security', + // eslint-disable-next-line @typescript-eslint/no-explicit-any + timestampFieldCapsResponse as ApiResponse<Record<string, any>>, + ['logs-endpoint.alerts-*'], + ruleStatusServiceMock, + mockLogger, + buildRuleMessage + ); + expect(mockLogger.error).toHaveBeenCalledWith( + 'This rule is attempting to query data from Elasticsearch indices listed in the "Index pattern" section of the rule definition, however no index matching: ["logs-endpoint.alerts-*"] was found. This warning will continue to appear until a matching index is created or this rule is de-activated. name: "fake name" id: "fake id" rule id: "fake rule id" signals index: "fakeindex"' + ); + expect(res).toBeTruthy(); + }); }); describe('wrapBuildingBlocks', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts index 2b306cd2a8d9d..aef9a5d470dcc 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts @@ -105,6 +105,7 @@ export const hasReadIndexPrivileges = async ( export const hasTimestampFields = async ( wroteStatus: boolean, timestampField: string, + ruleName: string, // any is derived from here // node_modules/@elastic/elasticsearch/api/kibana.d.ts // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -115,11 +116,15 @@ export const hasTimestampFields = async ( buildRuleMessage: BuildRuleMessage ): Promise<boolean> => { if (!wroteStatus && isEmpty(timestampFieldCapsResponse.body.indices)) { - const errorString = `The following index patterns did not match any indices: ${JSON.stringify( + const errorString = `This rule is attempting to query data from Elasticsearch indices listed in the "Index pattern" section of the rule definition, however no index matching: ${JSON.stringify( inputIndices - )}`; - logger.error(buildRuleMessage(errorString)); - await ruleStatusService.warning(errorString); + )} was found. This warning will continue to appear until a matching index is created or this rule is de-activated. ${ + ruleName === 'Endpoint Security' + ? 'If you have recently enrolled agents enabled with Endpoint Security through Fleet, this warning should stop once an alert is sent from an agent.' + : '' + }`; + logger.error(buildRuleMessage(errorString.trimEnd())); + await ruleStatusService.warning(errorString.trimEnd()); return true; } else if ( !wroteStatus && diff --git a/x-pack/plugins/security_solution/server/search_strategy/helpers/to_array.ts b/x-pack/plugins/security_solution/server/search_strategy/helpers/to_array.ts index 6e727a01b981a..fbb2b8d48a250 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/helpers/to_array.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/helpers/to_array.ts @@ -7,7 +7,6 @@ export const toArray = <T = string>(value: T | T[] | null): T[] => Array.isArray(value) ? value : value == null ? [] : [value]; - export const toStringArray = <T = string>(value: T | T[] | null): string[] => { if (Array.isArray(value)) { return value.reduce<string[]>((acc, v) => { @@ -42,3 +41,47 @@ export const toStringArray = <T = string>(value: T | T[] | null): string[] => { return [`${value}`]; } }; +export const toObjectArrayOfStrings = <T = string>( + value: T | T[] | null +): Array<{ + str: string; + isObjectArray?: boolean; +}> => { + if (Array.isArray(value)) { + return value.reduce< + Array<{ + str: string; + isObjectArray?: boolean; + }> + >((acc, v) => { + if (v != null) { + switch (typeof v) { + case 'number': + case 'boolean': + return [...acc, { str: v.toString() }]; + case 'object': + try { + return [...acc, { str: JSON.stringify(v), isObjectArray: true }]; // need to track when string is not a simple value + } catch { + return [...acc, { str: 'Invalid Object' }]; + } + case 'string': + return [...acc, { str: v }]; + default: + return [...acc, { str: `${v}` }]; + } + } + return acc; + }, []); + } else if (value == null) { + return []; + } else if (!Array.isArray(value) && typeof value === 'object') { + try { + return [{ str: JSON.stringify(value), isObjectArray: true }]; + } catch { + return [{ str: 'Invalid Object' }]; + } + } else { + return [{ str: `${value}` }]; + } +}; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/helpers.ts index 505f99dd28455..8b2397fd7fab0 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/helpers.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/helpers.ts @@ -11,7 +11,7 @@ import { hostFieldsMap } from '../../../../../../common/ecs/ecs_fields'; import { HostsEdges } from '../../../../../../common/search_strategy/security_solution/hosts'; import { HostAggEsItem, HostBuckets, HostValue } from '../../../../../lib/hosts/types'; -import { toStringArray } from '../../../../helpers/to_array'; +import { toObjectArrayOfStrings } from '../../../../helpers/to_array'; export const HOSTS_FIELDS: readonly string[] = [ '_id', @@ -33,7 +33,11 @@ export const formatHostEdgesData = ( flattenedFields.cursor.value = hostId || ''; const fieldValue = getHostFieldValue(fieldName, bucket); if (fieldValue != null) { - return set(`node.${fieldName}`, toStringArray(fieldValue), flattenedFields); + return set( + `node.${fieldName}`, + toObjectArrayOfStrings(fieldValue).map(({ str }) => str), + flattenedFields + ); } return flattenedFields; }, diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/helpers.ts index 06d81140f475e..aeaefe690cbde 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/helpers.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/helpers.ts @@ -8,7 +8,7 @@ import { get, getOr, isEmpty } from 'lodash/fp'; import { set } from '@elastic/safer-lodash-set/fp'; import { mergeFieldsWithHit } from '../../../../../utils/build_query'; -import { toStringArray } from '../../../../helpers/to_array'; +import { toObjectArrayOfStrings } from '../../../../helpers/to_array'; import { AuthenticationsEdges, AuthenticationHit, @@ -55,7 +55,11 @@ export const formatAuthenticationData = ( const fieldPath = `node.${fieldName}`; const fieldValue = get(fieldPath, mergedResult); if (!isEmpty(fieldValue)) { - return set(fieldPath, toStringArray(fieldValue), mergedResult); + return set( + fieldPath, + toObjectArrayOfStrings(fieldValue).map(({ str }) => str), + mergedResult + ); } else { return mergedResult; } diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts index 9c522bd704ef0..2b35517d693d5 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts @@ -9,7 +9,7 @@ import { set } from '@elastic/safer-lodash-set/fp'; import { get, has, head } from 'lodash/fp'; import { hostFieldsMap } from '../../../../../../common/ecs/ecs_fields'; import { HostItem } from '../../../../../../common/search_strategy/security_solution/hosts'; -import { toStringArray } from '../../../../helpers/to_array'; +import { toObjectArrayOfStrings } from '../../../../helpers/to_array'; import { HostAggEsItem, HostBuckets, HostValue } from '../../../../../lib/hosts/types'; @@ -42,7 +42,11 @@ export const formatHostItem = (bucket: HostAggEsItem): HostItem => if (fieldName === '_id') { return set('_id', fieldValue, flattenedFields); } - return set(fieldName, toStringArray(fieldValue), flattenedFields); + return set( + fieldName, + toObjectArrayOfStrings(fieldValue).map(({ str }) => str), + flattenedFields + ); } return flattenedFields; }, {}); diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/uncommon_processes/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/uncommon_processes/helpers.ts index 7b01f4e7dc816..fe202b48540d7 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/uncommon_processes/helpers.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/uncommon_processes/helpers.ts @@ -14,7 +14,7 @@ import { HostsUncommonProcessesEdges, HostsUncommonProcessHit, } from '../../../../../../common/search_strategy/security_solution/hosts/uncommon_processes'; -import { toStringArray } from '../../../../helpers/to_array'; +import { toObjectArrayOfStrings } from '../../../../helpers/to_array'; import { HostHits } from '../../../../../../common/search_strategy'; export const uncommonProcessesFields = [ @@ -82,7 +82,11 @@ export const formatUncommonProcessesData = ( fieldPath = `node.hosts.0.name`; fieldValue = get(fieldPath, mergedResult); } - return set(fieldPath, toStringArray(fieldValue), mergedResult); + return set( + fieldPath, + toObjectArrayOfStrings(fieldValue).map(({ str }) => str), + mergedResult + ); }, { node: { diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/details/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/details/helpers.ts index 3b387597618e8..8fc7ae0304a35 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/details/helpers.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/details/helpers.ts @@ -13,7 +13,7 @@ import { NetworkDetailsHostHit, NetworkHit, } from '../../../../../../common/search_strategy/security_solution/network'; -import { toStringArray } from '../../../../helpers/to_array'; +import { toObjectArrayOfStrings } from '../../../../helpers/to_array'; export const getNetworkDetailsAgg = (type: string, networkHit: NetworkHit | {}) => { const firstSeen = getOr(null, `firstSeen.value_as_string`, networkHit); @@ -53,7 +53,7 @@ const formatHostEcs = (data: Record<string, unknown> | null): HostEcs | null => } return { ...acc, - [key]: toStringArray(value), + [key]: toObjectArrayOfStrings(value).map(({ str }) => str), }; }, {}); }; diff --git a/x-pack/plugins/security_solution/server/search_strategy/timeline/eql/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/timeline/eql/helpers.ts index bdd3195b3b756..b007307412e95 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/timeline/eql/helpers.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/timeline/eql/helpers.ts @@ -7,7 +7,7 @@ import { EqlSearchStrategyResponse } from '../../../../../data_enhanced/common'; import { DEFAULT_MAX_TABLE_QUERY_SIZE } from '../../../../common/constants'; -import { EqlSearchResponse } from '../../../../common/detection_engine/types'; +import { EqlSearchResponse, EqlSequence } from '../../../../common/detection_engine/types'; import { EventHit, TimelineEdges } from '../../../../common/search_strategy'; import { TimelineEqlRequestOptions, @@ -56,51 +56,53 @@ export const buildEqlDsl = (options: TimelineEqlRequestOptions): Record<string, }, }; }; +const parseSequences = async (sequences: Array<EqlSequence<unknown>>, fieldRequested: string[]) => + sequences.reduce<Promise<TimelineEdges[]>>(async (acc, sequence, sequenceIndex) => { + const sequenceParentId = sequence.events[0]?._id ?? null; + const data = await acc; + const allData = await Promise.all( + sequence.events.map(async (event, eventIndex) => { + const item = await formatTimelineData( + fieldRequested, + TIMELINE_EVENTS_FIELDS, + event as EventHit + ); + return Promise.resolve({ + ...item, + node: { + ...item.node, + ecs: { + ...item.node.ecs, + ...(sequenceParentId != null + ? { + eql: { + parentId: sequenceParentId, + sequenceNumber: `${sequenceIndex}-${eventIndex}`, + }, + } + : {}), + }, + }, + }); + }) + ); + return Promise.resolve([...data, ...allData]); + }, Promise.resolve([])); -export const parseEqlResponse = ( +export const parseEqlResponse = async ( options: TimelineEqlRequestOptions, response: EqlSearchStrategyResponse<EqlSearchResponse<unknown>> ): Promise<TimelineEqlResponse> => { const { activePage, querySize } = options.pagination; - // const totalCount = response.rawResponse?.body?.hits?.total?.value ?? 0; let edges: TimelineEdges[] = []; + if (response.rawResponse.body.hits.sequences !== undefined) { - edges = response.rawResponse.body.hits.sequences.reduce<TimelineEdges[]>( - (data, sequence, sequenceIndex) => { - const sequenceParentId = sequence.events[0]?._id ?? null; - return [ - ...data, - ...sequence.events.map((event, eventIndex) => { - const item = formatTimelineData( - options.fieldRequested, - TIMELINE_EVENTS_FIELDS, - event as EventHit - ); - return { - ...item, - node: { - ...item.node, - ecs: { - ...item.node.ecs, - ...(sequenceParentId != null - ? { - eql: { - parentId: sequenceParentId, - sequenceNumber: `${sequenceIndex}-${eventIndex}`, - }, - } - : {}), - }, - }, - }; - }), - ]; - }, - [] - ); + edges = await parseSequences(response.rawResponse.body.hits.sequences, options.fieldRequested); } else if (response.rawResponse.body.hits.events !== undefined) { - edges = response.rawResponse.body.hits.events.map((event) => - formatTimelineData(options.fieldRequested, TIMELINE_EVENTS_FIELDS, event as EventHit) + edges = await Promise.all( + response.rawResponse.body.hits.events.map(async (event) => + formatTimelineData(options.fieldRequested, TIMELINE_EVENTS_FIELDS, event as EventHit) + ) ); } diff --git a/x-pack/plugins/security_solution/server/search_strategy/timeline/eql/index.ts b/x-pack/plugins/security_solution/server/search_strategy/timeline/eql/index.ts index cf7877e987ace..249f5582d2a39 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/timeline/eql/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/timeline/eql/index.ts @@ -38,7 +38,7 @@ export const securitySolutionTimelineEqlSearchStrategyProvider = ( }, }; }), - mergeMap((esSearchRes) => + mergeMap(async (esSearchRes) => parseEqlResponse( request, (esSearchRes as unknown) as EqlSearchStrategyResponse<EqlSearchResponse<unknown>> diff --git a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/helpers.test.ts b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/helpers.test.ts index 10bb606dc2387..61af6a7664faa 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/helpers.test.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/helpers.test.ts @@ -8,54 +8,23 @@ import { EventHit } from '../../../../../../common/search_strategy'; import { TIMELINE_EVENTS_FIELDS } from './constants'; import { formatTimelineData } from './helpers'; +import { eventHit } from '../mocks'; describe('#formatTimelineData', () => { - it('happy path', () => { - const response: EventHit = { - _index: 'auditbeat-7.8.0-2020.11.05-000003', - _id: 'tkCt1nUBaEgqnrVSZ8R_', - _score: 0, - _type: '', - fields: { - 'event.category': ['process'], - 'process.ppid': [3977], - 'user.name': ['jenkins'], - 'process.args': ['go', 'vet', './...'], - message: ['Process go (PID: 4313) by user jenkins STARTED'], - 'process.pid': [4313], - 'process.working_directory': [ - '/var/lib/jenkins/workspace/Beats_beats_PR-22624/src/github.com/elastic/beats/libbeat', - ], - 'process.entity_id': ['Z59cIkAAIw8ZoK0H'], - 'host.ip': ['10.224.1.237', 'fe80::4001:aff:fee0:1ed', '172.17.0.1'], - 'process.name': ['go'], - 'event.action': ['process_started'], - 'agent.type': ['auditbeat'], - '@timestamp': ['2020-11-17T14:48:08.922Z'], - 'event.module': ['system'], - 'event.type': ['start'], - 'host.name': ['beats-ci-immutable-ubuntu-1804-1605624279743236239'], - 'process.hash.sha1': ['1eac22336a41e0660fb302add9d97daa2bcc7040'], - 'host.os.family': ['debian'], - 'event.kind': ['event'], - 'host.id': ['e59991e835905c65ed3e455b33e13bd6'], - 'event.dataset': ['process'], - 'process.executable': [ - '/var/lib/jenkins/workspace/Beats_beats_PR-22624/.gvm/versions/go1.14.7.linux.amd64/bin/go', - ], - }, - _source: {}, - sort: ['1605624488922', 'beats-ci-immutable-ubuntu-1804-1605624279743236239'], - aggregations: {}, - }; - - expect( - formatTimelineData( - ['@timestamp', 'host.name', 'destination.ip', 'source.ip'], - TIMELINE_EVENTS_FIELDS, - response - ) - ).toEqual({ + it('happy path', async () => { + const res = await formatTimelineData( + [ + '@timestamp', + 'host.name', + 'destination.ip', + 'source.ip', + 'source.geo.location', + 'threat.indicator.matched.field', + ], + TIMELINE_EVENTS_FIELDS, + eventHit + ); + expect(res).toEqual({ cursor: { tiebreaker: 'beats-ci-immutable-ubuntu-1804-1605624279743236239', value: '1605624488922', @@ -72,6 +41,14 @@ describe('#formatTimelineData', () => { field: 'host.name', value: ['beats-ci-immutable-ubuntu-1804-1605624279743236239'], }, + { + field: 'source.geo.location', + value: [`{"lon":118.7778,"lat":32.0617}`], + }, + { + field: 'threat.indicator.matched.field', + value: ['matched_field', 'matched_field_2'], + }, ], ecs: { '@timestamp': ['2020-11-17T14:48:08.922Z'], @@ -122,7 +99,7 @@ describe('#formatTimelineData', () => { }); }); - it('rule signal results', () => { + it('rule signal results', async () => { const response: EventHit = { _index: '.siem-signals-patrykkopycinski-default-000007', _id: 'a77040f198355793c35bf22b900902371309be615381f0a2ec92c208b6132562', @@ -290,7 +267,7 @@ describe('#formatTimelineData', () => { }; expect( - formatTimelineData( + await formatTimelineData( ['@timestamp', 'host.name', 'destination.ip', 'source.ip'], TIMELINE_EVENTS_FIELDS, response diff --git a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/helpers.ts index 1a83cbf40f1f4..e5bb8cb7e14b7 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/helpers.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/helpers.ts @@ -6,9 +6,13 @@ */ import { get, has, merge, uniq } from 'lodash/fp'; -import { EventHit, TimelineEdges } from '../../../../../../common/search_strategy'; +import { + EventHit, + TimelineEdges, + TimelineNonEcsData, +} from '../../../../../../common/search_strategy'; import { toStringArray } from '../../../../helpers/to_array'; -import { formatGeoLocation, isGeoField } from '../details/helpers'; +import { getDataSafety, getDataFromFieldsHits } from '../details/helpers'; const getTimestamp = (hit: EventHit): string => { if (hit.fields && hit.fields['@timestamp']) { @@ -19,13 +23,14 @@ const getTimestamp = (hit: EventHit): string => { return ''; }; -export const formatTimelineData = ( +export const formatTimelineData = async ( dataFields: readonly string[], ecsFields: readonly string[], hit: EventHit ) => - uniq([...ecsFields, ...dataFields]).reduce<TimelineEdges>( - (flattenedFields, fieldName) => { + uniq([...ecsFields, ...dataFields]).reduce<Promise<TimelineEdges>>( + async (acc, fieldName) => { + const flattenedFields: TimelineEdges = await acc; flattenedFields.node._id = hit._id; flattenedFields.node._index = hit._index; flattenedFields.node.ecs._id = hit._id; @@ -35,30 +40,81 @@ export const formatTimelineData = ( flattenedFields.cursor.value = hit.sort[0]; flattenedFields.cursor.tiebreaker = hit.sort[1]; } - return mergeTimelineFieldsWithHit(fieldName, flattenedFields, hit, dataFields, ecsFields); + const waitForIt = await mergeTimelineFieldsWithHit( + fieldName, + flattenedFields, + hit, + dataFields, + ecsFields + ); + return Promise.resolve(waitForIt); }, - { + Promise.resolve({ node: { ecs: { _id: '' }, data: [], _id: '', _index: '' }, cursor: { value: '', tiebreaker: null, }, - } + }) ); const specialFields = ['_id', '_index', '_type', '_score']; -const mergeTimelineFieldsWithHit = <T>( +const getValuesFromFields = async ( + fieldName: string, + hit: EventHit, + nestedParentFieldName?: string +): Promise<TimelineNonEcsData[]> => { + if (specialFields.includes(fieldName)) { + return [{ field: fieldName, value: toStringArray(get(fieldName, hit)) }]; + } + + let fieldToEval; + if (has(fieldName, hit._source)) { + fieldToEval = { + [fieldName]: get(fieldName, hit._source), + }; + } else { + if (nestedParentFieldName == null || nestedParentFieldName === fieldName) { + fieldToEval = { + [fieldName]: hit.fields[fieldName], + }; + } else if (nestedParentFieldName != null) { + fieldToEval = { + [nestedParentFieldName]: hit.fields[nestedParentFieldName], + }; + } else { + // fallback, should never hit + fieldToEval = { + [fieldName]: [], + }; + } + } + const formattedData = await getDataSafety(getDataFromFieldsHits, fieldToEval); + return formattedData.reduce( + (acc: TimelineNonEcsData[], { field, values }) => + // nested fields return all field values, pick only the one we asked for + field.includes(fieldName) ? [...acc, { field, value: values }] : acc, + [] + ); +}; + +const mergeTimelineFieldsWithHit = async <T>( fieldName: string, flattenedFields: T, - hit: { _source: {}; fields: Record<string, unknown[]> }, + hit: EventHit, dataFields: readonly string[], ecsFields: readonly string[] ) => { if (fieldName != null || dataFields.includes(fieldName)) { + const fieldNameAsArray = fieldName.split('.'); + const nestedParentFieldName = Object.keys(hit.fields ?? []).find((f) => { + return f === fieldNameAsArray.slice(0, f.split('.').length).join('.'); + }); if ( has(fieldName, hit._source) || has(fieldName, hit.fields) || + nestedParentFieldName != null || specialFields.includes(fieldName) ) { const objectWithProperty = { @@ -67,16 +123,7 @@ const mergeTimelineFieldsWithHit = <T>( data: dataFields.includes(fieldName) ? [ ...get('node.data', flattenedFields), - { - field: fieldName, - value: specialFields.includes(fieldName) - ? toStringArray(get(fieldName, hit)) - : isGeoField(fieldName) - ? formatGeoLocation(hit.fields[fieldName]) - : has(fieldName, hit._source) - ? toStringArray(get(fieldName, hit._source)) - : toStringArray(hit.fields[fieldName]), - }, + ...(await getValuesFromFields(fieldName, hit, nestedParentFieldName)), ] : get('node.data', flattenedFields), ecs: ecsFields.includes(fieldName) diff --git a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/index.ts b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/index.ts index 93985baed770e..05058e3ee7a2d 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/index.ts @@ -40,8 +40,10 @@ export const timelineEventsAll: SecuritySolutionTimelineFactory<TimelineEventsQu const { activePage, querySize } = options.pagination; const totalCount = response.rawResponse.hits.total || 0; const hits = response.rawResponse.hits.hits; - const edges: TimelineEdges[] = hits.map((hit) => - formatTimelineData(options.fieldRequested, TIMELINE_EVENTS_FIELDS, hit as EventHit) + const edges: TimelineEdges[] = await Promise.all( + hits.map((hit) => + formatTimelineData(options.fieldRequested, TIMELINE_EVENTS_FIELDS, hit as EventHit) + ) ); const inspect = { dsl: [inspectStringifyObject(buildTimelineEventsAllQuery(queryOptions))], diff --git a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/helpers.test.ts b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/helpers.test.ts index ca9a4b708161d..dc3efc6909c63 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/helpers.test.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/helpers.test.ts @@ -5,150 +5,192 @@ * 2.0. */ -import { EventHit } from '../../../../../../common/search_strategy'; -import { getDataFromFieldsHits } from './helpers'; +import { EventHit, EventSource } from '../../../../../../common/search_strategy'; +import { getDataFromFieldsHits, getDataFromSourceHits, getDataSafety } from './helpers'; +import { eventDetailsFormattedFields, eventHit } from '../mocks'; -describe('#getDataFromFieldsHits', () => { - it('happy path', () => { - const response: EventHit = { - _index: 'auditbeat-7.8.0-2020.11.05-000003', - _id: 'tkCt1nUBaEgqnrVSZ8R_', - _score: 0, - _type: '', - fields: { - 'event.category': ['process'], - 'process.ppid': [3977], - 'user.name': ['jenkins'], - 'process.args': ['go', 'vet', './...'], - message: ['Process go (PID: 4313) by user jenkins STARTED'], - 'process.pid': [4313], - 'process.working_directory': [ - '/var/lib/jenkins/workspace/Beats_beats_PR-22624/src/github.com/elastic/beats/libbeat', +describe('Events Details Helpers', () => { + const fields: EventHit['fields'] = eventHit.fields; + const resultFields = eventDetailsFormattedFields; + describe('#getDataFromFieldsHits', () => { + it('happy path', () => { + const result = getDataFromFieldsHits(fields); + expect(result).toEqual(resultFields); + }); + it('lets get weird', () => { + const whackFields = { + 'crazy.pants': [ + { + 'matched.field': ['matched_field'], + first_seen: ['2021-02-22T17:29:25.195Z'], + provider: ['yourself'], + type: ['custom'], + 'matched.atomic': ['matched_atomic'], + lazer: [ + { + 'great.field': ['grrrrr'], + lazer: [ + { + lazer: [ + { + cool: true, + lazer: [ + { + lazer: [ + { + lazer: [ + { + lazer: [ + { + whoa: false, + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + { + lazer: [ + { + cool: false, + }, + ], + }, + ], + }, + { + 'great.field': ['grrrrr_2'], + }, + ], + }, ], - 'process.entity_id': ['Z59cIkAAIw8ZoK0H'], - 'host.ip': ['10.224.1.237', 'fe80::4001:aff:fee0:1ed', '172.17.0.1'], - 'process.name': ['go'], - 'event.action': ['process_started'], - 'agent.type': ['auditbeat'], - '@timestamp': ['2020-11-17T14:48:08.922Z'], - 'event.module': ['system'], - 'event.type': ['start'], - 'host.name': ['beats-ci-immutable-ubuntu-1804-1605624279743236239'], - 'process.hash.sha1': ['1eac22336a41e0660fb302add9d97daa2bcc7040'], - 'host.os.family': ['debian'], - 'event.kind': ['event'], - 'host.id': ['e59991e835905c65ed3e455b33e13bd6'], - 'event.dataset': ['process'], - 'process.executable': [ - '/var/lib/jenkins/workspace/Beats_beats_PR-22624/.gvm/versions/go1.14.7.linux.amd64/bin/go', - ], - }, - _source: {}, - sort: ['1605624488922', 'beats-ci-immutable-ubuntu-1804-1605624279743236239'], - aggregations: {}, + }; + const whackResultFields = [ + { + category: 'crazy', + field: 'crazy.pants.matched.field', + values: ['matched_field'], + originalValue: ['matched_field'], + isObjectArray: false, + }, + { + category: 'crazy', + field: 'crazy.pants.first_seen', + values: ['2021-02-22T17:29:25.195Z'], + originalValue: ['2021-02-22T17:29:25.195Z'], + isObjectArray: false, + }, + { + category: 'crazy', + field: 'crazy.pants.provider', + values: ['yourself'], + originalValue: ['yourself'], + isObjectArray: false, + }, + { + category: 'crazy', + field: 'crazy.pants.type', + values: ['custom'], + originalValue: ['custom'], + isObjectArray: false, + }, + { + category: 'crazy', + field: 'crazy.pants.matched.atomic', + values: ['matched_atomic'], + originalValue: ['matched_atomic'], + isObjectArray: false, + }, + { + category: 'crazy', + field: 'crazy.pants.lazer.great.field', + values: ['grrrrr', 'grrrrr_2'], + originalValue: ['grrrrr', 'grrrrr_2'], + isObjectArray: false, + }, + { + category: 'crazy', + field: 'crazy.pants.lazer.lazer.lazer.cool', + values: ['true', 'false'], + originalValue: ['true', 'false'], + isObjectArray: false, + }, + { + category: 'crazy', + field: 'crazy.pants.lazer.lazer.lazer.lazer.lazer.lazer.lazer.whoa', + values: ['false'], + originalValue: ['false'], + isObjectArray: false, + }, + ]; + const result = getDataFromFieldsHits(whackFields); + expect(result).toEqual(whackResultFields); + }); + }); + it('#getDataFromSourceHits', () => { + const _source: EventSource = { + '@timestamp': '2021-02-24T00:41:06.527Z', + 'signal.status': 'open', + 'signal.rule.name': 'Rawr', + 'threat.indicator': [ + { + provider: 'yourself', + type: 'custom', + first_seen: ['2021-02-22T17:29:25.195Z'], + matched: { atomic: 'atom', field: 'field', type: 'type' }, + }, + { + provider: 'other_you', + type: 'custom', + first_seen: '2021-02-22T17:29:25.195Z', + matched: { atomic: 'atom', field: 'field', type: 'type' }, + }, + ], }; - - expect(getDataFromFieldsHits(response.fields)).toEqual([ - { - category: 'event', - field: 'event.category', - originalValue: ['process'], - values: ['process'], - }, - { category: 'process', field: 'process.ppid', originalValue: ['3977'], values: ['3977'] }, - { category: 'user', field: 'user.name', originalValue: ['jenkins'], values: ['jenkins'] }, - { - category: 'process', - field: 'process.args', - originalValue: ['go', 'vet', './...'], - values: ['go', 'vet', './...'], - }, - { - category: 'base', - field: 'message', - originalValue: ['Process go (PID: 4313) by user jenkins STARTED'], - values: ['Process go (PID: 4313) by user jenkins STARTED'], - }, - { category: 'process', field: 'process.pid', originalValue: ['4313'], values: ['4313'] }, - { - category: 'process', - field: 'process.working_directory', - originalValue: [ - '/var/lib/jenkins/workspace/Beats_beats_PR-22624/src/github.com/elastic/beats/libbeat', - ], - values: [ - '/var/lib/jenkins/workspace/Beats_beats_PR-22624/src/github.com/elastic/beats/libbeat', - ], - }, - { - category: 'process', - field: 'process.entity_id', - originalValue: ['Z59cIkAAIw8ZoK0H'], - values: ['Z59cIkAAIw8ZoK0H'], - }, - { - category: 'host', - field: 'host.ip', - originalValue: ['10.224.1.237', 'fe80::4001:aff:fee0:1ed', '172.17.0.1'], - values: ['10.224.1.237', 'fe80::4001:aff:fee0:1ed', '172.17.0.1'], - }, - { category: 'process', field: 'process.name', originalValue: ['go'], values: ['go'] }, - { - category: 'event', - field: 'event.action', - originalValue: ['process_started'], - values: ['process_started'], - }, - { - category: 'agent', - field: 'agent.type', - originalValue: ['auditbeat'], - values: ['auditbeat'], - }, + expect(getDataFromSourceHits(_source)).toEqual([ { category: 'base', field: '@timestamp', - originalValue: ['2020-11-17T14:48:08.922Z'], - values: ['2020-11-17T14:48:08.922Z'], + values: ['2021-02-24T00:41:06.527Z'], + originalValue: ['2021-02-24T00:41:06.527Z'], + isObjectArray: false, }, - { category: 'event', field: 'event.module', originalValue: ['system'], values: ['system'] }, - { category: 'event', field: 'event.type', originalValue: ['start'], values: ['start'] }, { - category: 'host', - field: 'host.name', - originalValue: ['beats-ci-immutable-ubuntu-1804-1605624279743236239'], - values: ['beats-ci-immutable-ubuntu-1804-1605624279743236239'], + category: 'signal', + field: 'signal.status', + values: ['open'], + originalValue: ['open'], + isObjectArray: false, }, { - category: 'process', - field: 'process.hash.sha1', - originalValue: ['1eac22336a41e0660fb302add9d97daa2bcc7040'], - values: ['1eac22336a41e0660fb302add9d97daa2bcc7040'], + category: 'signal', + field: 'signal.rule.name', + values: ['Rawr'], + originalValue: ['Rawr'], + isObjectArray: false, }, - { category: 'host', field: 'host.os.family', originalValue: ['debian'], values: ['debian'] }, - { category: 'event', field: 'event.kind', originalValue: ['event'], values: ['event'] }, { - category: 'host', - field: 'host.id', - originalValue: ['e59991e835905c65ed3e455b33e13bd6'], - values: ['e59991e835905c65ed3e455b33e13bd6'], - }, - { - category: 'event', - field: 'event.dataset', - originalValue: ['process'], - values: ['process'], - }, - { - category: 'process', - field: 'process.executable', - originalValue: [ - '/var/lib/jenkins/workspace/Beats_beats_PR-22624/.gvm/versions/go1.14.7.linux.amd64/bin/go', - ], + category: 'threat', + field: 'threat.indicator', values: [ - '/var/lib/jenkins/workspace/Beats_beats_PR-22624/.gvm/versions/go1.14.7.linux.amd64/bin/go', + '{"provider":"yourself","type":"custom","first_seen":["2021-02-22T17:29:25.195Z"],"matched":{"atomic":"atom","field":"field","type":"type"}}', + '{"provider":"other_you","type":"custom","first_seen":"2021-02-22T17:29:25.195Z","matched":{"atomic":"atom","field":"field","type":"type"}}', + ], + originalValue: [ + '{"provider":"yourself","type":"custom","first_seen":["2021-02-22T17:29:25.195Z"],"matched":{"atomic":"atom","field":"field","type":"type"}}', + '{"provider":"other_you","type":"custom","first_seen":"2021-02-22T17:29:25.195Z","matched":{"atomic":"atom","field":"field","type":"type"}}', ], + isObjectArray: true, }, ]); }); + it('#getDataSafety', async () => { + const result = await getDataSafety(getDataFromFieldsHits, fields); + expect(result).toEqual(resultFields); + }); }); diff --git a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/helpers.ts index 779454e9474ee..2fc729729e435 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/helpers.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/helpers.ts @@ -7,8 +7,12 @@ import { get, isEmpty, isNumber, isObject, isString } from 'lodash/fp'; -import { EventSource, TimelineEventsDetailsItem } from '../../../../../../common/search_strategy'; -import { toStringArray } from '../../../../helpers/to_array'; +import { + EventHit, + EventSource, + TimelineEventsDetailsItem, +} from '../../../../../../common/search_strategy'; +import { toObjectArrayOfStrings, toStringArray } from '../../../../helpers/to_array'; export const baseCategoryFields = ['@timestamp', 'labels', 'message', 'tags']; @@ -24,7 +28,10 @@ export const formatGeoLocation = (item: unknown[]) => { const itemGeo = item.length > 0 ? (item[0] as { coordinates: number[] }) : null; if (itemGeo != null && !isEmpty(itemGeo.coordinates)) { try { - return toStringArray({ long: itemGeo.coordinates[0], lat: itemGeo.coordinates[1] }); + return toStringArray({ + lon: itemGeo.coordinates[0], + lat: itemGeo.coordinates[1], + }); } catch { return toStringArray(item); } @@ -46,13 +53,18 @@ export const getDataFromSourceHits = ( const field = path ? `${path}.${source}` : source; const fieldCategory = getFieldCategory(field); + const objArrStr = toObjectArrayOfStrings(item); + const strArr = objArrStr.map(({ str }) => str); + const isObjectArray = objArrStr.some((o) => o.isObjectArray); + return [ ...accumulator, { category: fieldCategory, field, - values: toStringArray(item), - originalValue: toStringArray(item), + values: strArr, + originalValue: strArr, + isObjectArray, } as TimelineEventsDetailsItem, ]; } else if (isObject(item)) { @@ -65,18 +77,81 @@ export const getDataFromSourceHits = ( }, []); export const getDataFromFieldsHits = ( - fields: Record<string, unknown[]> + fields: EventHit['fields'], + prependField?: string, + prependFieldCategory?: string ): TimelineEventsDetailsItem[] => Object.keys(fields).reduce<TimelineEventsDetailsItem[]>((accumulator, field) => { const item: unknown[] = fields[field]; - const fieldCategory = getFieldCategory(field); - return [ + + const fieldCategory = + prependFieldCategory != null ? prependFieldCategory : getFieldCategory(field); + if (isGeoField(field)) { + return [ + ...accumulator, + { + category: fieldCategory, + field, + values: formatGeoLocation(item), + originalValue: formatGeoLocation(item), + isObjectArray: true, // important for UI + }, + ]; + } + const objArrStr = toObjectArrayOfStrings(item); + const strArr = objArrStr.map(({ str }) => str); + const isObjectArray = objArrStr.some((o) => o.isObjectArray); + const dotField = prependField ? `${prependField}.${field}` : field; + + // return simple field value (non-object, non-array) + if (!isObjectArray) { + return [ + ...accumulator, + { + category: fieldCategory, + field: dotField, + values: strArr, + originalValue: strArr, + isObjectArray, + }, + ]; + } + + // format nested fields + const nestedFields = Array.isArray(item) + ? item + .reduce((acc, i) => [...acc, getDataFromFieldsHits(i, dotField, fieldCategory)], []) + .flat() + : getDataFromFieldsHits(item, prependField, fieldCategory); + + // combine duplicate fields + const flat: Record<string, TimelineEventsDetailsItem> = [ ...accumulator, - { - category: fieldCategory, - field, - values: isGeoField(field) ? formatGeoLocation(item) : toStringArray(item), - originalValue: toStringArray(item), - } as TimelineEventsDetailsItem, - ]; + ...nestedFields, + ].reduce( + (acc, f) => ({ + ...acc, + // acc/flat is hashmap to determine if we already have the field or not without an array iteration + // its converted back to array in return with Object.values + ...(acc[f.field] != null + ? { + [f.field]: { + ...f, + originalValue: acc[f.field].originalValue.includes(f.originalValue[0]) + ? acc[f.field].originalValue + : [...acc[f.field].originalValue, ...f.originalValue], + values: acc[f.field].values.includes(f.values[0]) + ? acc[f.field].values + : [...acc[f.field].values, ...f.values], + }, + } + : { [f.field]: f }), + }), + {} + ); + + return Object.values(flat); }, []); + +export const getDataSafety = <A, T>(fn: (args: A) => T, args: A): Promise<T> => + new Promise((resolve) => setTimeout(() => resolve(fn(args)))); diff --git a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/index.ts b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/index.ts index f5deb258fc1f4..7794de7f0f411 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { cloneDeep, merge } from 'lodash/fp'; +import { cloneDeep, merge, unionBy } from 'lodash/fp'; import { IEsSearchResponse } from '../../../../../../../../../src/plugins/data/common'; import { @@ -13,11 +13,13 @@ import { TimelineEventsQueries, TimelineEventsDetailsStrategyResponse, TimelineEventsDetailsRequestOptions, + TimelineEventsDetailsItem, + EventSource, } from '../../../../../../common/search_strategy'; import { inspectStringifyObject } from '../../../../../utils/build_query'; import { SecuritySolutionTimelineFactory } from '../../types'; import { buildTimelineDetailsQuery } from './query.events_details.dsl'; -import { getDataFromSourceHits } from './helpers'; +import { getDataFromFieldsHits, getDataFromSourceHits, getDataSafety } from './helpers'; export const timelineEventsDetails: SecuritySolutionTimelineFactory<TimelineEventsQueries.details> = { buildDsl: (options: TimelineEventsDetailsRequestOptions) => { @@ -29,11 +31,10 @@ export const timelineEventsDetails: SecuritySolutionTimelineFactory<TimelineEven response: IEsSearchResponse<EventHit> ): Promise<TimelineEventsDetailsStrategyResponse> => { const { indexName, eventId, docValueFields = [] } = options; - const { _source, ...hitsData } = cloneDeep(response.rawResponse.hits.hits[0] ?? {}); + const { _source, fields, ...hitsData } = cloneDeep(response.rawResponse.hits.hits[0] ?? {}); const inspect = { dsl: [inspectStringifyObject(buildTimelineDetailsQuery(indexName, eventId, docValueFields))], }; - if (response.isRunning) { return { ...response, @@ -41,12 +42,19 @@ export const timelineEventsDetails: SecuritySolutionTimelineFactory<TimelineEven inspect, }; } + const sourceData = await getDataSafety<EventSource, TimelineEventsDetailsItem[]>( + getDataFromSourceHits, + _source + ); + const fieldsData = await getDataSafety<EventHit['fields'], TimelineEventsDetailsItem[]>( + getDataFromFieldsHits, + merge(fields, hitsData) + ); - const sourceData = getDataFromSourceHits(merge(_source, hitsData)); - + const data = unionBy('field', fieldsData, sourceData); return { ...response, - data: sourceData, + data, inspect, }; }, diff --git a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/query.events_details.dsl.test.ts b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/query.events_details.dsl.test.ts index 47716e21bca31..4545a3a3e136b 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/query.events_details.dsl.test.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/query.events_details.dsl.test.ts @@ -24,6 +24,7 @@ describe('buildTimelineDetailsQuery', () => { Object { "allowNoIndices": true, "body": Object { + "_source": true, "docvalue_fields": Array [ Object { "field": "@timestamp", @@ -38,6 +39,9 @@ describe('buildTimelineDetailsQuery', () => { "field": "agent.name", }, ], + "fields": Array [ + "*", + ], "query": Object { "terms": Object { "_id": Array [ diff --git a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/query.events_details.dsl.ts b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/query.events_details.dsl.ts index e8890072c1aff..c624eb14ae969 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/query.events_details.dsl.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/query.events_details.dsl.ts @@ -22,6 +22,8 @@ export const buildTimelineDetailsQuery = ( _id: [id], }, }, + fields: ['*'], + _source: true, }, size: 1, }); diff --git a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/mocks.ts b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/mocks.ts new file mode 100644 index 0000000000000..13b7fe7051246 --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/mocks.ts @@ -0,0 +1,329 @@ +/* + * 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 eventHit = { + _index: 'auditbeat-7.8.0-2020.11.05-000003', + _id: 'tkCt1nUBaEgqnrVSZ8R_', + _score: 0, + _type: '', + fields: { + 'event.category': ['process'], + 'process.ppid': [3977], + 'user.name': ['jenkins'], + 'process.args': ['go', 'vet', './...'], + message: ['Process go (PID: 4313) by user jenkins STARTED'], + 'process.pid': [4313], + 'process.working_directory': [ + '/var/lib/jenkins/workspace/Beats_beats_PR-22624/src/github.com/elastic/beats/libbeat', + ], + 'process.entity_id': ['Z59cIkAAIw8ZoK0H'], + 'host.ip': ['10.224.1.237', 'fe80::4001:aff:fee0:1ed', '172.17.0.1'], + 'process.name': ['go'], + 'event.action': ['process_started'], + 'agent.type': ['auditbeat'], + '@timestamp': ['2020-11-17T14:48:08.922Z'], + 'event.module': ['system'], + 'event.type': ['start'], + 'host.name': ['beats-ci-immutable-ubuntu-1804-1605624279743236239'], + 'process.hash.sha1': ['1eac22336a41e0660fb302add9d97daa2bcc7040'], + 'host.os.family': ['debian'], + 'event.kind': ['event'], + 'host.id': ['e59991e835905c65ed3e455b33e13bd6'], + 'event.dataset': ['process'], + 'process.executable': [ + '/var/lib/jenkins/workspace/Beats_beats_PR-22624/.gvm/versions/go1.14.7.linux.amd64/bin/go', + ], + 'source.geo.location': [{ coordinates: [118.7778, 32.0617], type: 'Point' }], + 'threat.indicator': [ + { + 'matched.field': ['matched_field'], + first_seen: ['2021-02-22T17:29:25.195Z'], + provider: ['yourself'], + type: ['custom'], + 'matched.atomic': ['matched_atomic'], + lazer: [ + { + 'great.field': ['grrrrr'], + }, + { + 'great.field': ['grrrrr_2'], + }, + ], + }, + { + 'matched.field': ['matched_field_2'], + first_seen: ['2021-02-22T17:29:25.195Z'], + provider: ['other_you'], + type: ['custom'], + 'matched.atomic': ['matched_atomic_2'], + lazer: [ + { + 'great.field': [ + { + wowoe: [ + { + fooooo: ['grrrrr'], + }, + ], + astring: 'cool', + aNumber: 1, + anObject: { + neat: true, + }, + }, + ], + }, + ], + }, + ], + }, + _source: {}, + sort: ['1605624488922', 'beats-ci-immutable-ubuntu-1804-1605624279743236239'], + aggregations: {}, +}; + +export const eventDetailsFormattedFields = [ + { + category: 'event', + field: 'event.category', + isObjectArray: false, + originalValue: ['process'], + values: ['process'], + }, + { + category: 'process', + field: 'process.ppid', + isObjectArray: false, + originalValue: ['3977'], + values: ['3977'], + }, + { + category: 'user', + field: 'user.name', + isObjectArray: false, + originalValue: ['jenkins'], + values: ['jenkins'], + }, + { + category: 'process', + field: 'process.args', + isObjectArray: false, + originalValue: ['go', 'vet', './...'], + values: ['go', 'vet', './...'], + }, + { + category: 'base', + field: 'message', + isObjectArray: false, + originalValue: ['Process go (PID: 4313) by user jenkins STARTED'], + values: ['Process go (PID: 4313) by user jenkins STARTED'], + }, + { + category: 'process', + field: 'process.pid', + isObjectArray: false, + originalValue: ['4313'], + values: ['4313'], + }, + { + category: 'process', + field: 'process.working_directory', + isObjectArray: false, + originalValue: [ + '/var/lib/jenkins/workspace/Beats_beats_PR-22624/src/github.com/elastic/beats/libbeat', + ], + values: [ + '/var/lib/jenkins/workspace/Beats_beats_PR-22624/src/github.com/elastic/beats/libbeat', + ], + }, + { + category: 'process', + field: 'process.entity_id', + isObjectArray: false, + originalValue: ['Z59cIkAAIw8ZoK0H'], + values: ['Z59cIkAAIw8ZoK0H'], + }, + { + category: 'host', + field: 'host.ip', + isObjectArray: false, + originalValue: ['10.224.1.237', 'fe80::4001:aff:fee0:1ed', '172.17.0.1'], + values: ['10.224.1.237', 'fe80::4001:aff:fee0:1ed', '172.17.0.1'], + }, + { + category: 'process', + field: 'process.name', + isObjectArray: false, + originalValue: ['go'], + values: ['go'], + }, + { + category: 'event', + field: 'event.action', + isObjectArray: false, + originalValue: ['process_started'], + values: ['process_started'], + }, + { + category: 'agent', + field: 'agent.type', + isObjectArray: false, + originalValue: ['auditbeat'], + values: ['auditbeat'], + }, + { + category: 'base', + field: '@timestamp', + isObjectArray: false, + originalValue: ['2020-11-17T14:48:08.922Z'], + values: ['2020-11-17T14:48:08.922Z'], + }, + { + category: 'event', + field: 'event.module', + isObjectArray: false, + originalValue: ['system'], + values: ['system'], + }, + { + category: 'event', + field: 'event.type', + isObjectArray: false, + originalValue: ['start'], + values: ['start'], + }, + { + category: 'host', + field: 'host.name', + isObjectArray: false, + originalValue: ['beats-ci-immutable-ubuntu-1804-1605624279743236239'], + values: ['beats-ci-immutable-ubuntu-1804-1605624279743236239'], + }, + { + category: 'process', + field: 'process.hash.sha1', + isObjectArray: false, + originalValue: ['1eac22336a41e0660fb302add9d97daa2bcc7040'], + values: ['1eac22336a41e0660fb302add9d97daa2bcc7040'], + }, + { + category: 'host', + field: 'host.os.family', + isObjectArray: false, + originalValue: ['debian'], + values: ['debian'], + }, + { + category: 'event', + field: 'event.kind', + isObjectArray: false, + originalValue: ['event'], + values: ['event'], + }, + { + category: 'host', + field: 'host.id', + isObjectArray: false, + originalValue: ['e59991e835905c65ed3e455b33e13bd6'], + values: ['e59991e835905c65ed3e455b33e13bd6'], + }, + { + category: 'event', + field: 'event.dataset', + isObjectArray: false, + originalValue: ['process'], + values: ['process'], + }, + { + category: 'process', + field: 'process.executable', + isObjectArray: false, + originalValue: [ + '/var/lib/jenkins/workspace/Beats_beats_PR-22624/.gvm/versions/go1.14.7.linux.amd64/bin/go', + ], + values: [ + '/var/lib/jenkins/workspace/Beats_beats_PR-22624/.gvm/versions/go1.14.7.linux.amd64/bin/go', + ], + }, + { + category: 'source', + field: 'source.geo.location', + isObjectArray: true, + originalValue: [`{"lon":118.7778,"lat":32.0617}`], + values: [`{"lon":118.7778,"lat":32.0617}`], + }, + { + category: 'threat', + field: 'threat.indicator.matched.field', + values: ['matched_field', 'matched_field_2'], + originalValue: ['matched_field', 'matched_field_2'], + isObjectArray: false, + }, + { + category: 'threat', + field: 'threat.indicator.first_seen', + values: ['2021-02-22T17:29:25.195Z'], + originalValue: ['2021-02-22T17:29:25.195Z'], + isObjectArray: false, + }, + { + category: 'threat', + field: 'threat.indicator.provider', + values: ['yourself', 'other_you'], + originalValue: ['yourself', 'other_you'], + isObjectArray: false, + }, + { + category: 'threat', + field: 'threat.indicator.type', + values: ['custom'], + originalValue: ['custom'], + isObjectArray: false, + }, + { + category: 'threat', + field: 'threat.indicator.matched.atomic', + values: ['matched_atomic', 'matched_atomic_2'], + originalValue: ['matched_atomic', 'matched_atomic_2'], + isObjectArray: false, + }, + { + category: 'threat', + field: 'threat.indicator.lazer.great.field', + values: ['grrrrr', 'grrrrr_2'], + originalValue: ['grrrrr', 'grrrrr_2'], + isObjectArray: false, + }, + { + category: 'threat', + field: 'threat.indicator.lazer.great.field.wowoe.fooooo', + values: ['grrrrr'], + originalValue: ['grrrrr'], + isObjectArray: false, + }, + { + category: 'threat', + field: 'threat.indicator.lazer.great.field.astring', + values: ['cool'], + originalValue: ['cool'], + isObjectArray: false, + }, + { + category: 'threat', + field: 'threat.indicator.lazer.great.field.aNumber', + values: ['1'], + originalValue: ['1'], + isObjectArray: false, + }, + { + category: 'threat', + field: 'threat.indicator.lazer.great.field.neat', + values: ['true'], + originalValue: ['true'], + isObjectArray: false, + }, +]; diff --git a/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_stats_with_xpack.test.ts b/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_stats_with_xpack.test.ts index 047337bb48673..fed18bcb461e3 100644 --- a/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_stats_with_xpack.test.ts +++ b/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_stats_with_xpack.test.ts @@ -61,22 +61,22 @@ function mockEsClient() { const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; // mock for license should return a basic license esClient.license.get.mockResolvedValue( - // @ts-ignore we only care about the response body + // @ts-expect-error we only care about the response body { body: { license: { type: 'basic' } } } ); // mock for xpack usage should return an empty object esClient.xpack.usage.mockResolvedValue( - // @ts-ignore we only care about the response body + // @ts-expect-error we only care about the response body { body: {} } ); // mock for nodes usage should resolve for this test esClient.nodes.usage.mockResolvedValue( - // @ts-ignore we only care about the response body + // @ts-expect-error we only care about the response body { body: { cluster_name: 'test cluster', nodes: nodesUsage } } ); // mock for info should resolve for this test esClient.info.mockResolvedValue( - // @ts-ignore we only care about the response body + // @ts-expect-error we only care about the response body { body: { cluster_uuid: 'test', diff --git a/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_xpack.test.ts b/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_xpack.test.ts index c438abda8ca83..48b58c7679789 100644 --- a/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_xpack.test.ts +++ b/x-pack/plugins/telemetry_collection_xpack/server/telemetry_collection/get_xpack.test.ts @@ -12,7 +12,7 @@ describe('get_xpack', () => { describe('getXPackUsage', () => { it('uses esClient to get /_xpack/usage API', async () => { const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; - // @ts-ignore we only care about the response body + // @ts-expect-error we only care about the response body esClient.xpack.usage.mockResolvedValue({ body: {} }); const result = await getXPackUsage(esClient); expect(result).toEqual({}); diff --git a/x-pack/plugins/transform/common/api_schemas/common.ts b/x-pack/plugins/transform/common/api_schemas/common.ts index 1841724c16ef9..3651af69359a9 100644 --- a/x-pack/plugins/transform/common/api_schemas/common.ts +++ b/x-pack/plugins/transform/common/api_schemas/common.ts @@ -53,3 +53,27 @@ export interface ResponseStatus { export interface CommonResponseStatusSchema { [key: string]: ResponseStatus; } + +export const runtimeMappingsSchema = schema.maybe( + schema.recordOf( + schema.string(), + schema.object({ + type: schema.oneOf([ + schema.literal('keyword'), + schema.literal('long'), + schema.literal('double'), + schema.literal('date'), + schema.literal('ip'), + schema.literal('boolean'), + ]), + script: schema.maybe( + schema.oneOf([ + schema.string(), + schema.object({ + source: schema.string(), + }), + ]) + ), + }) + ) +); diff --git a/x-pack/plugins/transform/common/api_schemas/field_histograms.ts b/x-pack/plugins/transform/common/api_schemas/field_histograms.ts index fc5a95590c7c6..9f6f4c15d803a 100644 --- a/x-pack/plugins/transform/common/api_schemas/field_histograms.ts +++ b/x-pack/plugins/transform/common/api_schemas/field_histograms.ts @@ -7,14 +7,20 @@ import { schema, TypeOf } from '@kbn/config-schema'; +import { ChartData } from '../shared_imports'; + +import { runtimeMappingsSchema } from './common'; + export const fieldHistogramsRequestSchema = schema.object({ /** Query to match documents in the index. */ query: schema.any(), /** The fields to return histogram data. */ fields: schema.arrayOf(schema.any()), + /** Optional runtime mappings */ + runtimeMappings: runtimeMappingsSchema, /** Number of documents to be collected in the sample processed on each shard, or -1 for no sampling. */ samplerShardSize: schema.number(), }); export type FieldHistogramsRequestSchema = TypeOf<typeof fieldHistogramsRequestSchema>; -export type FieldHistogramsResponseSchema = any[]; +export type FieldHistogramsResponseSchema = ChartData[]; diff --git a/x-pack/plugins/transform/common/api_schemas/transforms.ts b/x-pack/plugins/transform/common/api_schemas/transforms.ts index d86df3af3e1d0..4d25bd74f4e74 100644 --- a/x-pack/plugins/transform/common/api_schemas/transforms.ts +++ b/x-pack/plugins/transform/common/api_schemas/transforms.ts @@ -14,7 +14,7 @@ import type { PivotAggDict } from '../types/pivot_aggs'; import type { PivotGroupByDict } from '../types/pivot_group_by'; import type { TransformId, TransformPivotConfig } from '../types/transform'; -import { transformStateSchema } from './common'; +import { transformStateSchema, runtimeMappingsSchema } from './common'; // GET transforms export const getTransformsRequestSchema = schema.arrayOf( @@ -64,30 +64,6 @@ export const settingsSchema = schema.object({ docs_per_second: schema.maybe(schema.nullable(schema.number())), }); -export const runtimeMappingsSchema = schema.maybe( - schema.recordOf( - schema.string(), - schema.object({ - type: schema.oneOf([ - schema.literal('keyword'), - schema.literal('long'), - schema.literal('double'), - schema.literal('date'), - schema.literal('ip'), - schema.literal('boolean'), - ]), - script: schema.maybe( - schema.oneOf([ - schema.string(), - schema.object({ - source: schema.string(), - }), - ]) - ), - }) - ) -); - export const sourceSchema = schema.object({ runtime_mappings: runtimeMappingsSchema, index: schema.oneOf([schema.string(), schema.arrayOf(schema.string())]), diff --git a/x-pack/plugins/transform/common/shared_imports.ts b/x-pack/plugins/transform/common/shared_imports.ts index 4506083a1876f..3062c7ab8d23c 100644 --- a/x-pack/plugins/transform/common/shared_imports.ts +++ b/x-pack/plugins/transform/common/shared_imports.ts @@ -6,5 +6,9 @@ */ export type { HitsTotalRelation, SearchResponse7 } from '../../ml/common'; -export { HITS_TOTAL_RELATION } from '../../ml/common'; -export { composeValidators, patternValidator } from '../../ml/common'; +export { + composeValidators, + patternValidator, + ChartData, + HITS_TOTAL_RELATION, +} from '../../ml/common'; diff --git a/x-pack/plugins/transform/public/app/hooks/use_api.ts b/x-pack/plugins/transform/public/app/hooks/use_api.ts index 388bc8b432fc4..7afbc5e403b78 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_api.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_api.ts @@ -16,7 +16,10 @@ import type { DeleteTransformsRequestSchema, DeleteTransformsResponseSchema, } from '../../../common/api_schemas/delete_transforms'; -import type { FieldHistogramsResponseSchema } from '../../../common/api_schemas/field_histograms'; +import type { + FieldHistogramsRequestSchema, + FieldHistogramsResponseSchema, +} from '../../../common/api_schemas/field_histograms'; import type { StartTransformsRequestSchema, StartTransformsResponseSchema, @@ -194,6 +197,7 @@ export const useApi = () => { indexPatternTitle: string, fields: FieldHistogramRequestConfig[], query: string | SavedSearchQuery, + runtimeMappings?: FieldHistogramsRequestSchema['runtimeMappings'], samplerShardSize = DEFAULT_SAMPLER_SHARD_SIZE ): Promise<FieldHistogramsResponseSchema | HttpFetchError> { try { @@ -202,6 +206,7 @@ export const useApi = () => { query, fields, samplerShardSize, + ...(runtimeMappings !== undefined ? { runtimeMappings } : {}), }), }); } catch (e) { diff --git a/x-pack/plugins/transform/public/app/hooks/use_index_data.ts b/x-pack/plugins/transform/public/app/hooks/use_index_data.ts index dde4c7eb0f3a0..e12aa78e33622 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_index_data.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_index_data.ts @@ -150,7 +150,8 @@ export const useIndexData = ( fieldName: cT.id, type: getFieldType(cT.schema), })), - isDefaultQuery(query) ? matchAllQuery : query + isDefaultQuery(query) ? matchAllQuery : query, + combinedRuntimeMappings ); if (!isFieldHistogramsResponseSchema(columnChartsData)) { diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_editor/advanced_runtime_mappings_editor.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_editor/advanced_runtime_mappings_editor.tsx index 087bae97e287e..23c4cfcefe8ef 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_editor/advanced_runtime_mappings_editor.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_editor/advanced_runtime_mappings_editor.tsx @@ -13,6 +13,7 @@ import { EuiCodeEditor } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { StepDefineFormHook } from '../step_define'; +import { isRuntimeMappings } from '../step_define/common/types'; export const AdvancedRuntimeMappingsEditor: FC<StepDefineFormHook['runtimeMappingsEditor']> = memo( ({ @@ -43,8 +44,8 @@ export const AdvancedRuntimeMappingsEditor: FC<StepDefineFormHook['runtimeMappin // Try to parse the string passed on from the editor. // If parsing fails, the "Apply"-Button will be disabled try { - JSON.parse(convertToJson(d)); - setRuntimeMappingsEditorApplyButtonEnabled(true); + const parsedJson = JSON.parse(convertToJson(d)); + setRuntimeMappingsEditorApplyButtonEnabled(isRuntimeMappings(parsedJson)); } catch (e) { setRuntimeMappingsEditorApplyButtonEnabled(false); } diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/get_pivot_dropdown_options.ts b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/get_pivot_dropdown_options.ts index c88b604989680..f981c3786de34 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/get_pivot_dropdown_options.ts +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/get_pivot_dropdown_options.ts @@ -26,7 +26,7 @@ import { import { getDefaultAggregationConfig } from './get_default_aggregation_config'; import { getDefaultGroupByConfig } from './get_default_group_by_config'; import type { Field, StepDefineExposedState } from './types'; -import { isPopulatedObject } from '../../../../../common/utils/object_utils'; +import { isRuntimeMappings } from './types'; const illegalEsAggNameChars = /[[\]>]/g; @@ -77,7 +77,7 @@ export function getPivotDropdownOptions( // Support for runtime_mappings that are defined by queries let runtimeFields: Field[] = []; - if (isPopulatedObject(runtimeMappings)) { + if (isRuntimeMappings(runtimeMappings)) { runtimeFields = Object.keys(runtimeMappings).map((fieldName) => { const field = runtimeMappings[fieldName]; return { name: fieldName, type: getKibanaFieldTypeFromEsType(field.type) }; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/types.test.ts b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/types.test.ts new file mode 100644 index 0000000000000..ec90d31a0d169 --- /dev/null +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/types.test.ts @@ -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 { isRuntimeField, isRuntimeMappings } from './types'; + +describe('Transform: step_define type guards', () => { + it('isRuntimeField()', () => { + expect(isRuntimeField(1)).toBe(false); + expect(isRuntimeField(null)).toBe(false); + expect(isRuntimeField([])).toBe(false); + expect(isRuntimeField({})).toBe(false); + expect(isRuntimeField({ someAttribute: 'someValue' })).toBe(false); + expect(isRuntimeField({ type: 'wrong-type' })).toBe(false); + expect(isRuntimeField({ type: 'keyword', someAttribute: 'some value' })).toBe(false); + + expect(isRuntimeField({ type: 'keyword' })).toBe(true); + expect(isRuntimeField({ type: 'keyword', script: 'some script' })).toBe(true); + }); + + it('isRuntimeMappings()', () => { + expect(isRuntimeMappings(1)).toBe(false); + expect(isRuntimeMappings(null)).toBe(false); + expect(isRuntimeMappings([])).toBe(false); + expect(isRuntimeMappings({})).toBe(false); + expect(isRuntimeMappings({ someAttribute: 'someValue' })).toBe(false); + expect(isRuntimeMappings({ fieldName1: { type: 'keyword' }, fieldName2: 'someValue' })).toBe( + false + ); + expect( + isRuntimeMappings({ + fieldName1: { type: 'keyword' }, + fieldName2: { type: 'keyword', someAttribute: 'some value' }, + }) + ).toBe(false); + expect( + isRuntimeMappings({ + fieldName: { type: 'long', script: 1234 }, + }) + ).toBe(false); + expect( + isRuntimeMappings({ + fieldName: { type: 'long', script: { someAttribute: 'some value' } }, + }) + ).toBe(false); + expect( + isRuntimeMappings({ + fieldName: { type: 'long', script: { source: 1234 } }, + }) + ).toBe(false); + + expect(isRuntimeMappings({ fieldName: { type: 'keyword' } })).toBe(true); + expect( + isRuntimeMappings({ fieldName1: { type: 'keyword' }, fieldName2: { type: 'keyword' } }) + ).toBe(true); + expect( + isRuntimeMappings({ + fieldName1: { type: 'keyword' }, + fieldName2: { type: 'keyword', script: 'some script as script' }, + }) + ).toBe(true); + expect( + isRuntimeMappings({ + fieldName: { type: 'long', script: { source: 'some script as source' } }, + }) + ).toBe(true); + }); +}); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/types.ts b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/types.ts index 6c9293a6d13cf..d0218996b2e4f 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/types.ts +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/types.ts @@ -24,6 +24,8 @@ import { } from '../../../../../../../common/types/transform'; import { LatestFunctionConfig } from '../../../../../../../common/api_schemas/transforms'; +import { isPopulatedObject } from '../../../../../common/utils/object_utils'; + export interface ErrorMessage { query: string; message: string; @@ -70,10 +72,30 @@ export interface StepDefineExposedState { isRuntimeMappingsEditorEnabled: boolean; } +export function isRuntimeField(arg: any): arg is RuntimeField { + return ( + isPopulatedObject(arg) && + ((Object.keys(arg).length === 1 && arg.hasOwnProperty('type')) || + (Object.keys(arg).length === 2 && + arg.hasOwnProperty('type') && + arg.hasOwnProperty('script') && + (typeof arg.script === 'string' || + (isPopulatedObject(arg.script) && + Object.keys(arg.script).length === 1 && + arg.script.hasOwnProperty('source') && + typeof arg.script.source === 'string')))) && + RUNTIME_FIELD_TYPES.includes(arg.type) + ); +} + +export function isRuntimeMappings(arg: any): arg is RuntimeMappings { + return isPopulatedObject(arg) && Object.values(arg).every((d) => isRuntimeField(d)); +} + export function isPivotPartialRequest(arg: any): arg is { pivot: PivotConfigDefinition } { - return typeof arg === 'object' && arg.hasOwnProperty('pivot'); + return isPopulatedObject(arg) && arg.hasOwnProperty('pivot'); } export function isLatestPartialRequest(arg: any): arg is { latest: LatestFunctionConfig } { - return typeof arg === 'object' && arg.hasOwnProperty('latest'); + return isPopulatedObject(arg) && arg.hasOwnProperty('latest'); } diff --git a/x-pack/plugins/transform/server/routes/api/field_histograms.ts b/x-pack/plugins/transform/server/routes/api/field_histograms.ts index d3269bf14322a..bfe2f47078569 100644 --- a/x-pack/plugins/transform/server/routes/api/field_histograms.ts +++ b/x-pack/plugins/transform/server/routes/api/field_histograms.ts @@ -32,7 +32,7 @@ export function registerFieldHistogramsRoutes({ router, license }: RouteDependen license.guardApiRoute<IndexPatternTitleSchema, undefined, FieldHistogramsRequestSchema>( async (ctx, req, res) => { const { indexPatternTitle } = req.params; - const { query, fields, samplerShardSize } = req.body; + const { query, fields, runtimeMappings, samplerShardSize } = req.body; try { const resp = await getHistogramsForFields( @@ -40,7 +40,8 @@ export function registerFieldHistogramsRoutes({ router, license }: RouteDependen indexPatternTitle, query, fields, - samplerShardSize + samplerShardSize, + runtimeMappings ); return res.ok({ body: resp }); diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 92fead153328a..dd628134c521e 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -9449,8 +9449,6 @@ "xpack.indexLifecycleMgmt.editPolicy.saveAsNewPolicyMessage": "新規ポリシーとして保存します", "xpack.indexLifecycleMgmt.editPolicy.saveButton": "ポリシーを保存", "xpack.indexLifecycleMgmt.editPolicy.saveErrorMessage": "ライフサイクルポリシー {lifecycleName} の保存中にエラーが発生しました", - "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotCalloutBody": "検索可能なスナップショットがホットフェーズで有効な場合には、強制、マージ、縮小、凍結、コールドフェーズの検索可能なスナップショットは許可されません。", - "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotDisabledCalloutBody": "ホットフェーズで構成されているときには、コールドフェーズで検索可能なスナップショットを作成できません。", "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotFieldDescription": "選択したリポジトリで管理されたインデックスのスナップショットを作成し、検索可能なスナップショットとしてマウントします。{learnMoreLink}。", "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotFieldLabel": "検索可能なスナップショットリポジドリ", "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotFieldTitle": "検索可能スナップショット", @@ -11418,7 +11416,6 @@ "xpack.lens.xySuggestions.unstackedChartTitle": "スタックが解除されました", "xpack.lens.xySuggestions.yAxixConjunctionSign": " & ", "xpack.lens.xyVisualization.areaLabel": "エリア", - "xpack.lens.xyVisualization.barHorizontalFullLabel": "横棒", "xpack.lens.xyVisualization.barHorizontalLabel": "横棒", "xpack.lens.xyVisualization.barLabel": "棒", "xpack.lens.xyVisualization.dataFailureSplitLong": "{layers, plural, other {レイヤー}} {layersList} には {axis} のフィールドが{layers, plural, other {必要です}}。", @@ -11430,11 +11427,9 @@ "xpack.lens.xyVisualization.mixedLabel": "ミックスされた XY", "xpack.lens.xyVisualization.noDataLabel": "結果が見つかりませんでした", "xpack.lens.xyVisualization.stackedAreaLabel": "スタックされたエリア", - "xpack.lens.xyVisualization.stackedBarHorizontalFullLabel": "積み上げ横棒", "xpack.lens.xyVisualization.stackedBarHorizontalLabel": "横積み上げ棒", "xpack.lens.xyVisualization.stackedBarLabel": "積み上げ棒", "xpack.lens.xyVisualization.stackedPercentageAreaLabel": "割合エリア", - "xpack.lens.xyVisualization.stackedPercentageBarHorizontalFullLabel": "割合横棒", "xpack.lens.xyVisualization.stackedPercentageBarHorizontalLabel": "横割合棒", "xpack.lens.xyVisualization.stackedPercentageBarLabel": "割合棒", "xpack.lens.xyVisualization.xyLabel": "XY", @@ -17199,7 +17194,6 @@ "xpack.securitySolution.case.common.noConnector": "コネクターを選択していません", "xpack.securitySolution.case.components.connectors.case.actionTypeTitle": "ケース", "xpack.securitySolution.case.components.connectors.case.addNewCaseOption": "新規ケースの追加", - "xpack.securitySolution.case.components.connectors.case.callOutInfo": "ルールを作成した後のすべてのアラートは、選択したケースの最後に追加されます。", "xpack.securitySolution.case.components.connectors.case.caseRequired": "ケースの選択が必要です。", "xpack.securitySolution.case.components.connectors.case.casesDropdownPlaceholder": "ケースを選択", "xpack.securitySolution.case.components.connectors.case.casesDropdownRowLabel": "ケース", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index b00c863cad9aa..c733f214be554 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -9473,8 +9473,6 @@ "xpack.indexLifecycleMgmt.editPolicy.saveAsNewPolicyMessage": "另存为新策略", "xpack.indexLifecycleMgmt.editPolicy.saveButton": "保存策略", "xpack.indexLifecycleMgmt.editPolicy.saveErrorMessage": "保存生命周期策略 {lifecycleName} 时出错", - "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotCalloutBody": "在热阶段启用可搜索快照时,不允许强制合并、缩小、冻结可搜索快照以及将其置入冷阶段。", - "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotDisabledCalloutBody": "无法在冷阶段创建在热阶段配置的可搜索快照。", "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotFieldDescription": "在所选存储库中拍取受管索引的快照,并将其安装为可搜索快照。{learnMoreLink}。", "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotFieldLabel": "可搜索快照存储库", "xpack.indexLifecycleMgmt.editPolicy.searchableSnapshotFieldTitle": "可搜索快照", @@ -11446,7 +11444,6 @@ "xpack.lens.xySuggestions.unstackedChartTitle": "非堆叠", "xpack.lens.xySuggestions.yAxixConjunctionSign": " & ", "xpack.lens.xyVisualization.areaLabel": "面积图", - "xpack.lens.xyVisualization.barHorizontalFullLabel": "水平条形图", "xpack.lens.xyVisualization.barHorizontalLabel": "水平条形图", "xpack.lens.xyVisualization.barLabel": "条形图", "xpack.lens.xyVisualization.dataFailureSplitLong": "{layers, plural, other {图层}} {layersList} {layers, plural, other {需要}}一个针对{axis}的字段。", @@ -11458,11 +11455,9 @@ "xpack.lens.xyVisualization.mixedLabel": "混合 XY", "xpack.lens.xyVisualization.noDataLabel": "找不到结果", "xpack.lens.xyVisualization.stackedAreaLabel": "堆叠面积图", - "xpack.lens.xyVisualization.stackedBarHorizontalFullLabel": "水平堆叠条形图", "xpack.lens.xyVisualization.stackedBarHorizontalLabel": "水平堆叠条形图", "xpack.lens.xyVisualization.stackedBarLabel": "堆叠条形图", "xpack.lens.xyVisualization.stackedPercentageAreaLabel": "百分比面积图", - "xpack.lens.xyVisualization.stackedPercentageBarHorizontalFullLabel": "水平百分比条形图", "xpack.lens.xyVisualization.stackedPercentageBarHorizontalLabel": "水平百分比条形图", "xpack.lens.xyVisualization.stackedPercentageBarLabel": "百分比条形图", "xpack.lens.xyVisualization.xyLabel": "XY", @@ -17242,7 +17237,6 @@ "xpack.securitySolution.case.common.noConnector": "未选择任何连接器", "xpack.securitySolution.case.components.connectors.case.actionTypeTitle": "案例", "xpack.securitySolution.case.components.connectors.case.addNewCaseOption": "添加新案例", - "xpack.securitySolution.case.components.connectors.case.callOutInfo": "规则创建后的所有告警将追加到选定案例。", "xpack.securitySolution.case.components.connectors.case.caseRequired": "必须选择策略。", "xpack.securitySolution.case.components.connectors.case.casesDropdownPlaceholder": "选择案例", "xpack.securitySolution.case.components.connectors.case.casesDropdownRowLabel": "案例", diff --git a/x-pack/plugins/triggers_actions_ui/README.md b/x-pack/plugins/triggers_actions_ui/README.md index 61cad0fc7fd7b..54e627d384936 100644 --- a/x-pack/plugins/triggers_actions_ui/README.md +++ b/x-pack/plugins/triggers_actions_ui/README.md @@ -1149,7 +1149,7 @@ triggersActionsUi.actionTypeRegistry.register(getSomeNewActionType()); ## Create and register new action type UI -Before starting the UI implementation, the [server side registration](https://github.com/elastic/kibana/tree/master/x-pack/plugins/actions#kibana-actions-configuration) should be done first. +Before starting the UI implementation, the [server side registration](https://github.com/elastic/kibana/tree/master/x-pack/plugins/actions#action-types) should be done first. Action type UI is expected to be defined as `ActionTypeModel` object. diff --git a/x-pack/plugins/watcher/public/plugin.ts b/x-pack/plugins/watcher/public/plugin.ts index 9cc0b1bbe99a8..6c6d6f1169658 100644 --- a/x-pack/plugins/watcher/public/plugin.ts +++ b/x-pack/plugins/watcher/public/plugin.ts @@ -6,9 +6,10 @@ */ import { i18n } from '@kbn/i18n'; -import { CoreSetup, Plugin, CoreStart } from 'kibana/public'; +import { CoreSetup, Plugin, CoreStart, Capabilities } from 'kibana/public'; import { first, map, skip } from 'rxjs/operators'; +import { Subject, combineLatest } from 'rxjs'; import { FeatureCatalogueCategory } from '../../../../src/plugins/home/public'; import { LicenseStatus } from '../common/types/license_status'; @@ -26,6 +27,8 @@ const licenseToLicenseStatus = (license: ILicense): LicenseStatus => { }; export class WatcherUIPlugin implements Plugin<void, void, Dependencies, any> { + private capabilities$: Subject<Capabilities> = new Subject(); + setup( { notifications, http, uiSettings, getStartServices }: CoreSetup, { licensing, management, data, home, charts }: Dependencies @@ -99,13 +102,16 @@ export class WatcherUIPlugin implements Plugin<void, void, Dependencies, any> { home.featureCatalogue.register(watcherHome); - licensing.license$.pipe(first(), map(licenseToLicenseStatus)).subscribe(({ valid }) => { + combineLatest([ + licensing.license$.pipe(first(), map(licenseToLicenseStatus)), + this.capabilities$, + ]).subscribe(([{ valid }, capabilities]) => { // NOTE: We enable the plugin by default instead of disabling it by default because this // creates a race condition that can cause the app nav item to not render in the side nav. // The race condition still exists, but it will result in the item rendering when it shouldn't // (e.g. on a license it's not available for), instead of *not* rendering when it *should*, // which is a less frustrating UX. - if (valid) { + if (valid && capabilities.management.insightsAndAlerting?.watcher === true) { watcherESApp.enable(); } else { watcherESApp.disable(); @@ -113,7 +119,9 @@ export class WatcherUIPlugin implements Plugin<void, void, Dependencies, any> { }); } - start(core: CoreStart) {} + start(core: CoreStart) { + this.capabilities$.next(core.application.capabilities); + } stop() {} } diff --git a/x-pack/test/api_integration/apis/security_solution/timeline_details.ts b/x-pack/test/api_integration/apis/security_solution/timeline_details.ts index 296e497eb4952..d653528fd47e2 100644 --- a/x-pack/test/api_integration/apis/security_solution/timeline_details.ts +++ b/x-pack/test/api_integration/apis/security_solution/timeline_details.ts @@ -20,96 +20,133 @@ const EXPECTED_DATA = [ field: '@timestamp', values: ['2019-02-10T02:39:44.107Z'], originalValue: ['2019-02-10T02:39:44.107Z'], + isObjectArray: false, }, { category: '@version', field: '@version', values: ['1'], originalValue: ['1'], + isObjectArray: false, + }, + { + category: '_id', + field: '_id', + values: ['QRhG1WgBqd-n62SwZYDT'], + originalValue: ['QRhG1WgBqd-n62SwZYDT'], + isObjectArray: false, + }, + { + category: '_index', + field: '_index', + values: ['filebeat-7.0.0-iot-2019.06'], + originalValue: ['filebeat-7.0.0-iot-2019.06'], + isObjectArray: false, + }, + { + category: '_score', + field: '_score', + values: ['1'], + originalValue: ['1'], + isObjectArray: false, }, { category: 'agent', field: 'agent.ephemeral_id', values: ['909cd6a1-527d-41a5-9585-a7fb5386f851'], originalValue: ['909cd6a1-527d-41a5-9585-a7fb5386f851'], + isObjectArray: false, }, { category: 'agent', field: 'agent.hostname', values: ['raspberrypi'], originalValue: ['raspberrypi'], + isObjectArray: false, }, { category: 'agent', field: 'agent.id', values: ['4d3ea604-27e5-4ec7-ab64-44f82285d776'], originalValue: ['4d3ea604-27e5-4ec7-ab64-44f82285d776'], + isObjectArray: false, }, { category: 'agent', field: 'agent.type', values: ['filebeat'], originalValue: ['filebeat'], + isObjectArray: false, }, { category: 'agent', field: 'agent.version', values: ['7.0.0'], originalValue: ['7.0.0'], + isObjectArray: false, }, { category: 'destination', field: 'destination.domain', values: ['s3-iad-2.cf.dash.row.aiv-cdn.net'], originalValue: ['s3-iad-2.cf.dash.row.aiv-cdn.net'], + isObjectArray: false, }, { category: 'destination', field: 'destination.ip', values: ['10.100.7.196'], originalValue: ['10.100.7.196'], + isObjectArray: false, }, { category: 'destination', field: 'destination.port', values: ['40684'], originalValue: ['40684'], + isObjectArray: false, }, { category: 'ecs', field: 'ecs.version', values: ['1.0.0-beta2'], originalValue: ['1.0.0-beta2'], + isObjectArray: false, }, { category: 'event', field: 'event.dataset', values: ['suricata.eve'], originalValue: ['suricata.eve'], + isObjectArray: false, }, { category: 'event', field: 'event.end', values: ['2019-02-10T02:39:44.107Z'], originalValue: ['2019-02-10T02:39:44.107Z'], + isObjectArray: false, }, { category: 'event', field: 'event.kind', values: ['event'], originalValue: ['event'], + isObjectArray: false, }, { category: 'event', field: 'event.module', values: ['suricata'], originalValue: ['suricata'], + isObjectArray: false, }, { category: 'event', field: 'event.type', values: ['fileinfo'], originalValue: ['fileinfo'], + isObjectArray: false, }, { category: 'file', @@ -120,270 +157,484 @@ const EXPECTED_DATA = [ originalValue: [ '/dm/2$XTMWANo0Q2RZKlH-95UoAahZrOg~/0a9a/bf72/e1da/4c20-919e-0cbabcf7bfe8/75f50c57-d25f-4e97-9e37-01b9f5caa293_audio_13.mp4', ], + isObjectArray: false, }, { category: 'file', field: 'file.size', values: ['48277'], originalValue: ['48277'], + isObjectArray: false, }, { category: 'fileset', field: 'fileset.name', values: ['eve'], originalValue: ['eve'], + isObjectArray: false, }, { category: 'flow', field: 'flow.locality', values: ['public'], originalValue: ['public'], + isObjectArray: false, }, { category: 'host', field: 'host.architecture', values: ['armv7l'], originalValue: ['armv7l'], + isObjectArray: false, + }, + { + category: 'host', + field: 'host.containerized', + values: ['false'], + originalValue: ['false'], + isObjectArray: false, }, { category: 'host', field: 'host.hostname', values: ['raspberrypi'], originalValue: ['raspberrypi'], + isObjectArray: false, }, { category: 'host', field: 'host.id', values: ['b19a781f683541a7a25ee345133aa399'], originalValue: ['b19a781f683541a7a25ee345133aa399'], + isObjectArray: false, }, { category: 'host', field: 'host.name', values: ['raspberrypi'], originalValue: ['raspberrypi'], + isObjectArray: false, }, { category: 'host', field: 'host.os.codename', values: ['stretch'], originalValue: ['stretch'], + isObjectArray: false, }, { category: 'host', field: 'host.os.family', values: [''], originalValue: [''], + isObjectArray: false, }, { category: 'host', field: 'host.os.kernel', values: ['4.14.50-v7+'], originalValue: ['4.14.50-v7+'], + isObjectArray: false, }, { category: 'host', field: 'host.os.name', values: ['Raspbian GNU/Linux'], originalValue: ['Raspbian GNU/Linux'], + isObjectArray: false, }, { category: 'host', field: 'host.os.platform', values: ['raspbian'], originalValue: ['raspbian'], + isObjectArray: false, }, { category: 'host', field: 'host.os.version', values: ['9 (stretch)'], originalValue: ['9 (stretch)'], + isObjectArray: false, }, { category: 'http', field: 'http.request.method', values: ['get'], originalValue: ['get'], + isObjectArray: false, }, { category: 'http', field: 'http.response.body.bytes', values: ['48277'], originalValue: ['48277'], + isObjectArray: false, }, { category: 'http', field: 'http.response.status_code', values: ['206'], originalValue: ['206'], + isObjectArray: false, }, { category: 'input', field: 'input.type', values: ['log'], originalValue: ['log'], + isObjectArray: false, }, { category: 'base', field: 'labels.pipeline', values: ['filebeat-7.0.0-suricata-eve-pipeline'], originalValue: ['filebeat-7.0.0-suricata-eve-pipeline'], + isObjectArray: false, }, { category: 'log', field: 'log.file.path', values: ['/var/log/suricata/eve.json'], originalValue: ['/var/log/suricata/eve.json'], + isObjectArray: false, }, { category: 'log', field: 'log.offset', values: ['1856288115'], originalValue: ['1856288115'], + isObjectArray: false, }, { category: 'network', field: 'network.name', values: ['iot'], originalValue: ['iot'], + isObjectArray: false, }, { category: 'network', field: 'network.protocol', values: ['http'], originalValue: ['http'], + isObjectArray: false, }, { category: 'network', field: 'network.transport', values: ['tcp'], originalValue: ['tcp'], + isObjectArray: false, }, { category: 'service', field: 'service.type', values: ['suricata'], originalValue: ['suricata'], + isObjectArray: false, }, { category: 'source', field: 'source.as.num', values: ['16509'], originalValue: ['16509'], + isObjectArray: false, }, { category: 'source', field: 'source.as.org', values: ['Amazon.com, Inc.'], originalValue: ['Amazon.com, Inc.'], + isObjectArray: false, }, { category: 'source', field: 'source.domain', values: ['server-54-239-219-210.jfk51.r.cloudfront.net'], originalValue: ['server-54-239-219-210.jfk51.r.cloudfront.net'], + isObjectArray: false, }, { category: 'source', field: 'source.geo.city_name', values: ['Seattle'], originalValue: ['Seattle'], + isObjectArray: false, }, { category: 'source', field: 'source.geo.continent_name', values: ['North America'], originalValue: ['North America'], + isObjectArray: false, }, { category: 'source', field: 'source.geo.country_iso_code', values: ['US'], originalValue: ['US'], + isObjectArray: false, + }, + { + category: 'source', + field: 'source.geo.location', + values: ['{"lon":-122.3341,"lat":47.6103}'], + originalValue: ['{"lon":-122.3341,"lat":47.6103}'], + isObjectArray: true, }, { category: 'source', field: 'source.geo.location.lat', values: ['47.6103'], originalValue: ['47.6103'], + isObjectArray: false, }, { category: 'source', field: 'source.geo.location.lon', values: ['-122.3341'], originalValue: ['-122.3341'], + isObjectArray: false, }, { category: 'source', field: 'source.geo.region_iso_code', values: ['US-WA'], originalValue: ['US-WA'], + isObjectArray: false, }, { category: 'source', field: 'source.geo.region_name', values: ['Washington'], originalValue: ['Washington'], + isObjectArray: false, }, { category: 'source', field: 'source.ip', values: ['54.239.219.210'], originalValue: ['54.239.219.210'], + isObjectArray: false, }, { category: 'source', field: 'source.port', values: ['80'], originalValue: ['80'], + isObjectArray: false, + }, + { + category: 'suricata', + field: 'suricata.eve.app_proto', + values: ['http'], + originalValue: ['http'], + isObjectArray: false, + }, + { + category: 'suricata', + field: 'suricata.eve.dest_ip', + values: ['10.100.7.196'], + originalValue: ['10.100.7.196'], + isObjectArray: false, + }, + { + category: 'suricata', + field: 'suricata.eve.dest_port', + values: ['40684'], + originalValue: ['40684'], + isObjectArray: false, + }, + { + category: 'suricata', + field: 'suricata.eve.fileinfo.filename', + values: [ + '/dm/2$XTMWANo0Q2RZKlH-95UoAahZrOg~/0a9a/bf72/e1da/4c20-919e-0cbabcf7bfe8/75f50c57-d25f-4e97-9e37-01b9f5caa293_audio_13.mp4', + ], + originalValue: [ + '/dm/2$XTMWANo0Q2RZKlH-95UoAahZrOg~/0a9a/bf72/e1da/4c20-919e-0cbabcf7bfe8/75f50c57-d25f-4e97-9e37-01b9f5caa293_audio_13.mp4', + ], + isObjectArray: false, + }, + { + category: 'suricata', + field: 'suricata.eve.fileinfo.size', + values: ['48277'], + originalValue: ['48277'], + isObjectArray: false, }, { category: 'suricata', field: 'suricata.eve.fileinfo.state', values: ['CLOSED'], originalValue: ['CLOSED'], + isObjectArray: false, + }, + { + category: 'suricata', + field: 'suricata.eve.fileinfo.stored', + values: ['false'], + originalValue: ['false'], + isObjectArray: false, }, { category: 'suricata', field: 'suricata.eve.fileinfo.tx_id', values: ['301'], originalValue: ['301'], + isObjectArray: false, }, { category: 'suricata', field: 'suricata.eve.flow_id', values: ['196625917175466'], originalValue: ['196625917175466'], + isObjectArray: false, + }, + { + category: 'suricata', + field: 'suricata.eve.http.hostname', + values: ['s3-iad-2.cf.dash.row.aiv-cdn.net'], + originalValue: ['s3-iad-2.cf.dash.row.aiv-cdn.net'], + isObjectArray: false, }, { category: 'suricata', field: 'suricata.eve.http.http_content_type', values: ['video/mp4'], originalValue: ['video/mp4'], + isObjectArray: false, + }, + { + category: 'suricata', + field: 'suricata.eve.http.http_method', + values: ['get'], + originalValue: ['get'], + isObjectArray: false, + }, + { + category: 'suricata', + field: 'suricata.eve.http.length', + values: ['48277'], + originalValue: ['48277'], + isObjectArray: false, }, { category: 'suricata', field: 'suricata.eve.http.protocol', values: ['HTTP/1.1'], originalValue: ['HTTP/1.1'], + isObjectArray: false, + }, + { + category: 'suricata', + field: 'suricata.eve.http.status', + values: ['206'], + originalValue: ['206'], + isObjectArray: false, + }, + { + category: 'suricata', + field: 'suricata.eve.http.url', + values: [ + '/dm/2$XTMWANo0Q2RZKlH-95UoAahZrOg~/0a9a/bf72/e1da/4c20-919e-0cbabcf7bfe8/75f50c57-d25f-4e97-9e37-01b9f5caa293_audio_13.mp4', + ], + originalValue: [ + '/dm/2$XTMWANo0Q2RZKlH-95UoAahZrOg~/0a9a/bf72/e1da/4c20-919e-0cbabcf7bfe8/75f50c57-d25f-4e97-9e37-01b9f5caa293_audio_13.mp4', + ], + isObjectArray: false, }, { category: 'suricata', field: 'suricata.eve.in_iface', values: ['eth0'], originalValue: ['eth0'], + isObjectArray: false, + }, + { + category: 'suricata', + field: 'suricata.eve.proto', + values: ['tcp'], + originalValue: ['tcp'], + isObjectArray: false, + }, + { + category: 'suricata', + field: 'suricata.eve.src_ip', + values: ['54.239.219.210'], + originalValue: ['54.239.219.210'], + isObjectArray: false, + }, + { + category: 'suricata', + field: 'suricata.eve.src_port', + values: ['80'], + originalValue: ['80'], + isObjectArray: false, + }, + { + category: 'suricata', + field: 'suricata.eve.timestamp', + values: ['2019-02-10T02:39:44.107Z'], + originalValue: ['2019-02-10T02:39:44.107Z'], + isObjectArray: false, }, { category: 'base', field: 'tags', values: ['suricata'], originalValue: ['suricata'], + isObjectArray: false, + }, + { + category: 'traefik', + field: 'traefik.access.geoip.city_name', + values: ['Seattle'], + originalValue: ['Seattle'], + isObjectArray: false, + }, + { + category: 'traefik', + field: 'traefik.access.geoip.continent_name', + values: ['North America'], + originalValue: ['North America'], + isObjectArray: false, + }, + { + category: 'traefik', + field: 'traefik.access.geoip.country_iso_code', + values: ['US'], + originalValue: ['US'], + isObjectArray: false, + }, + { + category: 'traefik', + field: 'traefik.access.geoip.location', + values: ['{"lon":-122.3341,"lat":47.6103}'], + originalValue: ['{"lon":-122.3341,"lat":47.6103}'], + isObjectArray: true, + }, + { + category: 'traefik', + field: 'traefik.access.geoip.region_iso_code', + values: ['US-WA'], + originalValue: ['US-WA'], + isObjectArray: false, + }, + { + category: 'traefik', + field: 'traefik.access.geoip.region_name', + values: ['Washington'], + originalValue: ['Washington'], + isObjectArray: false, }, { category: 'url', field: 'url.domain', values: ['s3-iad-2.cf.dash.row.aiv-cdn.net'], originalValue: ['s3-iad-2.cf.dash.row.aiv-cdn.net'], + isObjectArray: false, }, { category: 'url', @@ -394,6 +645,7 @@ const EXPECTED_DATA = [ originalValue: [ '/dm/2$XTMWANo0Q2RZKlH-95UoAahZrOg~/0a9a/bf72/e1da/4c20-919e-0cbabcf7bfe8/75f50c57-d25f-4e97-9e37-01b9f5caa293_audio_13.mp4', ], + isObjectArray: false, }, { category: 'url', @@ -404,27 +656,9 @@ const EXPECTED_DATA = [ originalValue: [ '/dm/2$XTMWANo0Q2RZKlH-95UoAahZrOg~/0a9a/bf72/e1da/4c20-919e-0cbabcf7bfe8/75f50c57-d25f-4e97-9e37-01b9f5caa293_audio_13.mp4', ], - }, - { - category: '_index', - field: '_index', - values: ['filebeat-7.0.0-iot-2019.06'], - originalValue: ['filebeat-7.0.0-iot-2019.06'], - }, - { - category: '_id', - field: '_id', - values: ['QRhG1WgBqd-n62SwZYDT'], - originalValue: ['QRhG1WgBqd-n62SwZYDT'], - }, - { - category: '_score', - field: '_score', - values: ['1'], - originalValue: ['1'], + isObjectArray: false, }, ]; - const EXPECTED_KPI_COUNTS = { destinationIpCount: 154, hostCount: 1, @@ -456,7 +690,7 @@ export default function ({ getService }: FtrProviderContext) { wait_for_completion_timeout: '10s', }) .expect(200); - expect(sortBy(detailsData, 'name')).to.eql(sortBy(EXPECTED_DATA, 'name')); + expect(sortBy(detailsData, 'field')).to.eql(sortBy(EXPECTED_DATA, 'field')); }); it('Make sure that we get kpi data', async () => { diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_rules.ts index 8d494724d9f76..6bdf881ba8ca2 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_rules.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_rules.ts @@ -138,7 +138,7 @@ export default ({ getService }: FtrProviderContext) => { expect(statusBody[body.id].current_status.status).to.eql('warning'); expect(statusBody[body.id].current_status.last_success_message).to.eql( - 'The following index patterns did not match any indices: ["does-not-exist-*"]' + 'This rule is attempting to query data from Elasticsearch indices listed in the "Index pattern" section of the rule definition, however no index matching: ["does-not-exist-*"] was found. This warning will continue to appear until a matching index is created or this rule is de-activated.' ); }); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_threat_matching.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_threat_matching.ts index 9da98e316315d..59526fd5abb8f 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_threat_matching.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_threat_matching.ts @@ -35,7 +35,8 @@ export default ({ getService }: FtrProviderContext) => { /** * Specific api integration tests for threat matching rule type */ - describe('create_threat_matching', () => { + // FLAKY: https://github.com/elastic/kibana/issues/93152 + describe.skip('create_threat_matching', () => { describe('validation errors', () => { it('should give an error that the index must exist first if it does not exist before creating a rule', async () => { const { body } = await supertest diff --git a/x-pack/test/functional/apps/lens/dashboard.ts b/x-pack/test/functional/apps/lens/dashboard.ts index 0d2db53ba73af..a15176d76f953 100644 --- a/x-pack/test/functional/apps/lens/dashboard.ts +++ b/x-pack/test/functional/apps/lens/dashboard.ts @@ -120,7 +120,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { '[data-test-subj="embeddablePanelHeading-lnsPieVis"]', 'lnsPieVis' ); - const hasGeoDestFilter = await filterBar.hasFilter('geo.dest', 'LS'); + const hasGeoDestFilter = await filterBar.hasFilter('geo.dest', 'AL'); expect(hasGeoDestFilter).to.be(true); await filterBar.addFilter('geo.src', 'is', 'US'); await filterBar.toggleFilterPinned('geo.src'); diff --git a/x-pack/test/functional/page_objects/lens_page.ts b/x-pack/test/functional/page_objects/lens_page.ts index d9ec9ca5d3f62..2ecf6f3163d7e 100644 --- a/x-pack/test/functional/page_objects/lens_page.ts +++ b/x-pack/test/functional/page_objects/lens_page.ts @@ -418,19 +418,20 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont * @param subVisualizationId - the ID of the sub-visualization to switch to, such as * lnsDatatable or bar_stacked */ - async switchToVisualization(subVisualizationId: string) { + async switchToVisualization(subVisualizationId: string, searchTerm?: string) { await this.openChartSwitchPopover(); + await this.searchOnChartSwitch(subVisualizationId, searchTerm); await testSubjects.click(`lnsChartSwitchPopover_${subVisualizationId}`); await PageObjects.header.waitUntilLoadingHasFinished(); }, async openChartSwitchPopover() { - if (await testSubjects.exists('visTypeTitle')) { + if (await testSubjects.exists('lnsChartSwitchList')) { return; } await retry.try(async () => { await testSubjects.click('lnsChartSwitchPopover'); - await testSubjects.existOrFail('visTypeTitle'); + await testSubjects.existOrFail('lnsChartSwitchList'); }); }, @@ -451,17 +452,28 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont return errors?.length ?? 0; }, + async searchOnChartSwitch(subVisualizationId: string, searchTerm?: string) { + // Because the new chart switcher is now a virtualized list, the process needs some help + // So either pass a search string or pick the last 3 letters from the id (3 because pie + // is the smallest chart name) and use them to search + const queryTerm = searchTerm ?? subVisualizationId.substring(subVisualizationId.length - 3); + return await testSubjects.setValue('lnsChartSwitchSearch', queryTerm, { + clearWithKeyboard: true, + }); + }, + /** * Checks a specific subvisualization in the chart switcher for a "data loss" indicator * * @param subVisualizationId - the ID of the sub-visualization to switch to, such as * lnsDatatable or bar_stacked */ - async hasChartSwitchWarning(subVisualizationId: string) { + async hasChartSwitchWarning(subVisualizationId: string, searchTerm?: string) { await this.openChartSwitchPopover(); + await this.searchOnChartSwitch(subVisualizationId, searchTerm); const element = await testSubjects.find(`lnsChartSwitchPopover_${subVisualizationId}`); - return await find.descendantExistsByCssSelector( - '.euiKeyPadMenuItem__betaBadgeWrapper', + return await testSubjects.descendantExists( + `lnsChartSwitchPopoverAlert_${subVisualizationId}`, element ); },