diff --git a/.i18nrc.json b/.i18nrc.json index 4a516f23ebf05d..d4286a7bd50e0f 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -48,7 +48,7 @@ "visDefaultEditor": "src/plugins/vis_default_editor", "visTypeMarkdown": "src/plugins/vis_type_markdown", "visTypeMetric": "src/plugins/vis_type_metric", - "visTypeTable": "src/legacy/core_plugins/vis_type_table", + "visTypeTable": "src/plugins/vis_type_table", "visTypeTagCloud": "src/legacy/core_plugins/vis_type_tagcloud", "visTypeTimeseries": ["src/legacy/core_plugins/vis_type_timeseries", "src/plugins/vis_type_timeseries"], "visTypeVega": "src/legacy/core_plugins/vis_type_vega", diff --git a/docs/CHANGELOG.asciidoc b/docs/CHANGELOG.asciidoc index d0c30d7c4e5ae4..2f7dd0ba7fd478 100644 --- a/docs/CHANGELOG.asciidoc +++ b/docs/CHANGELOG.asciidoc @@ -10,6 +10,7 @@ This section summarizes the changes in each release. +* <> * <> * <> * <> @@ -35,6 +36,312 @@ This section summarizes the changes in each release. * <> -- + +[[release-notes-7.7.0]] +== {kib} 7.7.0 + +See <>. + +[float] +[[known-issues-7.7.0]] +=== Known issues + +SIEM:: +* When you deactivate an action within a rule, the rule fails {issue}620[#620] +* When you add a timestamp to the PagerDuty action, the rule fails {issue}607[#607] + +[float] +[[enhancement-7.7.0]] +=== Enhancements +Alerting:: +* Notifies user when security is enabled but TLS is not {pull}60270[#60270] +* Displays warning when a permanent encryption key is missing and hides alerting UI appropriately {pull}62772[#62772] +* Edits alert flyout {pull}58964[#58964] +* Moves index params fields to connector config {pull}60349[#60349] +* Adds the AlertDetails page {pull}55671[#55671] +* License checks for actions plugin {pull}59070[#59070] +APM:: +* Updates monospace font family variable {pull}57555[#57555] +* Shows missing permissions message to the user on the Services overview {pull}56374[#56374] +* Settings list page for managing custom actions {pull}56853[#56853] +* Divides "Actions menu" into sections to improve readability {pull}56623[#56623] +* Creates settings page to manage Custom Links {pull}57788[#57788] +* Creates custom link from Trace summary {pull}59648[#59648] +* Writes tests for the Custom Link API {pull}60899[#60899] +* Threshold alerts {pull}59566[#59566] +* Adds additional (java) options {pull}59860[#59860] +* Sync badge {pull}55113[#55113] +* Client.ip to metadata for RUM transactions {pull}56546[#56546] +Canvas:: +* Adds Lens embeddables {pull}57499[#57499] +* Switches to using EUI SuperDatePicker in time filter element {pull}59249[#59249] +* Adds Visualize embeddable {pull}60859[#60859] +* Adds argument to open all links in new tab within markdown element {pull}57017[#57017] +* Updates esdocs datasource {pull}59512[#59512] +* Improves expression autocomplete {pull}52035[#52035] +Dashboard:: +* Use Elasticsearch `_async_search` instead of `_search` when it is available (excluding TSVB, Timelion, and Vega) {pull}59224[#59224} +* When queries run more than 10 seconds, show a pop-up to allow users to run the queries beyond the configured timeout or cancel the queries {pull}60706[#60706] +* Dashboard/add panel flow {pull}59918[#59918] +* Moves the "Create New" button in add panel flyout to the top to make it more visible to the user {pull}56428[#56428] +Lens and visualizations:: +* Creates Lens filters on click with bar, line, area charts {pull}57261[#57261] +* Allows number formatting within Lens {pull}56253[#56253] +* Shows a warning when you have partially configured a visualization, such as a bar chart with only an X axis {pull}58279[#58279] +* Improves suggestion logic when dragging fields into the chart {pull}60687[#60687] +* Disallows duplicate percentiles {pull}58299[#58299] +* EUICodeEditor for Visualize JSON {pull}58679[#58679] +* Supports Histogram Data Type {pull}59387[#59387] +* Median aggregation labels now show "Median" instead of "50th percentile of" in Visualize. Custom labels are also used {pull}58521[#58521] +* Adds positive_rate as a new aggregation to TSVB {pull}59843[#59843] +* Makes linked saved search work when user navigates back using browser back button {pull}59690[#59690] +* Visualization editor UI has been updated to the new styles, consistent with the rest of the platform and a more logical left-to-right flow of creating content {pull}49864[#49864] +Logs:: +* Uses the Super date picker in the log stream {pull}54280[#54280] +* Adds expandable rows with category examples {pull}54586[#54586] +* Shows navigation bar while loading source configuration {pull}59997[#59997] +Machine Learning:: +* Processes delimited files like semi-structured text {pull}56038[#56038] +* Supports multi-line JSON notation {pull}58870[#58870] +* Validates manual model memory input {pull}59056[#59056] +* Clones analytics job {pull}59791[#59791] +* Uses a new ML endpoint to estimate a model memory {pull}60376[#60376] +* Module setup with dynamic model memory estimation {pull}60656[#60656] +* Adds text fields to datafeed start modal {pull}55560[#55560] +* Categorization examples privilege check {pull}57375[#57375] +* Adds filebeat config to file dataviz {pull}58152[#58152] +* Global calendars {pull}57890[#57890] +* Adds indices_options to datafeed {pull}59119[#59119] +* Displays multi-class results in evaluate panel {pull}60760[#60760] +* Adds support for date_nanos time field in anomaly job wizard {pull}59017[#59017] +* Uses EuiDataGrid for outlier result page {pull}58235[#58235] +* Supports multi-line JSON notation in advanced editor {pull}58015[#58015] +* Adds support for percentiles aggregation to Transform wizard {pull}60763[#60763] +* Adds clone feature to transforms list {pull}57837[#57837] +* Uses EuiDataGrid for transform wizard {pull}52510[#52510] +* Replaces KqlFilterBar with QueryStringInput {pull}59723[#59723] +Management:: +* The Remote Clusters UI added support for enabling "proxy" mode when creating or editing a remote cluster {pull}59221[#59221] +* Adds filter for ILM phase to Index Management {pull}57402[#57402] +* Creates Painless Lab app {pull}57538[#57538] +* Moves out of legacy {pull}55331[#55331] +* Moves out of legacy and migrates server side to New Platform {pull}55690[#55690] +* Updates Console progress bar {pull}56628[#56628] +* Auto follow pause & resume {pull}56615[#56615] +* Supports triple quoted JSON strings and Painless highlighting to Watcher and SearchProfiler {pull}57563[#57563] +* Server-side batch reindexing {pull}58598[#58598] +* Better handling of closed indices {pull}58890[#58890] +* Advanced settings UI change to centralize save state {pull}53693[#53693] +* The autocomplete in the dev console now supports many different types of Elasticsearch pipeline processors {pull}60553[#60553] +Maps:: +* Improves Layer Style UI {pull}58406[#58406] +* Shows field type icons in data driven styling field select {pull}55166[#55166] +* Style icons by category {pull}55747[#55747] +* Adds type icons to SingleFieldSelect component {pull}56313[#56313] +* Disables style forms when they are not applied due to other style settings {pull}55858[#55858] +* Autocompletes for custom color palettes and custom icon palettes {pull}56446[#56446] +* Allows simultaneous opening of multiple tooltips {pull}57226[#57226] +* Adds Top term aggregation {pull}57875[#57875] +* Direct Discover "visualize" to open Maps application {pull}58549[#58549] +* Top term percentage field property {pull}59386[#59386] +* Adds UI to disable style meta and get top categories from current features {pull}59707[#59707] +* Adds draw control to create distance filter {pull}58163[#58163] +* Blended layer that switches between documents and clusters {pull}57879[#57879] +* Default ES document layer scaling type to clusters and show scaling UI in the create wizard {pull}60668[#60668] +* Disables add layer button when flyout is open {pull}54932[#54932] +* Supports categorical styling for numbers and dates {pull}57908[#57908] +Metrics:: +* Setup commonly used time ranges in timepicker {pull}56701[#56701] +* Custom Metrics for Inventory View {pull}58072[#58072] +* Alerting for metrics explorer and inventory {pull}58779[#58779] +* Creates a new menu for observability links {pull}54847[#54847] +* Creates Metric Threshold Alert Type and Executor {pull}57606[#57606] +Monitoring:: +* Supports shipping directly to the monitoring cluster {pull}57022[#57022] +Platform:: +* Improves validation in truncate field formatter editor {pull}56521[#56521] +* Variable support for interpreter {pull}54788[#54788] +Reporting:: +* Handles page setup errors and capture the page, don't fail the job {pull}58683[#58683] +* Adds the ability to search and delete historical reports in Management > Kibana > Reporting {pull}60077[#60077] +SIEM:: +* Recent cases widget {pull}60993[#60993] +* Adds custom reputation link {pull}57814[#57814] +* Exports timeline {pull}58368[#58368] +* Rule activity monitoring {pull}60816[#60816] +* Removes has manage api keys requirement {pull}62446[#62446] +* Adds release notes link and updates one UI section {pull}60825[#60825] +* Adds rule notifications {pull}59004[#59004] +* Version 7.7 rule import {pull}61903[#61903] +* Creates ML Rules {pull}58053[#58053] +* Case workflow api schema {pull}51535[#51535] +* Service Now {kib} Action {pull}53890[#53890] +* API with io-ts validation {pull}59265[#59265] +* Status / Batch update {pull}59856[#59856] +* Imports timeline {pull}60880[#60880] +* Bug/clean up phase I {pull}61354[#61354] +* Cases clean up Phase II {pull}61750[#61750] +* Modifies gap detection util to accept all dateMath formats {pull}56055[#56055] +* Adds note markdown field to backend {pull}59796[#59796] +* Adds rule markdown field to rule create, detail, and edit flows {pull}60108[#60108] +* Adds rule markdown to timeline global notes {pull}61026[#61026] +* ServiceNow executor {pull}58894[#58894] +* ServiceNow action improvements {pull}60052[#60052] +Security:: +* Uses links instead of click handlers when switching spaces {pull}57730[#57730] +* Introduce a login selector screen when multiple auth providers are enabled {pull}53010[#53010] +* Warn when using deprecated roles {pull}57209[#57209] +* Support for subfeature privileges {pull}60563[#60563] +Telemetry:: +* Application Usage implemented in @kbn/analytics {pull}58401[#58401] +* Server-side Migration to NP {pull}60485[#60485] +* Use EuiTokens for ES field types {pull}57911[#57911] +* Adds 7 day metrics to Application Usage telemetry {pull}59846[#59846] +Uptime:: +* Adds Settings Page {pull}53550[#53550] +* Adds Alerting UI {pull}57919[#57919] +* Adds configurable page size to monitor list {pull}60573[#60573] +* Adds Green Icon for all up Monitors {pull}56770[#56770] +* Implements drag and select on charts {pull}57089[#57089] +* Fix/filter group autocomplete {pull}57686[#57686] +* Ml detection of duration anomalies {pull}59785[#59785] + +[float] +[[bug-7.7.0]] +=== Bug fixes +Alerting:: +* Retains empty AlertsList when filter has removed all items {pull}60501[#60501] +* Fixes alert threshold line disappears {pull}61499[#61499] +* Cleanup action task params objects after successful execution {pull}55227[#55227] +* Disables action plugin functionality when ESO plugin is using an ephemeral encryption key {pull}56906[#56906] +* Makes slack param validation handle empty messages {pull}60468[#60468] +* Makes user and password secrets optional {pull}56823[#56823] +APM:: +* Changes "url" to "urls" in APM agent instructions {pull}60790[#60790] +* Uses ES Permission API to check if a user has permissions to read from APM indices {pull}57311[#57311] +* Filters are not prefilled when the custom link flyout is opened from a transaction page {pull}61650[#61650] +* .apm-agent-configuration is not created if {kib} is started while ES is not ready {pull}61610[#61610] +* Don’t include UI filters when fetching a specific transaction {pull}57934[#57934] +* Uses docLinks API for APM doc links {pull}61880[#61880] +* Updates APM index pattern {pull}61265[#61265] +Canvas:: +* Toggles footer editable controls when you turn off edit mode #52786 {pull}58044[#58044] +* Fixes map embeddables not showing up on PDF reports {pull}61149[#61149] +* Limits rows in debug element {pull}60804[#60804] +Dashboard:: +* Puts embed param into short url instead of behind it {pull}58846[#58846] +* Allows markdown in error embeddable {pull}62427[#62427] +Discover:: +* Removes flickering when opening filter bar popover {pull}56222[#56222] +* Retains pinned filters when loading and clearing saved queries {pull}54307[#54307] +Graph:: +* Specifies valid licenses for the Graph feature {pull}55911[#55911] +* Improves graph missing workspace error message {pull}58876[#58876] +Lens and visualizations:: +* Filters out pinned filters from saved object of Lens {pull}57197[#57197] +* Adds using queries/filters for field existence endpoint {pull}59033[#59033] +* Fixes display single bar in XYChart Bar Vis {pull}61452[#61452] +* Resetting a layer generates new suggestions {pull}60674[#60674] +* Fixes disabled switches in the editor {pull}62911[#62911] +* Fixes broken Handlebar documentation links {pull}55866[#55866] +* Shows timepicker in Timelion and TSVB {pull}58857[#58857] +* Makes Vega remove filter work {pull}58871[#58871] +* Makes d3 place nicely with object values {pull}62004[#62004] +* Fixes position calculation of ticks in non-horizontal axes {pull}62309[#62309] +Logs:: +* Correctly update the expanded log rate table rows {pull}60306[#60306] +Machine Learning:: +* Handles Empty Partition Field Values in Single Metric Viewer {pull}61649[#61649] +* Fixes job wizard model memory limit warnings {pull}62331[#62331] +* Files data viz fix index pattern warning after index change {pull}57807[#57807] +* Uses real datafeed ID for datafeed preview {pull}60275[#60275] +* Disables start trial option when license management ui is disabled {pull}60987[#60987] +* Fixes jobs list filter in url {pull}61822[#61822] +* Fixes job ID in edit job flyout {pull}61840[#61840] +* Fixes reporting of http request errors {pull}61811[#61811] +* Ensures confusion matrix label column is correct {pull}60308[#60308] +* Ensures column in correct position after reselect {pull}61342[#61342] +* Ensures query bar syntax errors are shown {pull}61333[#61333] +* Ensures job state is up to date {pull}61678[#61678] +* Increases number of items that can be paged in calendars and filters lists {pull}61842[#61842] +* Uses index pattern field format if one exists {pull}61709[#61709] +* Ensures filter works as expected {pull}62041[#62041] +* Ensures destination index pattern created {pull}62450[#62450] +* Fixes page heading structure {pull}56741[#56741] +* Fixes handling of index pattern with special characters {pull}59884[#59884] +* Fixes to error handling for analytics jobs and file data viz {pull}60249[#60249] +* Fixes Anomaly Explorer swimlane label and chart tooltips {pull}61327[#61327] +* Prevents training_percent of 0 for analytics job {pull}61789[#61789] +* Removes duplicate page main landmarks {pull}56883[#56883] +* Fixes license check {pull}58343[#58343] +* Clears {kib} index pattern cache on creation or form reset {pull}62184[#62184] +Management:: +* Adds support for additional watch action statuses {pull}55092[#55092] +* Fixes the Upgrade Assistant where the reindexing of an index was incorrectly marked as "Done", when it still required to be reindexed. This scenario could occur if a user reindexed an index, deleted it, then restored a snapshot of the index of an older version {pull}60789[#60789] +* Fixes several invalid documentation links in the Snapshot and Restore UI {pull}61331[#61331] +* Fixes for console error handling and loading of autocomplete {pull}58587[#58587] +* Fixes a bug that caused Grokdebugger simulation to break in non-Default Kibana spaces {pull}61423[#61423] +* Fixes an issue where Console would not render the request output if localStorage quota was reached {pull}62424[#62424] +* Fixes a bug with Console's Copy As cURL functionality that would not properly escape single quotes in JSON string values which created issues with copying SQL queries from Console to cURL {pull}63229[#63229] +* System index templates can't be edited {pull}55229[#55229] +* Not possible to edit a watch that was created with the API if the ID contains a dot {pull}59383[#59383] +* Fixes console a11y failures {pull}57520[#57520] +Maps:: +* Do not show border color for icon in legend when border width is zero {pull}57501[#57501] +* Uses blended layer when linking discover to maps {pull}61467[#61467] +* Fixes tooltip overflow {pull}61564[#61564] +* Cleans up unsaved state check {pull}61705[#61705] +* Fixes regression in loading left join fields {pull}63325[#63325] +* Fixes cross origin error for icon spritesheets when Kibana secured via OAuth proxy {pull}53896[#53896] +* Correctly open layer settings from add layer wizard {pull}48971[#48971] +Metrics:: +* Limits group by selector to only 2 fields {pull}56800[#56800] +* Uses CPU Usage limits for Kubernetes pods when available {pull}58424[#58424] +* Fixes toolbar popover for metrics table row {pull}56796[#56796] +Monitoring:: +* Handles setup mode if security is disabled {pull}53306[#53306] +* Protects against no monitoring data near end of time series {pull}61273[#61273] +* Adds new config for logging index name {pull}56920[#56920] +Platform:: +* Rollup index pattern error: must match one rollup index {pull}56732[#56732] +* In scripted fields, unable to switch the `Type` {pull}59285[#59285] +* Duplicates query filters in es request {pull}60106[#60106] +* Bugfix dashboard unpins filters {pull}62301[#62301] +* Fixes plugin enabled config options {pull}60998[#60998] +* Fixes tabifyAggResponse {pull}61214[#61214] +* Fixes parse interval {pull}62267[#62267] +* Avoid 'app not found' flickering while awaiting for mount {pull}56483[#56483] +* Creates empty string filters when value not specified {pull}57442[#57442] +* Range aggregations now use the field formatter from the index pattern, instead of no formatter {pull}58651[#58651] +Reporting:: +* Fixes error handling for job handler in route {pull}60161[#60161] +Security:: +* Handling a 404 when the space's telemetry collector runs {pull}55921[#55921] +SIEM:: +* Allows Import timeline for authorised users {pull}61438[#61438] +* Imports timeline schema update {pull}61622[#61622] +* Fixes bug with timeline templates not working {pull}60476[#60476] +* Fixes export of single rule and the icons {pull}62394[#62394] +* Updates process and TLS tables to use ECS 1.5 fields {pull}60854[#60854] +Telemetry:: +* Fixes bug introduced in #55859 {pull}57441[#57441] +* UI Metrics use findAll to retrieve all Saved Objects {pull}59891[#59891] +Uptime:: +* Updates heartbeat index name for 7.7 {pull}62172[#62172] +* Shows only total in snapshot heading {pull}58376[#58376] +* Fixes PingList pagination {pull}61481[#61481] +* Fixes es query function null reference errors {pull}61465[#61465] +* Fixes issue with Kibana Icon in Uptime App {pull}56837[#56837] +* Adds tests for pages {pull}56736[#56736] + +[float] +[[deprecation-7.7.0]] +=== Deprecations +Monitoring:: +* Changes all configs to `monitoring.*` {pull}54919[#54919], {pull}56215[#56215] +Platform:: +* Migrates Vega and Graph configs to new platform {pull}57011[#57011] + [[release-notes-7.6.2]] == {kib} 7.6.2 diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.__spec.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.__spec.md new file mode 100644 index 00000000000000..43ff9a930b974d --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.__spec.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [$$spec](./kibana-plugin-plugins-data-public.field.__spec.md) + +## Field.$$spec property + +Signature: + +```typescript +$$spec: FieldSpec; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield._constructor_.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field._constructor_.md similarity index 68% rename from docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield._constructor_.md rename to docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field._constructor_.md index cf7470c035a533..c3b2ac8d30b5a9 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield._constructor_.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field._constructor_.md @@ -1,8 +1,8 @@ -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [(constructor)](./kibana-plugin-plugins-data-public.indexpatternfield._constructor_.md) +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [(constructor)](./kibana-plugin-plugins-data-public.field._constructor_.md) -## IndexPatternField.(constructor) +## Field.(constructor) Constructs a new instance of the `Field` class diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.aggregatable.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.aggregatable.md new file mode 100644 index 00000000000000..fcfd7d73c8b0ce --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.aggregatable.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [aggregatable](./kibana-plugin-plugins-data-public.field.aggregatable.md) + +## Field.aggregatable property + +Signature: + +```typescript +aggregatable?: boolean; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.count.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.count.md new file mode 100644 index 00000000000000..4f51d88a3046ed --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.count.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [count](./kibana-plugin-plugins-data-public.field.count.md) + +## Field.count property + +Signature: + +```typescript +count?: number; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.displayname.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.displayname.md new file mode 100644 index 00000000000000..0846a7595cf907 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.displayname.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [displayName](./kibana-plugin-plugins-data-public.field.displayname.md) + +## Field.displayName property + +Signature: + +```typescript +displayName?: string; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.estypes.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.estypes.md new file mode 100644 index 00000000000000..efe1bceb43361a --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.estypes.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [esTypes](./kibana-plugin-plugins-data-public.field.estypes.md) + +## Field.esTypes property + +Signature: + +```typescript +esTypes?: string[]; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.filterable.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.filterable.md new file mode 100644 index 00000000000000..fd7be589e87a79 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.filterable.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [filterable](./kibana-plugin-plugins-data-public.field.filterable.md) + +## Field.filterable property + +Signature: + +```typescript +filterable?: boolean; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.format.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.format.md new file mode 100644 index 00000000000000..431e043d1fecc6 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.format.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [format](./kibana-plugin-plugins-data-public.field.format.md) + +## Field.format property + +Signature: + +```typescript +format: any; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.indexpattern.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.indexpattern.md new file mode 100644 index 00000000000000..59420747e0958e --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.indexpattern.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [indexPattern](./kibana-plugin-plugins-data-public.field.indexpattern.md) + +## Field.indexPattern property + +Signature: + +```typescript +indexPattern?: IndexPattern; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.lang.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.lang.md new file mode 100644 index 00000000000000..d51857090356fe --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.lang.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [lang](./kibana-plugin-plugins-data-public.field.lang.md) + +## Field.lang property + +Signature: + +```typescript +lang?: string; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.md new file mode 100644 index 00000000000000..84c22c47a5e2fc --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.md @@ -0,0 +1,40 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) + +## Field class + +Signature: + +```typescript +export declare class Field implements IFieldType +``` + +## Constructors + +| Constructor | Modifiers | Description | +| --- | --- | --- | +| [(constructor)(indexPattern, spec, shortDotsEnable)](./kibana-plugin-plugins-data-public.field._constructor_.md) | | Constructs a new instance of the Field class | + +## Properties + +| Property | Modifiers | Type | Description | +| --- | --- | --- | --- | +| [$$spec](./kibana-plugin-plugins-data-public.field.__spec.md) | | FieldSpec | | +| [aggregatable](./kibana-plugin-plugins-data-public.field.aggregatable.md) | | boolean | | +| [count](./kibana-plugin-plugins-data-public.field.count.md) | | number | | +| [displayName](./kibana-plugin-plugins-data-public.field.displayname.md) | | string | | +| [esTypes](./kibana-plugin-plugins-data-public.field.estypes.md) | | string[] | | +| [filterable](./kibana-plugin-plugins-data-public.field.filterable.md) | | boolean | | +| [format](./kibana-plugin-plugins-data-public.field.format.md) | | any | | +| [indexPattern](./kibana-plugin-plugins-data-public.field.indexpattern.md) | | IndexPattern | | +| [lang](./kibana-plugin-plugins-data-public.field.lang.md) | | string | | +| [name](./kibana-plugin-plugins-data-public.field.name.md) | | string | | +| [script](./kibana-plugin-plugins-data-public.field.script.md) | | string | | +| [scripted](./kibana-plugin-plugins-data-public.field.scripted.md) | | boolean | | +| [searchable](./kibana-plugin-plugins-data-public.field.searchable.md) | | boolean | | +| [sortable](./kibana-plugin-plugins-data-public.field.sortable.md) | | boolean | | +| [subType](./kibana-plugin-plugins-data-public.field.subtype.md) | | IFieldSubType | | +| [type](./kibana-plugin-plugins-data-public.field.type.md) | | string | | +| [visualizable](./kibana-plugin-plugins-data-public.field.visualizable.md) | | boolean | | + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.name.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.name.md new file mode 100644 index 00000000000000..d2a9b9b86aefc9 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.name.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [name](./kibana-plugin-plugins-data-public.field.name.md) + +## Field.name property + +Signature: + +```typescript +name: string; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.script.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.script.md new file mode 100644 index 00000000000000..676ff9bdfc35a7 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.script.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [script](./kibana-plugin-plugins-data-public.field.script.md) + +## Field.script property + +Signature: + +```typescript +script?: string; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.scripted.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.scripted.md new file mode 100644 index 00000000000000..1f6c8105e3f618 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.scripted.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [scripted](./kibana-plugin-plugins-data-public.field.scripted.md) + +## Field.scripted property + +Signature: + +```typescript +scripted?: boolean; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.searchable.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.searchable.md new file mode 100644 index 00000000000000..186d344f503788 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.searchable.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [searchable](./kibana-plugin-plugins-data-public.field.searchable.md) + +## Field.searchable property + +Signature: + +```typescript +searchable?: boolean; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.sortable.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.sortable.md new file mode 100644 index 00000000000000..0cd4b14d0e1e5c --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.sortable.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [sortable](./kibana-plugin-plugins-data-public.field.sortable.md) + +## Field.sortable property + +Signature: + +```typescript +sortable?: boolean; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.subtype.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.subtype.md new file mode 100644 index 00000000000000..bef3b2131fa475 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.subtype.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [subType](./kibana-plugin-plugins-data-public.field.subtype.md) + +## Field.subType property + +Signature: + +```typescript +subType?: IFieldSubType; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.type.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.type.md new file mode 100644 index 00000000000000..490615edcf097e --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.type.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [type](./kibana-plugin-plugins-data-public.field.type.md) + +## Field.type property + +Signature: + +```typescript +type: string; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.visualizable.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.visualizable.md new file mode 100644 index 00000000000000..f32a5c456dc5db --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.visualizable.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [Field](./kibana-plugin-plugins-data-public.field.md) > [visualizable](./kibana-plugin-plugins-data-public.field.visualizable.md) + +## Field.visualizable property + +Signature: + +```typescript +visualizable?: boolean; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.__spec.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.__spec.md deleted file mode 100644 index f52a3324af36f7..00000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.__spec.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [$$spec](./kibana-plugin-plugins-data-public.indexpatternfield.__spec.md) - -## IndexPatternField.$$spec property - -Signature: - -```typescript -$$spec: FieldSpec; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.aggregatable.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.aggregatable.md deleted file mode 100644 index 267c8f786b5dd2..00000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.aggregatable.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [aggregatable](./kibana-plugin-plugins-data-public.indexpatternfield.aggregatable.md) - -## IndexPatternField.aggregatable property - -Signature: - -```typescript -aggregatable?: boolean; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.count.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.count.md deleted file mode 100644 index 8e848276f21c4c..00000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.count.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [count](./kibana-plugin-plugins-data-public.indexpatternfield.count.md) - -## IndexPatternField.count property - -Signature: - -```typescript -count?: number; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.displayname.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.displayname.md deleted file mode 100644 index ed9630f92fc975..00000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.displayname.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [displayName](./kibana-plugin-plugins-data-public.indexpatternfield.displayname.md) - -## IndexPatternField.displayName property - -Signature: - -```typescript -displayName?: string; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.estypes.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.estypes.md deleted file mode 100644 index dec74df099d43a..00000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.estypes.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [esTypes](./kibana-plugin-plugins-data-public.indexpatternfield.estypes.md) - -## IndexPatternField.esTypes property - -Signature: - -```typescript -esTypes?: string[]; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.filterable.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.filterable.md deleted file mode 100644 index 4290c4a2f86b3b..00000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.filterable.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [filterable](./kibana-plugin-plugins-data-public.indexpatternfield.filterable.md) - -## IndexPatternField.filterable property - -Signature: - -```typescript -filterable?: boolean; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.format.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.format.md deleted file mode 100644 index d5df8ed628cb08..00000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.format.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [format](./kibana-plugin-plugins-data-public.indexpatternfield.format.md) - -## IndexPatternField.format property - -Signature: - -```typescript -format: any; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.indexpattern.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.indexpattern.md deleted file mode 100644 index d1a1ee0905c6e3..00000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.indexpattern.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [indexPattern](./kibana-plugin-plugins-data-public.indexpatternfield.indexpattern.md) - -## IndexPatternField.indexPattern property - -Signature: - -```typescript -indexPattern?: IndexPattern; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.lang.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.lang.md deleted file mode 100644 index f731be8f613cfa..00000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.lang.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [lang](./kibana-plugin-plugins-data-public.indexpatternfield.lang.md) - -## IndexPatternField.lang property - -Signature: - -```typescript -lang?: string; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.md deleted file mode 100644 index ae458c553421a9..00000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.md +++ /dev/null @@ -1,41 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) - -## IndexPatternField class - -Signature: - -```typescript -export declare class Field implements IFieldType -``` - -## Constructors - -| Constructor | Modifiers | Description | -| --- | --- | --- | -| [(constructor)(indexPattern, spec, shortDotsEnable)](./kibana-plugin-plugins-data-public.indexpatternfield._constructor_.md) | | Constructs a new instance of the Field class | - -## Properties - -| Property | Modifiers | Type | Description | -| --- | --- | --- | --- | -| [$$spec](./kibana-plugin-plugins-data-public.indexpatternfield.__spec.md) | | FieldSpec | | -| [aggregatable](./kibana-plugin-plugins-data-public.indexpatternfield.aggregatable.md) | | boolean | | -| [count](./kibana-plugin-plugins-data-public.indexpatternfield.count.md) | | number | | -| [displayName](./kibana-plugin-plugins-data-public.indexpatternfield.displayname.md) | | string | | -| [esTypes](./kibana-plugin-plugins-data-public.indexpatternfield.estypes.md) | | string[] | | -| [filterable](./kibana-plugin-plugins-data-public.indexpatternfield.filterable.md) | | boolean | | -| [format](./kibana-plugin-plugins-data-public.indexpatternfield.format.md) | | any | | -| [indexPattern](./kibana-plugin-plugins-data-public.indexpatternfield.indexpattern.md) | | IndexPattern | | -| [lang](./kibana-plugin-plugins-data-public.indexpatternfield.lang.md) | | string | | -| [name](./kibana-plugin-plugins-data-public.indexpatternfield.name.md) | | string | | -| [routes](./kibana-plugin-plugins-data-public.indexpatternfield.routes.md) | | Record<string, string> | | -| [script](./kibana-plugin-plugins-data-public.indexpatternfield.script.md) | | string | | -| [scripted](./kibana-plugin-plugins-data-public.indexpatternfield.scripted.md) | | boolean | | -| [searchable](./kibana-plugin-plugins-data-public.indexpatternfield.searchable.md) | | boolean | | -| [sortable](./kibana-plugin-plugins-data-public.indexpatternfield.sortable.md) | | boolean | | -| [subType](./kibana-plugin-plugins-data-public.indexpatternfield.subtype.md) | | IFieldSubType | | -| [type](./kibana-plugin-plugins-data-public.indexpatternfield.type.md) | | string | | -| [visualizable](./kibana-plugin-plugins-data-public.indexpatternfield.visualizable.md) | | boolean | | - diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.name.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.name.md deleted file mode 100644 index cb24621e732093..00000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.name.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [name](./kibana-plugin-plugins-data-public.indexpatternfield.name.md) - -## IndexPatternField.name property - -Signature: - -```typescript -name: string; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.routes.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.routes.md deleted file mode 100644 index 664a7b7b7ca0e5..00000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.routes.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [routes](./kibana-plugin-plugins-data-public.indexpatternfield.routes.md) - -## IndexPatternField.routes property - -Signature: - -```typescript -routes: Record; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.script.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.script.md deleted file mode 100644 index 132ba25a476374..00000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.script.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [script](./kibana-plugin-plugins-data-public.indexpatternfield.script.md) - -## IndexPatternField.script property - -Signature: - -```typescript -script?: string; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.scripted.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.scripted.md deleted file mode 100644 index 1dd6bc865a75d9..00000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.scripted.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [scripted](./kibana-plugin-plugins-data-public.indexpatternfield.scripted.md) - -## IndexPatternField.scripted property - -Signature: - -```typescript -scripted?: boolean; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.searchable.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.searchable.md deleted file mode 100644 index 42f984d851435b..00000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.searchable.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [searchable](./kibana-plugin-plugins-data-public.indexpatternfield.searchable.md) - -## IndexPatternField.searchable property - -Signature: - -```typescript -searchable?: boolean; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.sortable.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.sortable.md deleted file mode 100644 index 72d225185140be..00000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.sortable.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [sortable](./kibana-plugin-plugins-data-public.indexpatternfield.sortable.md) - -## IndexPatternField.sortable property - -Signature: - -```typescript -sortable?: boolean; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.subtype.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.subtype.md deleted file mode 100644 index 2d807f8a5739ce..00000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.subtype.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [subType](./kibana-plugin-plugins-data-public.indexpatternfield.subtype.md) - -## IndexPatternField.subType property - -Signature: - -```typescript -subType?: IFieldSubType; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.type.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.type.md deleted file mode 100644 index c8483c9b83c9a1..00000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.type.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [type](./kibana-plugin-plugins-data-public.indexpatternfield.type.md) - -## IndexPatternField.type property - -Signature: - -```typescript -type: string; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.visualizable.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.visualizable.md deleted file mode 100644 index dd661ae779c117..00000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.visualizable.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [visualizable](./kibana-plugin-plugins-data-public.indexpatternfield.visualizable.md) - -## IndexPatternField.visualizable property - -Signature: - -```typescript -visualizable?: boolean; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.md index 4b7184b7dc151e..478b73f5f85813 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.md @@ -24,5 +24,5 @@ export declare class FieldList extends Array implements IFieldList | [getByName](./kibana-plugin-plugins-data-public.indexpatternfieldlist.getbyname.md) | | (name: string) => Field | undefined | | | [getByType](./kibana-plugin-plugins-data-public.indexpatternfieldlist.getbytype.md) | | (type: string) => any[] | | | [remove](./kibana-plugin-plugins-data-public.indexpatternfieldlist.remove.md) | | (field: IFieldType) => void | | -| [update](./kibana-plugin-plugins-data-public.indexpatternfieldlist.update.md) | | (field: Field) => void | | +| [update](./kibana-plugin-plugins-data-public.indexpatternfieldlist.update.md) | | (field: Record<string, any>) => void | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.update.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.update.md index ca03ec4b728932..d5156ed41e493e 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.update.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.update.md @@ -7,5 +7,5 @@ Signature: ```typescript -update: (field: Field) => void; +update: (field: Record) => void; ``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md index fc0dab94a0f656..3713827f75386d 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md @@ -11,9 +11,9 @@ | [AggParamType](./kibana-plugin-plugins-data-public.aggparamtype.md) | | | [AggTypeFieldFilters](./kibana-plugin-plugins-data-public.aggtypefieldfilters.md) | A registry to store which are used to filter down available fields for a specific visualization and . | | [AggTypeFilters](./kibana-plugin-plugins-data-public.aggtypefilters.md) | A registry to store which are used to filter down available aggregations for a specific visualization and . | +| [Field](./kibana-plugin-plugins-data-public.field.md) | | | [FilterManager](./kibana-plugin-plugins-data-public.filtermanager.md) | | | [IndexPattern](./kibana-plugin-plugins-data-public.indexpattern.md) | | -| [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) | | | [IndexPatternFieldList](./kibana-plugin-plugins-data-public.indexpatternfieldlist.md) | | | [IndexPatternSelect](./kibana-plugin-plugins-data-public.indexpatternselect.md) | | | [OptionedParamType](./kibana-plugin-plugins-data-public.optionedparamtype.md) | | @@ -88,7 +88,6 @@ | [SavedQuery](./kibana-plugin-plugins-data-public.savedquery.md) | | | [SavedQueryService](./kibana-plugin-plugins-data-public.savedqueryservice.md) | | | [SearchSourceFields](./kibana-plugin-plugins-data-public.searchsourcefields.md) | | -| [SearchStrategyProvider](./kibana-plugin-plugins-data-public.searchstrategyprovider.md) | | | [TabbedAggColumn](./kibana-plugin-plugins-data-public.tabbedaggcolumn.md) | \* | | [TabbedTable](./kibana-plugin-plugins-data-public.tabbedtable.md) | \* | | [TimeRange](./kibana-plugin-plugins-data-public.timerange.md) | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.search.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.search.md index 78ac05b9fd3861..9a22339fd05307 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.search.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.search.md @@ -27,8 +27,9 @@ search: { InvalidEsCalendarIntervalError: typeof InvalidEsCalendarIntervalError; InvalidEsIntervalFormatError: typeof InvalidEsIntervalFormatError; isDateHistogramBucketAggConfig: typeof isDateHistogramBucketAggConfig; + isNumberType: (agg: import("./search").AggConfig) => boolean; isStringType: (agg: import("./search").AggConfig) => boolean; - isType: (type: string) => (agg: import("./search").AggConfig) => boolean; + isType: (...types: string[]) => (agg: import("./search").AggConfig) => boolean; isValidEsInterval: typeof isValidEsInterval; isValidInterval: typeof isValidInterval; parentPipelineType: string; diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchstrategyprovider.id.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchstrategyprovider.id.md deleted file mode 100644 index d60ffba6a05ca8..00000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchstrategyprovider.id.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [SearchStrategyProvider](./kibana-plugin-plugins-data-public.searchstrategyprovider.md) > [id](./kibana-plugin-plugins-data-public.searchstrategyprovider.id.md) - -## SearchStrategyProvider.id property - -Signature: - -```typescript -id: string; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchstrategyprovider.isviable.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchstrategyprovider.isviable.md deleted file mode 100644 index aa8ed49051ee9a..00000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchstrategyprovider.isviable.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [SearchStrategyProvider](./kibana-plugin-plugins-data-public.searchstrategyprovider.md) > [isViable](./kibana-plugin-plugins-data-public.searchstrategyprovider.isviable.md) - -## SearchStrategyProvider.isViable property - -Signature: - -```typescript -isViable: (indexPattern: IndexPattern) => boolean; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchstrategyprovider.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchstrategyprovider.md deleted file mode 100644 index b271a921906a71..00000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchstrategyprovider.md +++ /dev/null @@ -1,20 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [SearchStrategyProvider](./kibana-plugin-plugins-data-public.searchstrategyprovider.md) - -## SearchStrategyProvider interface - -Signature: - -```typescript -export interface SearchStrategyProvider -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [id](./kibana-plugin-plugins-data-public.searchstrategyprovider.id.md) | string | | -| [isViable](./kibana-plugin-plugins-data-public.searchstrategyprovider.isviable.md) | (indexPattern: IndexPattern) => boolean | | -| [search](./kibana-plugin-plugins-data-public.searchstrategyprovider.search.md) | (params: SearchStrategySearchParams) => SearchStrategyResponse | | - diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchstrategyprovider.search.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchstrategyprovider.search.md deleted file mode 100644 index 6e2561c3b0ad00..00000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchstrategyprovider.search.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [SearchStrategyProvider](./kibana-plugin-plugins-data-public.searchstrategyprovider.md) > [search](./kibana-plugin-plugins-data-public.searchstrategyprovider.search.md) - -## SearchStrategyProvider.search property - -Signature: - -```typescript -search: (params: SearchStrategySearchParams) => SearchStrategyResponse; -``` diff --git a/docs/images/clone_panel.gif b/docs/images/clone_panel.gif new file mode 100644 index 00000000000000..e521e438d051a9 Binary files /dev/null and b/docs/images/clone_panel.gif differ diff --git a/docs/images/vega_lite_default.png b/docs/images/vega_lite_default.png new file mode 100644 index 00000000000000..1ce1592d0738c6 Binary files /dev/null and b/docs/images/vega_lite_default.png differ diff --git a/docs/management/advanced-options.asciidoc b/docs/management/advanced-options.asciidoc index 20f22ad969687f..1895046e885b56 100644 --- a/docs/management/advanced-options.asciidoc +++ b/docs/management/advanced-options.asciidoc @@ -218,6 +218,8 @@ might increase the search time. This setting is off by default. Users must opt-i [horizontal] `siem:defaultAnomalyScore`:: The threshold above which Machine Learning job anomalies are displayed in the SIEM app. `siem:defaultIndex`:: A comma-delimited list of Elasticsearch indices from which the SIEM app collects events. +`siem:ipReputationLinks`:: A JSON array containing links for verifying the reputation of an IP address. The links are displayed on +{siem-guide}/siem-ui-overview.html#network-ui[IP detail] pages. `siem:enableNewsFeed`:: Enables the security news feed on the SIEM *Overview* page. `siem:newsFeedUrl`:: The URL from which the security news feed content is diff --git a/docs/redirects.asciidoc b/docs/redirects.asciidoc index 69a909419be19a..1bdba6f1ae0583 100644 --- a/docs/redirects.asciidoc +++ b/docs/redirects.asciidoc @@ -23,7 +23,7 @@ For more {kib} configuration settings, see <>. [role="exclude",id="uptime-security"] == Uptime security -This page has moved. Please see the new section in the {uptime-guide}/uptime-security.html[Uptime Monitoring Guide]. +This page has moved. Please see the new section in the {heartbeat-ref}/securing-heartbeat.html[Uptime Monitoring Guide]. [role="exclude",id="infra-read-only-access"] == Configure source read-only access diff --git a/docs/settings/ml-settings.asciidoc b/docs/settings/ml-settings.asciidoc index 6528568e868900..b71e1c672756ac 100644 --- a/docs/settings/ml-settings.asciidoc +++ b/docs/settings/ml-settings.asciidoc @@ -8,7 +8,6 @@ You do not need to configure any settings to use {kib} {ml-features}. They are enabled by default. -[float] [[general-ml-settings-kb]] ==== General {ml} settings @@ -19,3 +18,11 @@ If set to `false` in `kibana.yml`, the {ml} icon is hidden in this {kib} instance. If `xpack.ml.enabled` is set to `true` in `elasticsearch.yml`, however, you can still use the {ml} APIs. To disable {ml} entirely, see the {ref}/ml-settings.html[{es} {ml} settings]. + +[[data-visualizer-settings]] +==== {data-viz} settings + +`xpack.ml.file_data_visualizer.max_file_size`:: +Sets the file size limit when importing data in the {data-viz}. The default +value is `100MB`. The highest supported value for this setting is `1GB`. + diff --git a/docs/setup/production.asciidoc b/docs/setup/production.asciidoc index eef2b11e53d85f..19f9d64d13623d 100644 --- a/docs/setup/production.asciidoc +++ b/docs/setup/production.asciidoc @@ -133,7 +133,8 @@ server.port Settings that must be the same: -------- xpack.security.encryptionKey //decrypting session cookies -xpack.reporting.encryptionKey //decrypting reports stored in Elasticsearch +xpack.reporting.encryptionKey //decrypting reports +xpack.encryptedSavedObjects.encryptionKey // decrypting saved objects -------- Separate configuration files can be used from the command line by using the `-c` flag: diff --git a/docs/siem/images/cases-ui.png b/docs/siem/images/cases-ui.png new file mode 100644 index 00000000000000..b513efb6647407 Binary files /dev/null and b/docs/siem/images/cases-ui.png differ diff --git a/docs/siem/siem-ui.asciidoc b/docs/siem/siem-ui.asciidoc index 85253daaf29330..985138756622d2 100644 --- a/docs/siem/siem-ui.asciidoc +++ b/docs/siem/siem-ui.asciidoc @@ -35,7 +35,7 @@ image::siem/images/network-ui.png[] [float] [[detections-ui]] -=== Detections (Beta) +=== Detections (beta) The Detections feature automatically searches for threats and creates signals when they are detected. Signal detection rules define the conditions @@ -50,6 +50,22 @@ or the Detections API. [role="screenshot"] image::siem/images/detections-ui.png[] +[float] +[[cases-ui]] +=== Cases (beta) + +Cases are used to open and track security issues directly in SIEM. +Cases list the original reporter and all users who contribute to a case +(`participants`). Case comments support Markdown syntax, and allow linking to +saved Timelines. Additionally, you can send cases to external systems from +within SIEM (currently ServiceNow). + +For information about opening, updating, and closing cases, see +{siem-guide}/cases-overview.html[Cases] in the SIEM Guide. + +[role="screenshot"] +image::siem/images/cases-ui.png[] + [float] [[timelines-ui]] === Timeline diff --git a/docs/uptime-guide/index.asciidoc b/docs/uptime-guide/index.asciidoc index 7bbc01bb303f1f..09763182fa88fc 100644 --- a/docs/uptime-guide/index.asciidoc +++ b/docs/uptime-guide/index.asciidoc @@ -12,4 +12,3 @@ include::install.asciidoc[] include::deployment-arch.asciidoc[] -include::security.asciidoc[] diff --git a/docs/uptime-guide/install.asciidoc b/docs/uptime-guide/install.asciidoc index e7c50bb7604ce9..0ed1270ca92cea 100644 --- a/docs/uptime-guide/install.asciidoc +++ b/docs/uptime-guide/install.asciidoc @@ -56,6 +56,11 @@ Additional information is available in {heartbeat-ref}/heartbeat-configuration.h [role="screenshot"] image::images/uptime-setup.png[Installation instructions on the Uptime page in Kibana] +[[setup-security]] +=== Step 4: Setup Security + +Secure your installation by following the {heartbeat-ref}/securing-heartbeat.html[Secure Heartbeat] documentation. + [float] ==== Important considerations diff --git a/docs/uptime-guide/security.asciidoc b/docs/uptime-guide/security.asciidoc deleted file mode 100644 index 0c6fa4c6c4f56f..00000000000000 --- a/docs/uptime-guide/security.asciidoc +++ /dev/null @@ -1,60 +0,0 @@ -[[uptime-security]] -== Elasticsearch Security - -If you use Elasticsearch security, you'll need to enable certain privileges for users -that would like to access the Uptime app. For example, create user and support roles to implement the privileges: - -[float] -=== Create a role - -You'll need a role that lets you access the Heartbeat indices, which by default are `heartbeat-*`. -You can create this with the following request: - -["source","sh",subs="attributes,callouts"] ---------------------------------------------------------------- -PUT /_security/role/uptime -{ "indices" : [ - { - "names" : [ - "heartbeat-*" - ], - "privileges" : [ - "read", - "view_index_metadata" - ], - "field_security" : { - "grant" : [ - "*" - ] - }, - "allow_restricted_indices" : false - } - ], - "transient_metadata" : { - "enabled" : true - } -} ---------------------------------------------------------------- -// CONSOLE - -[float] -=== Assign the role to a user - -Next, you'll need to create a user with both the `uptime` role, and another role with sufficient {kibana-ref}/kibana-privileges.html[Kibana privileges], -such as the `kibana_admin` role. -You can do this with the following request: - -["source","sh",subs="attributes,callouts"] ---------------------------------------------------------------- -PUT /_security/user/jacknich -{ - "password" : "j@rV1s", - "roles" : [ "uptime", "kibana_admin" ], - "full_name" : "Jack Nicholson", - "email" : "jacknich@example.com", - "metadata" : { - "intelligence" : 7 - } -} ---------------------------------------------------------------- -// CONSOLE diff --git a/docs/uptime/images/alert-flyout.png b/docs/uptime/images/alert-flyout.png new file mode 100644 index 00000000000000..7fc1e3d9aefe27 Binary files /dev/null and b/docs/uptime/images/alert-flyout.png differ diff --git a/docs/uptime/images/check-history.png b/docs/uptime/images/check-history.png index 6418495eee9edd..91565bf59aa7f2 100644 Binary files a/docs/uptime/images/check-history.png and b/docs/uptime/images/check-history.png differ diff --git a/docs/uptime/images/error-list.png b/docs/uptime/images/error-list.png deleted file mode 100644 index 99f017f2945a5b..00000000000000 Binary files a/docs/uptime/images/error-list.png and /dev/null differ diff --git a/docs/uptime/images/monitor-charts.png b/docs/uptime/images/monitor-charts.png index dbfa43f47656e0..522f34662657ee 100644 Binary files a/docs/uptime/images/monitor-charts.png and b/docs/uptime/images/monitor-charts.png differ diff --git a/docs/uptime/images/observability_integrations.png b/docs/uptime/images/observability_integrations.png index d5c612c7589ca3..6589c0c5565dd6 100644 Binary files a/docs/uptime/images/observability_integrations.png and b/docs/uptime/images/observability_integrations.png differ diff --git a/docs/uptime/images/settings.png b/docs/uptime/images/settings.png new file mode 100644 index 00000000000000..dd36f0a6d702b3 Binary files /dev/null and b/docs/uptime/images/settings.png differ diff --git a/docs/uptime/images/snapshot-view.png b/docs/uptime/images/snapshot-view.png index 020396d0f3e4cf..1fce2e9592c14c 100644 Binary files a/docs/uptime/images/snapshot-view.png and b/docs/uptime/images/snapshot-view.png differ diff --git a/docs/uptime/images/status-bar.png b/docs/uptime/images/status-bar.png index e0e9b27555900a..8d242789cdccd7 100644 Binary files a/docs/uptime/images/status-bar.png and b/docs/uptime/images/status-bar.png differ diff --git a/docs/uptime/index.asciidoc b/docs/uptime/index.asciidoc index 785b9f818f5bfc..a355f8ecf48436 100644 --- a/docs/uptime/index.asciidoc +++ b/docs/uptime/index.asciidoc @@ -12,8 +12,10 @@ To get started with Elastic Uptime, refer to {uptime-guide}/install-uptime.html[ * <> * <> +* <> -- include::overview.asciidoc[] include::monitor.asciidoc[] +include::settings.asciidoc[] diff --git a/docs/uptime/monitor.asciidoc b/docs/uptime/monitor.asciidoc index d54fd02c7c0691..8a4be1f11a7219 100644 --- a/docs/uptime/monitor.asciidoc +++ b/docs/uptime/monitor.asciidoc @@ -5,21 +5,24 @@ The Monitor page will help you get further insight into the performance of a specific network endpoint. You'll see a detailed visualization of the monitor's request duration over time, as well as the `up`/`down` -status over time. +status over time. You can also also detect anomalies in response time data +by configuring Machine Learning jobs on this page. [float] -=== Status bar +=== Status panel [role="screenshot"] image::uptime/images/status-bar.png[Status bar] -The Status bar displays a quick summary of the latest information +The Status panel displays a quick summary of the latest information regarding your monitor. You can view its latest status, click a link to visit the targeted URL, see its most recent request duration, and determine the amount of time that has elapsed since the last check. -You can use the Status bar to get a quick summary of current performance, -beyond simply knowing if the monitor is `up` or `down`. +When two Heartbeat instances are configured in different geographic locations +the map will show each location as a pinpoint on the map, along with the +amount of time elapsed since data was last received from that location. + [float] === Monitor charts @@ -32,12 +35,14 @@ date range. These charts can help you gain insight into how quickly requests are by the targeted endpoint, and give you a sense of how frequently a host or endpoint was down in your selected timespan. -The first chart displays request duration information for your monitor. +The Monitor duration chart displays request duration information for your monitor. The area surrounding the line is the range of request time for the corresponding -bucket. The line is the average time. +bucket. The line is the average time. Anomaly detection using Machine Learning +can be configured in the upper right hand of this panel. When response times change +in an unexpected way the time range in which they occurred will be given filled with a color. -Next, is a graphical representation of the check statuses over time. Hover over -the charts to display crosshairs with more specific numeric data. +The pings over time chart is a graphical representation of the check statuses over time. +Hover over the charts to display crosshairs with more specific numeric data. [role="screenshot"] image::uptime/images/crosshair-example.png[Chart crosshair] @@ -49,6 +54,6 @@ image::uptime/images/crosshair-example.png[Chart crosshair] image::uptime/images/check-history.png[Check history view] The Check history displays the total count of this monitor's checks for the selected -date range. You can additionally filter the checks by `status` to help find recent problems +date range. You can additionally filter the checks by status and location to help find recent problems on a per-check basis. This table can help you gain some insight into more granular details about recent individual data points Heartbeat is logging about your host or endpoint. diff --git a/docs/uptime/overview.asciidoc b/docs/uptime/overview.asciidoc index 098ce12a569911..71c09c968e5124 100644 --- a/docs/uptime/overview.asciidoc +++ b/docs/uptime/overview.asciidoc @@ -21,12 +21,12 @@ This control allows you to use automated filter options, as well as input custom text to select specific monitors by field, URL, ID, and other attributes. [float] -=== Snapshot view +=== Snapshot panel [role="screenshot"] image::uptime/images/snapshot-view.png[Snapshot view] -This view is intended to quickly give you a sense of the overall +This panel is intended to quickly give you a sense of the overall status of the environment you're monitoring, or a subset of those monitors. Here, you can see the total number of detected monitors within the selected Uptime date range. In addition to the total, the counts for the number of monitors @@ -49,6 +49,17 @@ way to navigate to a more in-depth visualization for interesting hosts or endpoi This table includes information like the most recent status, when the monitor was last checked, its ID and URL, its IP address, and a dedicated sparkline showing its check status over time. +[float] +=== Creating and managing alerts + +[role="screenshot"] +image::uptime/images/alert-flyout.png[Create alert flyout] + +To receive alerts when a monitor goes down, use the alerting menu at the top of the +overview page. Use a query in the alert flyout to determine which monitors to check +with your alert. If you already have a query in the overview page search bar it will +be carried over into this box. + [float] === Observability integrations @@ -60,14 +71,3 @@ Docker related host information, it will provide links to open the Metrics app o for this host. Additionally, this feature supplies links to simply filter the other views on the host's IP address, to help you quickly determine if these other solutions contain data relevant to your current interest. - -[float] -=== Error list - -[role="screenshot"] -image::uptime/images/error-list.png[Error list] - -The Error list displays aggregations of errors that Heartbeat has logged. Errors are -displayed by Error type, monitor ID, and message. Clicking a monitor's ID will take you -to the corresponding Monitor view, which can provide you richer information about the individual -data points that are resulting in the displayed errors. diff --git a/docs/uptime/settings.asciidoc b/docs/uptime/settings.asciidoc new file mode 100644 index 00000000000000..55da6e802bec60 --- /dev/null +++ b/docs/uptime/settings.asciidoc @@ -0,0 +1,27 @@ +[role="xpack"] +[[uptime-settings]] + +== Settings + +[role="screenshot"] +image::uptime/images/settings.png[Filter bar] + +The Uptime settings page lets you change which Heartbeat indices are displayed +by the uptime app. Users must have the 'all' permission to modify items on this page. +Uptime settings apply to the current space only. Use different settings in different +spaces to segment different uptime use cases and domains. + +As an example, imagine your organization has one team for internal IT services, and another +for public services. Each team operates independently and is only responsible for its +own services. In this scenario, you might set up separate Heartbeat instances for each team, +writing out to index patterns named `it-heartbeat-\*`, and `external-heartbeat-\*`. You would +create separate roles and users for each in Elasticsearch, each with access to their own spaces, +named `it` and `external` respectively. Within each space you would navigate to the settings page +and set the correct index pattern to match only the indices that space is allowed to access. + +Note that the pattern set here only restricts what the Uptime app shows. Users may still be able +to manually query Elasticsearch for data outside this pattern! + +See the <> +and {heartbeat-ref}/securing-heartbeat.html[Heartbeat security] +docs for more information. diff --git a/docs/user/alerting/action-types/pagerduty.asciidoc b/docs/user/alerting/action-types/pagerduty.asciidoc index 50a1f31e4a9ae1..da34c6e0855d76 100644 --- a/docs/user/alerting/action-types/pagerduty.asciidoc +++ b/docs/user/alerting/action-types/pagerduty.asciidoc @@ -4,19 +4,142 @@ The PagerDuty action type uses the https://v2.developer.pagerduty.com/docs/events-api-v2[v2 Events API] to trigger, acknowledge, and resolve PagerDuty alerts. +* <> +* <> +* <> + +[float] +[[pagerduty-benefits]] +=== PagerDuty + Elastic integration benefits + +By integrating PagerDuty with alerts, you can: + +* Route your alerts to the right PagerDuty responder within your team, based on your structure, escalation policies, and workflows. +* Automatically generate incidents of different types and severity based on each alert’s context. +* Tailor the incident data to match your needs by easily passing the alerting context from Kibana to PagerDuty. + +[float] +[[pagerduty-how-it-works]] +==== How it works + +{kib} allows you to create alerts to notify you of a significant move +in your dataset. +You can create alerts for all your Observability, Security, and Elastic Stack use cases. +Alerts will trigger a new incident on the corresponding PagerDuty service. + +[float] +==== Requirements + +In the `kibana.yml` configuration file, you must add the <>. +This is required to encrypt parameters that must be secured, for example PagerDuty’s integration key. + +If you have security enabled: + +* You must have +application privileges to access Metrics, APM, Uptime, or SIEM. +* If you are using a self-managed deployment with security, you must have +Transport Security Layer (TLS) enabled for communication <>. +Alerts uses API keys to secure background alert checks and actions, +and API keys require {ref}/configuring-tls.html#tls-http[TLS on the HTTP interface]. + +Although not a requirement, to harden the integrations security you might want to +review the <> that are available to you. + +[float] +[[pagerduty-support]] +==== Support +If you need help with this integration, get in touch with the {kib} team by visiting +https://support.elastic.co[support.elastic.co] or by using the *Ask Elastic* option in the {kib} Help menu. +You can also select the {kib} category at https://discuss.elastic.co/[discuss.elastic.co]. + +[float] +[[pagerduty-integration-walkthrough]] +==== Integration with PagerDuty walkthrough + +[float] +[[pagerduty-in-pagerduty]] +===== In PagerDuty + +. From the *Configuration* menu, select *Services*. +. Add an integration to a service: ++ +* If you are adding your integration to an existing service, +click the name of the service you want to add the integration to. +Then, select the *Integrations* tab and click the *New Integration* button. +* If you are creating a new service for your integration, +go to +https://support.pagerduty.com/docs/services-and-integrations#section-configuring-services-and-integrations[Configuring Services and Integrations] +and follow the steps outlined in the *Create a New Service* section, selecting *Elastic* as the *Integration Type* in step 4. +Continue with the <> section once you have finished these steps. + +. Enter an *Integration Name* in the format Elastic-service-name (for example, Elastic-Alerting or Kibana-APM-Alerting) +and select Elastic from the *Integration Type* menu. +. Click *Add Integration* to save your new integration. ++ +You will be redirected to the *Integrations* tab for your service. An Integration Key is generated on this screen. ++ +[role="screenshot"] +image::user/alerting/images/pagerduty-integration.png[PagerDuty Integrations tab] + +. Save this key, as you will use it when you configure the integration with Elastic in the next section. + +[float] +[[pagerduty-in-elastic]] +===== In Elastic + +. Create a PagerDuty Connector in Kibana. You can: ++ +* Create a connector as part of creating an alert by selecting PagerDuty in the *Actions* +section of the alert configuration and selecting *Add new*. +* Alternatively, create a connector by navigating to *Management* from the {kib} navbar and selecting +*Alerts and Actions*. Then, select the *Connectors* tab, click the *Create connector* button, and select the PagerDuty option. + +. Configure the connector by giving it a name and optionally entering the API URL and Routing Key, or using the defaults. ++ +See <> for how to obtain the endpoint and key information from PagerDuty and +<> for more details. + +. Save the Connector. + +. Create an alert using *Management > Alerts and Actions* or the application of your choice. + +. Set up an action using your PagerDuty connector, by determining: ++ +* The action’s type: Trigger, Resolve, or Acknowledge. +* The event’s severity: Info, warning, error, or critical. +* An array of different fields, including the timestamp, group, class, component, and your dedup key. +Depending on your custom needs, assign them variables from the alerting context. +To see the available context variables, click on the *Add alert variable* icon next +to each corresponding field. For more details on these parameters, see the +<> and the PagerDuty +https://v2.developer.pagerduty.com/v2/docs/send-an-event-events-api-v2[API v2 documentation]. + + +[float] +[[pagerduty-uninstall]] +==== How to uninstall +To remove a PagerDuty connector from an alert, simply remove it +from the *Actions* section of that alert, using the remove (x) icon. +This will disable the integration for the particular alert. + +To delete the connector entirely, go to *Management > Alerts and Actions*. +Select the *Connectors* tab, and then click on the delete icon. +This is an irreversible action and impacts all alerts that use this connector. + + [float] [[pagerduty-connector-configuration]] -==== Connector configuration +=== Connector configuration PagerDuty connectors have the following configuration properties: Name:: The name of the connector. The name is used to identify a connector in the management UI connector listing, or in the connector list when configuring an action. -API URL:: An optional PagerDuty event URL. Defaults to `https://events.pagerduty.com/v2/enqueue`. If you are using the <> setting, make sure the hostname is whitelisted. +API URL:: An optional PagerDuty event URL. Defaults to `https://events.pagerduty.com/v2/enqueue`. If you are using the <> setting, make sure the hostname is whitelisted. Routing Key:: A 32 character PagerDuty Integration Key for an integration on a service or on a global ruleset. [float] [[pagerduty-action-configuration]] -==== Action configuration +=== Action configuration PagerDuty actions have the following properties: @@ -26,8 +149,8 @@ Dedup Key:: All actions sharing this key will be associated with the same Pa Timestamp:: An *optional* https://v2.developer.pagerduty.com/v2/docs/types#datetime[ISO-8601 format date-time], indicating the time the event was detected or generated. Component:: An *optional* value indicating the component of the source machine that is responsible for the event, for example `mysql` or `eth0`. Group:: An *optional* value indicating the logical grouping of components of a service, for example `app-stack`. -Source:: An *optional* value indicating the affected system, preferably a hostname or fully qualified domain name. Defaults to the {kib} saved object id of the action. +Source:: An *optional* value indicating the affected system, preferably a hostname or fully qualified domain name. Defaults to the {kib} saved object id of the action. Summary:: An *optional* text summary of the event, defaults to `No summary provided`. The maximum length is 1024 characters. Class:: An *optional* value indicating the class/type of the event, for example `ping failure` or `cpu load`. -For more details on these properties, see https://v2.developer.pagerduty.com/v2/docs/send-an-event-events-api-v2[PagerDuty v2 event parameters]. \ No newline at end of file +For more details on these properties, see https://v2.developer.pagerduty.com/v2/docs/send-an-event-events-api-v2[PagerDuty v2 event parameters]. diff --git a/docs/user/alerting/images/pagerduty-integration.png b/docs/user/alerting/images/pagerduty-integration.png new file mode 100755 index 00000000000000..0a270de866b36e Binary files /dev/null and b/docs/user/alerting/images/pagerduty-integration.png differ diff --git a/docs/user/dashboard.asciidoc b/docs/user/dashboard.asciidoc index ab529a533d5e37..de714ae40086be 100644 --- a/docs/user/dashboard.asciidoc +++ b/docs/user/dashboard.asciidoc @@ -98,6 +98,24 @@ to the new dimensions. * To delete a panel, open the panel menu and select *Delete from dashboard.* Deleting a panel from a dashboard does *not* delete the saved visualization or search. +[float] +[[cloning-a-panel]] +=== Clone dashboard elements + +In *Edit* mode, you can clone any panel on a dashboard. + +To clone an existing panel, open the panel menu of the element you wish to clone, then select *Clone panel*. + +* Cloned panels appear beside the original, and will move other panels down to make room if necessary. + +* Clones support all of the original panel's functionality, including renaming, editing, and cloning. + +* All cloned visualizations will appear in the visualization list. + +[role="screenshot"] +image:images/clone_panel.gif[clone panel] + + [float] [[viewing-detailed-information]] === Inspect and edit elements diff --git a/docs/user/ml/images/ml-data-visualizer-sample.jpg b/docs/user/ml/images/ml-data-visualizer-sample.jpg index 6c2e018932717f..ce2bb660d7da1a 100644 Binary files a/docs/user/ml/images/ml-data-visualizer-sample.jpg and b/docs/user/ml/images/ml-data-visualizer-sample.jpg differ diff --git a/docs/user/ml/index.asciidoc b/docs/user/ml/index.asciidoc index cca0dc5e4530fe..e9ef4a55b2b3ae 100644 --- a/docs/user/ml/index.asciidoc +++ b/docs/user/ml/index.asciidoc @@ -4,31 +4,31 @@ [partintro] -- -As datasets increase in size and complexity, the human effort required to +As data sets increase in size and complexity, the human effort required to inspect dashboards or maintain rules for spotting infrastructure problems, cyber attacks, or business issues becomes impractical. Elastic {ml-features} such as {anomaly-detect} and {oldetection} make it easier to notice suspicious activities with minimal human interference. -If you have a basic license, you can use the *Data Visualizer* to learn more -about your data. In particular, if your data is stored in {es} and contains a -time field, you can use the *Data Visualizer* to identify possible fields for -{anomaly-detect}: +{kib} includes a free *{data-viz}* to learn more about your data. In particular, +if your data is stored in {es} and contains a time field, you can use the +*{data-viz}* to identify possible fields for {anomaly-detect}: [role="screenshot"] -image::user/ml/images/ml-data-visualizer-sample.jpg[Data Visualizer for sample flight data] +image::user/ml/images/ml-data-visualizer-sample.jpg[{data-viz} for sample flight data] -experimental[] You can also upload a CSV, NDJSON, or log file (up to 100 MB in -size). The *Data Visualizer* identifies the file format and field mappings. You -can then optionally import that data into an {es} index. +experimental[] You can also upload a CSV, NDJSON, or log file. The *{data-viz}* +identifies the file format and field mappings. You can then optionally import +that data into an {es} index. To change the default file size limit, see +<>. -You need the following permissions to use the Data Visualizer with file upload: +You need the following permissions to use the {data-viz} with file upload: * cluster privileges: `monitor`, `manage_ingest_pipelines` * index privileges: `read`, `manage`, `index` For more information, see {ref}/security-privileges.html[Security privileges] -and {ref}/built-in-roles.html[Built-in roles]. +and {ml-docs}/setup.html[Set up {ml-features}]. -- diff --git a/docs/visualize/vega.asciidoc b/docs/visualize/vega.asciidoc index b8c0d1dbe3ddaf..e0d9955f0c3dbf 100644 --- a/docs/visualize/vega.asciidoc +++ b/docs/visualize/vega.asciidoc @@ -1,81 +1,80 @@ [[vega-graph]] -== Vega Graphs -experimental[] +== Vega -You can build https://vega.github.io/vega/examples/[Vega] and -https://vega.github.io/vega-lite/examples/[Vega-Lite] data visualizations -into Kibana, either standalone, or on top of a map. To see Vega in action, -watch this -https://www.youtube.com/watch?v=lQGCipY3th8[short introduction video]. +experimental[] -Currently Vega version 4.3 and Vega-Lite version 2.6 are supported. +Build custom visualizations from multiple data sources using Vega +and Vega-Lite. -NOTE: In Vega it is possible to load data dynamically, e.g. by setting signals as data urls. This is not supported in Kibana as all data is fetched at once prior to passing it to the Vega renderer. +* *Vega* — A declarative format to create visualizations using JSON. + Generate interactive displays using D3. +* *Vega-Lite* — An easier format to use than Vega that enables more rapid + data analysis. Compiles into Vega. -[[vega-quick-demo]] -=== Getting Started with Vega +For more information about Vega and Vega-Lite, refer to +<>. -* To experiment using sample data, first click the {kib} logo in the upper left hand corner -and then click the link next to *Sample Data*. -* Once you have data loaded, go to *Visualize*, click *+*, and select *Vega* to see an example graph. -*Note*: The default graph is written in Vega-Lite, but you can build visualizations -in either language. See <> for more information. -* Try changing `mark` from `line` to `point`, `area`, `bar`, `circle`, -or `square`. Check out the -https://vega.github.io/vega-lite/docs/mark.html#mark-def[Vega-Lite docs] for more information. -* Explore other available https://vega.github.io/vega/examples/[Vega] or -https://vega.github.io/vega-lite/examples/[Vega-Lite] visualizations. -*Note*: You might need to make URLs absolute, for example, replace -`"url": "data/world-110m.json"` with -`"url": "https://vega.github.io/editor/data/world-110m.json"`. -See <>. -* For more information on getting started, check out this https://www.elastic.co/blog/getting-started-with-vega-visualizations-in-kibana[blog post]. +[float] +[[create-vega-viz]] +=== Create Vega visualizations +You create Vega visualizations by using the text editor, which is +preconfigured with the options you need. -[[vega-vs-vegalite]] -=== Vega vs Vega-Lite +[role="screenshot"] +image::images/vega_lite_default.png[] -The Vega visualization in {kib} supports both Vega and Vega-Lite. You can use the -`schema` value to define which language you would like to use and its minimum -required version. +[float] +[[vega-schema]] +==== Change the Vega version -For example: +The default visualization uses Vega-Lite version 2. To use Vega version 4, edit +the `schema`. -* Vega-Lite v2: `$schema: https://vega.github.io/schema/vega-lite/v2.json` -* Vega v4: `$schema: https://vega.github.io/schema/vega/v4.json` +Go to `$schema`, enter `https://vega.github.io/schema/vega/v4.json`, then click +*Update*. -The `schema` URL is only used for identification, and does not need to be accessible by {kib}. +[float] +[[vega-type]] +==== Change the visualization type -Vega-Lite is a simplified version of Vega; it automates some constructions and has -much shorter specifications than Vega. Vega-Lite is automatically converted into -Vega before rendering, but it has some limitations, and there are some visualizations -that can be expressed in Vega that cannot be expressed in Vega-Lite. You can learn more -in the https://vega.github.io/vega-lite/[Vega-Lite documentation]. +The default visualization is a line chart. To change the visualization type, +change the `mark` value. The supported visualization types are listed in the +text editor. -You can use https://vega.github.io/editor/[this editor] to convert Vega-Lite into -Vega. +Go to `mark`, change the value to a different visualization type, then click +*Update*. -When you create a Vega visualization in {kib}, you can edit the `schema` -value in the dev tools to the left of the graph to define which of the two expression -languages you would like to use. +[float] +[[vega-sizing-and-positioning]] +==== Change the layout +By default, Vega visualizations use the `autosize = { type: 'fit', contains: 'padding' }` layout. +`fit` uses all available space, ignores `width` and `height` values, +and respects the padding values. To override this behavior, change the +`autosize` value. [[vega-querying-elasticsearch]] -=== Querying Elasticsearch +=== Query {es} -By default, Vega's https://vega.github.io/vega/docs/data/[data] element -can use embedded and external data with a `"url"` parameter. Kibana adds support for the direct Elasticsearch queries by overloading +experimental[] Vega https://vega.github.io/vega/docs/data/[data] elements +use embedded and external data with a `"url"` parameter. {kib} adds support for +direct {es} queries by overloading the `"url"` value. -Here is an example of an Elasticsearch query that counts the number of documents in all indexes. The query uses *@timestamp* field to filter the time range, and break it into histogram buckets. +NOTE: With Vega, you dynamically load your data by setting signals as data URLs. +Since {kib} is unable to support dynamically loaded data, all data is fetched +before it's passed to the Vega renderer. + +For example, count the number of documents in all indices: [source,yaml] ---- -// An object instead of a string for the url value +// An object instead of a string for the URL value // is treated as a context-aware Elasticsearch query. url: { - // Specify the time filter (upper right corner) with this field + // Specify the time filter. %timefield%: @timestamp // Apply dashboard context filters when set %context%: true @@ -88,8 +87,8 @@ url: { time_buckets: { date_histogram: { // Use date histogram aggregation on @timestamp field - field: @timestamp - // interval value will depend on the daterange picker + field: @timestamp <1> + // interval value will depend on the time filter // Use an integer to set approximate bucket count interval: { %autointerval%: true } // Make sure we get an entire range, even if it has no data @@ -109,7 +108,10 @@ url: { } ---- -The full result has this kind of structure: +<1> `@timestamp` — Filters the time range and breaks it into histogram +buckets. + +The full result includes the following structure: [source,yaml] ---- @@ -118,23 +120,24 @@ The full result has this kind of structure: "time_buckets": { "buckets": [{ "key_as_string": "2015-11-30T22:00:00.000Z", - "key": 1448920800000, + "key": 1448920800000,<1> "doc_count": 28 }, { "key_as_string": "2015-11-30T23:00:00.000Z", - "key": 1448924400000, + "key": 1448924400000, <1> "doc_count": 330 }, ... ---- -Note that `"key"` is a unix timestamp, and can be used without conversions by the +<1> `"key"` — The unix timestamp you can use without conversions by the Vega date expressions. -For most graphs we only need the list of the bucket values, so we use `format: {property: "aggregations.time_buckets.buckets"}` expression to focus on just the data we need. +For most visualizations, you only need the list of bucket values. To focus on +only the data you need, use `format: {property: "aggregations.time_buckets.buckets"}`. -Query may be specified with individual range and dashboard context as -well. This query is equivalent to `"%context%": true, "%timefield%": "@timestamp"`, -except that the timerange is shifted back by 10 minutes: +Specify a query with individual range and dashboard context. The query is +equivalent to `"%context%": true, "%timefield%": "@timestamp"`, +except that the time range is shifted back by 10 minutes: [source,yaml] ---- @@ -185,9 +188,9 @@ on the currently picked range: `"interval": {"%autointerval%": 10}` will try to get about 10-15 data points (buckets). [[vega-esmfiles]] -=== Elastic Map Files +=== Access Elastic Map Service files -It is possible to access Elastic Map Service's files via the same mechanism +experimental[] Access the Elastic Map Service files via the same mechanism: [source,yaml] ---- @@ -203,11 +206,8 @@ url: { format: {property: "features"} ---- -[[vega-with-a-map]] -=== Vega with a Map - -Kibana's default map can be used as a base of the Vega graph. To enable, -the graph must specify `type=map` in the host configuration: +To enable Elastic Maps, the graph must specify `type=map` in the host +configuration: [source,yaml] ---- @@ -247,42 +247,47 @@ the graph must specify `type=map` in the host configuration: } ---- -This visualization will automatically inject a projection called -`"projection"`. Use it to calculate positioning of all geo-aware marks. -Additionally, you may use `latitude`, `longitude`, and `zoom` signals. +The visualization automatically injects a `"projection"`, which you can use to +calculate the position of all geo-aware marks. +Additionally, you can use `latitude`, `longitude`, and `zoom` signals. These signals can be used in the graph, or can be updated to modify the -positioning of the map. +position of the map. + +Vega visualization ignore the `autosize`, `width`, `height`, and `padding` +values, using `fit` model with zero padding. [[vega-debugging]] -=== Debugging +=== Debugging Vega [[vega-browser-debugging-console]] -==== Browser Debugging console +==== Browser debugging console -Use browser debugging tools (e.g. F12 or Ctrl+Shift+J in Chrome) to +experimental[] Use browser debugging tools (for example, F12 or Ctrl+Shift+J in Chrome) to inspect the `VEGA_DEBUG` variable: -* `view` - access to the Vega View object. See https://vega.github.io/vega/docs/api/debugging/[Vega Debugging Guide] - on how to inspect data and signals at runtime. For Vega-Lite, `VEGA_DEBUG.view.data('source_0')` gets the main data set. - For Vega, it uses the data name as defined in your Vega spec. -* `vega_spec` - Vega JSON graph specification after some modifications by Kibana. In case ++ +* `view` — Access to the Vega View object. See https://vega.github.io/vega/docs/api/debugging/[Vega Debugging Guide] +on how to inspect data and signals at runtime. For Vega-Lite, `VEGA_DEBUG.view.data('source_0')` gets the main data set. +For Vega, it uses the data name as defined in your Vega spec. + +* `vega_spec` — Vega JSON graph specification after some modifications by {kib}. In case of Vega-Lite, this is the output of the Vega-Lite compiler. -* `vegalite_spec` - If this is a Vega-Lite graph, JSON specification of the graph before + +* `vegalite_spec` — If this is a Vega-Lite graph, JSON specification of the graph before Vega-Lite compilation. [[vega-data]] ==== Data -If you are using Elasticsearch query, make sure your resulting data is -what you expected. The easiest way to view it is by using "networking" -tab in the browser debugging tools (e.g. F12). Modify the graph slightly +experimental[] If you are using an {es} query, make sure your resulting data is +what you expected. The easiest way to view it is by using the "networking" +tab in the browser debugging tools (for example, F12). Modify the graph slightly so that it makes a search request, and view the response from the server. Another approach is to use -https://www.elastic.co/guide/en/kibana/current/console-kibana.html[Kibana -Dev Tools] tab - place the index name into the first line: -`GET /_search`, and add your query as the following lines -(just the value of the `"query"` field) +https://www.elastic.co/guide/en/kibana/current/console-kibana.html[Dev Tools]. Place the index name into the first line: +`GET /_search`, then add your query as the following lines +(just the value of the `"query"` field). -If you need to share your graph with someone, you may want to copy the +If you need to share your graph with someone, copy the raw data response to https://gist.github.com/[gist.github.com], possibly with a `.json` extension, use the `[raw]` button, and use that url directly in your graph. @@ -292,9 +297,11 @@ to your kibana.yml file. [[vega-notes]] [[vega-useful-links]] -=== Useful Links +=== Resources and examples + +experimental[] To learn more about Vega and Vega-List, refer to the resources and examples. -==== Vega Editor +==== Vega editor The https://vega.github.io/editor/[Vega Editor] includes examples for Vega & Vega-Lite, but does not support any {kib}-specific features like {es} requests and interactive base maps. @@ -308,28 +315,15 @@ The https://vega.github.io/editor/[Vega Editor] includes examples for Vega & Veg * https://vega.github.io/vega/docs/[Docs] * https://vega.github.io/vega/examples/[Examples] -==== Elastic blog posts -* https://www.elastic.co/blog/getting-started-with-vega-visualizations-in-kibana[Getting Started with Vega Visualizations in Kibana] -* https://www.elastic.co/blog/custom-vega-visualizations-in-kibana[Custom Vega Visualizations in Kibana] -* https://www.elastic.co/blog/sankey-visualization-with-vega-in-kibana[Sankey Visualization with Vega in Kibana] - - -[[vega-using-vega-and-vegalite-examples]] -==== Using Vega and Vega-Lite examples - -When using https://vega.github.io/vega/examples/[Vega] and -https://vega.github.io/vega-lite/examples/[VegaLite] examples, you may +TIP: When you use the examples, you may need to modify the "data" section to use absolute URL. For example, replace `"url": "data/world-110m.json"` with -`"url": "https://vega.github.io/editor/data/world-110m.json"`. Also, -regular Vega examples use `"autosize": "pad"` layout model, whereas -Kibana uses `fit`. Remove all `autosize`, `width`, and `height` -values. See link:#sizing-and-positioning[sizing and positioning]. +`"url": "https://vega.github.io/editor/data/world-110m.json"`. [[vega-additional-configuration-options]] ==== Additional configuration options -These options are specific to the Kibana. link:#vega-with-a-map[Map support] has +These options are specific to the {kib}. link:#vega-with-a-map[Map support] has additional configuration options. [source,yaml] @@ -351,21 +345,3 @@ additional configuration options. /* the rest of Vega code */ } ---- - -[[vega-sizing-and-positioning]] -==== Sizing and positioning - -[[vega-and-vegalite]] -===== Vega and Vega-Lite - -By default, Kibana Vega graphs will use -`autosize = { type: 'fit', contains: 'padding' }` layout model for Vega -and Vega-Lite graphs. The `fit` model uses all available space, ignores -`width` and `height` values, but respects the padding values. You may -override this behaviour by specifying a different `autosize` value. - -[[vega-on-a-map]] -===== Vega on a map - -All Vega graphs will ignore `autosize`, `width`, `height`, and `padding` -values, using `fit` model with zero padding. diff --git a/examples/state_containers_examples/public/todo/app.tsx b/examples/state_containers_examples/public/todo/app.tsx index 319680d07f9bc8..f2183613e4a12c 100644 --- a/examples/state_containers_examples/public/todo/app.tsx +++ b/examples/state_containers_examples/public/todo/app.tsx @@ -20,7 +20,7 @@ import { AppMountParameters } from 'kibana/public'; import ReactDOM from 'react-dom'; import React from 'react'; -import { createHashHistory, createBrowserHistory } from 'history'; +import { createHashHistory } from 'history'; import { TodoAppPage } from './todo'; export interface AppOptions { @@ -35,13 +35,10 @@ export enum History { } export const renderApp = ( - { appBasePath, element }: AppMountParameters, + { appBasePath, element, history: platformHistory }: AppMountParameters, { appInstanceId, appTitle, historyType }: AppOptions ) => { - const history = - historyType === History.Browser - ? createBrowserHistory({ basename: appBasePath }) - : createHashHistory(); + const history = historyType === History.Browser ? platformHistory : createHashHistory(); ReactDOM.render( = ({ filter }) => { return ( <>
- + All - + Completed - + Not Completed @@ -121,6 +124,7 @@ const TodoApp: React.FC = ({ filter }) => { }); }} label={todo.text} + data-test-subj={`todoCheckbox-${todo.id}`} /> { - const history = createBrowserHistory({ basename: appBasePath }); const kbnUrlStateStorage = createKbnUrlStateStorage({ useHash: false, history }); ReactDOM.render( diff --git a/package.json b/package.json index 417480d4635c2c..dc4f94c64eef05 100644 --- a/package.json +++ b/package.json @@ -117,7 +117,7 @@ "dependencies": { "@babel/core": "^7.9.0", "@babel/register": "^7.9.0", - "@elastic/apm-rum": "^4.6.0", + "@elastic/apm-rum": "^5.1.1", "@elastic/charts": "18.3.0", "@elastic/datemath": "5.0.2", "@elastic/ems-client": "7.8.0", diff --git a/packages/kbn-config-schema/src/types/object_type.test.ts b/packages/kbn-config-schema/src/types/object_type.test.ts index 47a0f5f7a5491c..5ab59d1c020779 100644 --- a/packages/kbn-config-schema/src/types/object_type.test.ts +++ b/packages/kbn-config-schema/src/types/object_type.test.ts @@ -18,6 +18,7 @@ */ import { schema } from '..'; +import { TypeOf } from './object_type'; test('returns value by default', () => { const type = schema.object({ @@ -350,3 +351,26 @@ test('unknowns = `ignore` affects only own keys', () => { }) ).toThrowErrorMatchingInlineSnapshot(`"[foo.baz]: definition for this key is missing"`); }); + +test('handles optional properties', () => { + const type = schema.object({ + required: schema.string(), + optional: schema.maybe(schema.string()), + }); + + type SchemaType = TypeOf; + + let foo: SchemaType = { + required: 'foo', + }; + foo = { + required: 'hello', + optional: undefined, + }; + foo = { + required: 'hello', + optional: 'bar', + }; + + expect(foo).toBeDefined(); +}); diff --git a/packages/kbn-config-schema/src/types/object_type.ts b/packages/kbn-config-schema/src/types/object_type.ts index 5a50e714a59311..fee2d02c1bfb96 100644 --- a/packages/kbn-config-schema/src/types/object_type.ts +++ b/packages/kbn-config-schema/src/types/object_type.ts @@ -26,9 +26,26 @@ export type Props = Record>; export type TypeOf> = RT['type']; +type OptionalProperties = Pick< + Base, + { + [Key in keyof Base]: undefined extends TypeOf ? Key : never; + }[keyof Base] +>; + +type RequiredProperties = Pick< + Base, + { + [Key in keyof Base]: undefined extends TypeOf ? never : Key; + }[keyof Base] +>; + // Because of https://github.com/Microsoft/TypeScript/issues/14041 // this might not have perfect _rendering_ output, but it will be typed. -export type ObjectResultType

= Readonly<{ [K in keyof P]: TypeOf }>; +export type ObjectResultType

= Readonly< + { [K in keyof OptionalProperties

]?: TypeOf } & + { [K in keyof RequiredProperties

]: TypeOf } +>; interface UnknownOptions { /** @@ -40,9 +57,7 @@ interface UnknownOptions { unknowns?: 'allow' | 'ignore' | 'forbid'; } -export type ObjectTypeOptions

= TypeOptions< - { [K in keyof P]: TypeOf } -> & +export type ObjectTypeOptions

= TypeOptions> & UnknownOptions; export class ObjectType

extends Type> { diff --git a/packages/kbn-test/src/functional_test_runner/functional_test_runner.ts b/packages/kbn-test/src/functional_test_runner/functional_test_runner.ts index 03075dd4081fd4..3a66ba22ccf3d4 100644 --- a/packages/kbn-test/src/functional_test_runner/functional_test_runner.ts +++ b/packages/kbn-test/src/functional_test_runner/functional_test_runner.ts @@ -30,6 +30,7 @@ import { setupMocha, runTests, Config, + SuiteTracker, } from './lib'; export class FunctionalTestRunner { @@ -52,6 +53,8 @@ export class FunctionalTestRunner { async run() { return await this._run(async (config, coreProviders) => { + SuiteTracker.startTracking(this.lifecycle, this.configFile); + const providers = new ProviderCollection(this.log, [ ...coreProviders, ...readProviderSpec('Service', config.get('services')), diff --git a/packages/kbn-test/src/functional_test_runner/lib/index.ts b/packages/kbn-test/src/functional_test_runner/lib/index.ts index 8940eccad503a4..2e534974e1d76c 100644 --- a/packages/kbn-test/src/functional_test_runner/lib/index.ts +++ b/packages/kbn-test/src/functional_test_runner/lib/index.ts @@ -23,3 +23,4 @@ export { readConfigFile, Config } from './config'; export { readProviderSpec, ProviderCollection, Provider } from './providers'; export { runTests, setupMocha } from './mocha'; export { FailureMetadata } from './failure_metadata'; +export { SuiteTracker } from './suite_tracker'; diff --git a/packages/kbn-test/src/functional_test_runner/lib/suite_tracker.test.ts b/packages/kbn-test/src/functional_test_runner/lib/suite_tracker.test.ts new file mode 100644 index 00000000000000..b6c2c0a6d511d1 --- /dev/null +++ b/packages/kbn-test/src/functional_test_runner/lib/suite_tracker.test.ts @@ -0,0 +1,197 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import fs from 'fs'; +import { join, resolve } from 'path'; + +jest.mock('fs'); +jest.mock('@kbn/dev-utils', () => { + return { REPO_ROOT: '/dev/null/root' }; +}); + +import { REPO_ROOT } from '@kbn/dev-utils'; +import { Lifecycle } from './lifecycle'; +import { SuiteTracker } from './suite_tracker'; + +const DEFAULT_TEST_METADATA_PATH = join(REPO_ROOT, 'target', 'test_metadata.json'); +const MOCK_CONFIG_PATH = join('test', 'config.js'); +const MOCK_TEST_PATH = join('test', 'apps', 'test.js'); +const ENVS_TO_RESET = ['TEST_METADATA_PATH']; + +describe('SuiteTracker', () => { + const originalEnvs: Record = {}; + + beforeEach(() => { + for (const env of ENVS_TO_RESET) { + if (env in process.env) { + originalEnvs[env] = process.env[env] || ''; + delete process.env[env]; + } + } + }); + + afterEach(() => { + for (const env of ENVS_TO_RESET) { + delete process.env[env]; + } + + for (const env of Object.keys(originalEnvs)) { + process.env[env] = originalEnvs[env]; + } + + jest.resetAllMocks(); + }); + + let MOCKS: Record; + + const createMock = (overrides = {}) => { + return { + file: resolve(REPO_ROOT, MOCK_TEST_PATH), + title: 'A Test', + suiteTag: MOCK_TEST_PATH, + ...overrides, + }; + }; + + const runLifecycleWithMocks = async (mocks: object[], fn: (objs: any) => any = () => {}) => { + const lifecycle = new Lifecycle(); + const suiteTracker = SuiteTracker.startTracking( + lifecycle, + resolve(REPO_ROOT, MOCK_CONFIG_PATH) + ); + + const ret = { lifecycle, suiteTracker }; + + for (const mock of mocks) { + await lifecycle.beforeTestSuite.trigger(mock); + } + + if (fn) { + fn(ret); + } + + for (const mock of mocks.reverse()) { + await lifecycle.afterTestSuite.trigger(mock); + } + + return ret; + }; + + beforeEach(() => { + MOCKS = { + WITH_TESTS: createMock({ tests: [{}] }), // i.e. a describe with tests in it + WITHOUT_TESTS: createMock(), // i.e. a describe with only other describes in it + }; + }); + + it('collects metadata for a single suite with multiple describe()s', async () => { + const { suiteTracker } = await runLifecycleWithMocks([MOCKS.WITHOUT_TESTS, MOCKS.WITH_TESTS]); + + const suites = suiteTracker.getAllFinishedSuites(); + expect(suites.length).toBe(1); + const suite = suites[0]; + + expect(suite).toMatchObject({ + config: MOCK_CONFIG_PATH, + file: MOCK_TEST_PATH, + tag: MOCK_TEST_PATH, + hasTests: true, + success: true, + }); + }); + + it('writes metadata to a file when cleanup is triggered', async () => { + const { lifecycle, suiteTracker } = await runLifecycleWithMocks([MOCKS.WITH_TESTS]); + await lifecycle.cleanup.trigger(); + + const suites = suiteTracker.getAllFinishedSuites(); + + const call = (fs.writeFileSync as jest.Mock).mock.calls[0]; + expect(call[0]).toEqual(DEFAULT_TEST_METADATA_PATH); + expect(call[1]).toEqual(JSON.stringify(suites, null, 2)); + }); + + it('respects TEST_METADATA_PATH env var for metadata target override', async () => { + process.env.TEST_METADATA_PATH = resolve(REPO_ROOT, '../fake-test-path'); + const { lifecycle } = await runLifecycleWithMocks([MOCKS.WITH_TESTS]); + await lifecycle.cleanup.trigger(); + + expect((fs.writeFileSync as jest.Mock).mock.calls[0][0]).toEqual( + process.env.TEST_METADATA_PATH + ); + }); + + it('identifies suites with tests as leaf suites', async () => { + const root = createMock({ title: 'root', file: join(REPO_ROOT, 'root.js') }); + const parent = createMock({ parent: root }); + const withTests = createMock({ parent, tests: [{}] }); + + const { suiteTracker } = await runLifecycleWithMocks([root, parent, withTests]); + const suites = suiteTracker.getAllFinishedSuites(); + + const finishedRoot = suites.find(s => s.title === 'root'); + const finishedWithTests = suites.find(s => s.title !== 'root'); + + expect(finishedRoot).toBeTruthy(); + expect(finishedRoot?.hasTests).toBeFalsy(); + expect(finishedWithTests?.hasTests).toBe(true); + }); + + describe('with a failing suite', () => { + let root: any; + let parent: any; + let failed: any; + + beforeEach(() => { + root = createMock({ file: join(REPO_ROOT, 'root.js') }); + parent = createMock({ parent: root }); + failed = createMock({ parent, tests: [{}] }); + }); + + it('marks parent suites as not successful when a test fails', async () => { + const { suiteTracker } = await runLifecycleWithMocks( + [root, parent, failed], + async ({ lifecycle }) => { + await lifecycle.testFailure.trigger(Error('test'), { parent: failed }); + } + ); + + const suites = suiteTracker.getAllFinishedSuites(); + expect(suites.length).toBe(2); + for (const suite of suites) { + expect(suite.success).toBeFalsy(); + } + }); + + it('marks parent suites as not successful when a test hook fails', async () => { + const { suiteTracker } = await runLifecycleWithMocks( + [root, parent, failed], + async ({ lifecycle }) => { + await lifecycle.testHookFailure.trigger(Error('test'), { parent: failed }); + } + ); + + const suites = suiteTracker.getAllFinishedSuites(); + expect(suites.length).toBe(2); + for (const suite of suites) { + expect(suite.success).toBeFalsy(); + } + }); + }); +}); diff --git a/packages/kbn-test/src/functional_test_runner/lib/suite_tracker.ts b/packages/kbn-test/src/functional_test_runner/lib/suite_tracker.ts new file mode 100644 index 00000000000000..8967251ea78de7 --- /dev/null +++ b/packages/kbn-test/src/functional_test_runner/lib/suite_tracker.ts @@ -0,0 +1,147 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import fs from 'fs'; +import { dirname, relative, resolve } from 'path'; + +import { REPO_ROOT } from '@kbn/dev-utils'; + +import { Lifecycle } from './lifecycle'; + +export interface SuiteInProgress { + startTime?: Date; + endTime?: Date; + success?: boolean; +} + +export interface SuiteWithMetadata { + config: string; + file: string; + tag: string; + title: string; + startTime: Date; + endTime: Date; + duration: number; + success: boolean; + hasTests: boolean; +} + +const getTestMetadataPath = () => { + return process.env.TEST_METADATA_PATH || resolve(REPO_ROOT, 'target', 'test_metadata.json'); +}; + +export class SuiteTracker { + finishedSuitesByConfig: Record> = {}; + inProgressSuites: Map = new Map(); + + static startTracking(lifecycle: Lifecycle, configPath: string): SuiteTracker { + const suiteTracker = new SuiteTracker(lifecycle, configPath); + return suiteTracker; + } + + getTracked(suite: object): SuiteInProgress { + if (!this.inProgressSuites.has(suite)) { + this.inProgressSuites.set(suite, { success: undefined } as SuiteInProgress); + } + return this.inProgressSuites.get(suite)!; + } + + constructor(lifecycle: Lifecycle, configPathAbsolute: string) { + if (fs.existsSync(getTestMetadataPath())) { + fs.unlinkSync(getTestMetadataPath()); + } else { + fs.mkdirSync(dirname(getTestMetadataPath()), { recursive: true }); + } + + const config = relative(REPO_ROOT, configPathAbsolute); + + lifecycle.beforeTestSuite.add(suite => { + const tracked = this.getTracked(suite); + tracked.startTime = new Date(); + }); + + // If a test fails, we want to make sure all of the ancestors, all the way up to the root, get marked as failed + // This information is not available on the mocha objects without traversing all descendants of a given node + const handleFailure = (_: any, test: any) => { + let parent = test.parent; + + // Infinite loop protection, just in case + for (let i = 0; i < 500 && parent; i++) { + if (this.inProgressSuites.has(parent)) { + this.getTracked(parent).success = false; + } + parent = parent.parent; + } + }; + + lifecycle.testFailure.add(handleFailure); + lifecycle.testHookFailure.add(handleFailure); + + lifecycle.afterTestSuite.add(suite => { + const tracked = this.getTracked(suite); + tracked.endTime = new Date(); + + // The suite ended without any children failing, so we can mark it as successful + if (typeof tracked.success === 'undefined') { + tracked.success = true; + } + + let duration = tracked.endTime.getTime() - (tracked.startTime || new Date()).getTime(); + duration = Math.floor(duration / 1000); + + const file = relative(REPO_ROOT, suite.file); + + this.finishedSuitesByConfig[config] = this.finishedSuitesByConfig[config] || {}; + + // This will get called multiple times for a test file that has multiple describes in it or similar + // This is okay, because the last one that fires is always the root of the file, which is is the one we ultimately want + this.finishedSuitesByConfig[config][file] = { + ...tracked, + duration, + config, + file, + tag: suite.suiteTag, + title: suite.title, + hasTests: !!( + (suite.tests && suite.tests.length) || + // The below statement is so that `hasTests` will bubble up nested describes in the same file + (this.finishedSuitesByConfig[config][file] && + this.finishedSuitesByConfig[config][file].hasTests) + ), + } as SuiteWithMetadata; + }); + + lifecycle.cleanup.add(() => { + const suites = this.getAllFinishedSuites(); + + fs.writeFileSync(getTestMetadataPath(), JSON.stringify(suites, null, 2)); + }); + } + + getAllFinishedSuites() { + const flattened: SuiteWithMetadata[] = []; + for (const byFile of Object.values(this.finishedSuitesByConfig)) { + for (const suite of Object.values(byFile)) { + flattened.push(suite); + } + } + + flattened.sort((a, b) => b.duration - a.duration); + return flattened; + } +} diff --git a/scripts/prettier_on_changed.js b/scripts/prettier_on_changed.js new file mode 100644 index 00000000000000..f9598110f91fd3 --- /dev/null +++ b/scripts/prettier_on_changed.js @@ -0,0 +1,21 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +require('../src/setup_node_env/babel_register'); +require('../src/dev/run_prettier_on_changed'); diff --git a/src/core/server/http/router/validator/validator.ts b/src/core/server/http/router/validator/validator.ts index 6c766e69f0f37f..a2299b47ae253d 100644 --- a/src/core/server/http/router/validator/validator.ts +++ b/src/core/server/http/router/validator/validator.ts @@ -17,7 +17,14 @@ * under the License. */ -import { ValidationError, Type, schema, ObjectType, isConfigSchema } from '@kbn/config-schema'; +import { + ValidationError, + Type, + schema, + ObjectType, + TypeOf, + isConfigSchema, +} from '@kbn/config-schema'; import { Stream } from 'stream'; import { RouteValidationError } from './validator_error'; @@ -85,7 +92,7 @@ type RouteValidationResultType | undefined> = T extends RouteValidationFunction ? ReturnType['value'] : T extends Type - ? ReturnType + ? TypeOf : undefined >; @@ -170,7 +177,7 @@ export class RouteValidator

{ * @internal */ public getParams(data: unknown, namespace?: string): Readonly

{ - return this.validate(this.config.params, this.options.unsafe?.params, data, namespace); + return this.validate(this.config.params, this.options.unsafe?.params, data, namespace) as P; } /** @@ -178,7 +185,7 @@ export class RouteValidator

{ * @internal */ public getQuery(data: unknown, namespace?: string): Readonly { - return this.validate(this.config.query, this.options.unsafe?.query, data, namespace); + return this.validate(this.config.query, this.options.unsafe?.query, data, namespace) as Q; } /** @@ -186,7 +193,7 @@ export class RouteValidator

{ * @internal */ public getBody(data: unknown, namespace?: string): Readonly { - return this.validate(this.config.body, this.options.unsafe?.body, data, namespace); + return this.validate(this.config.body, this.options.unsafe?.body, data, namespace) as B; } /** diff --git a/src/dev/build/tasks/os_packages/docker_generator/resources/bin/kibana-docker b/src/dev/build/tasks/os_packages/docker_generator/resources/bin/kibana-docker index b0ab274ced77bf..9b7964462ad4f6 100755 --- a/src/dev/build/tasks/os_packages/docker_generator/resources/bin/kibana-docker +++ b/src/dev/build/tasks/os_packages/docker_generator/resources/bin/kibana-docker @@ -195,6 +195,7 @@ kibana_vars=( xpack.reporting.capture.viewport.width xpack.reporting.capture.zoom xpack.reporting.csv.checkForFormulas + xpack.reporting.csv.escapeFormulaValues xpack.reporting.csv.enablePanelActionDownload xpack.reporting.csv.maxSizeBytes xpack.reporting.csv.scroll.duration diff --git a/src/dev/eslint/index.js b/src/dev/eslint/index.ts similarity index 100% rename from src/dev/eslint/index.js rename to src/dev/eslint/index.ts diff --git a/src/dev/eslint/lint_files.js b/src/dev/eslint/lint_files.ts similarity index 90% rename from src/dev/eslint/lint_files.js rename to src/dev/eslint/lint_files.ts index a76edeb2eb865f..80c493233f39ab 100644 --- a/src/dev/eslint/lint_files.js +++ b/src/dev/eslint/lint_files.ts @@ -19,7 +19,8 @@ import { CLIEngine } from 'eslint'; -import { createFailError } from '@kbn/dev-utils'; +import { createFailError, ToolingLog } from '@kbn/dev-utils'; +import { File } from '../file'; import { REPO_ROOT } from '../constants'; /** @@ -30,7 +31,7 @@ import { REPO_ROOT } from '../constants'; * @param {Array} files * @return {undefined} */ -export function lintFiles(log, files, { fix } = {}) { +export function lintFiles(log: ToolingLog, files: File[], { fix }: { fix?: boolean } = {}) { const cli = new CLIEngine({ cache: true, cwd: REPO_ROOT, diff --git a/src/dev/eslint/pick_files_to_lint.js b/src/dev/eslint/pick_files_to_lint.ts similarity index 88% rename from src/dev/eslint/pick_files_to_lint.js rename to src/dev/eslint/pick_files_to_lint.ts index e3212c00d9e0de..b96781fc3a611f 100644 --- a/src/dev/eslint/pick_files_to_lint.js +++ b/src/dev/eslint/pick_files_to_lint.ts @@ -16,9 +16,11 @@ * specific language governing permissions and limitations * under the License. */ - import { CLIEngine } from 'eslint'; +import { ToolingLog } from '@kbn/dev-utils'; +import { File } from '../file'; + /** * Filters a list of files to only include lintable files. * @@ -26,8 +28,8 @@ import { CLIEngine } from 'eslint'; * @param {Array} files * @return {Array} */ -export function pickFilesToLint(log, files) { - const cli = new CLIEngine(); +export function pickFilesToLint(log: ToolingLog, files: File[]) { + const cli = new CLIEngine({}); return files.filter(file => { if (!file.isJs() && !file.isTypescript()) { diff --git a/src/dev/run_prettier_on_changed.ts b/src/dev/run_prettier_on_changed.ts new file mode 100644 index 00000000000000..deca4fa1be3ce5 --- /dev/null +++ b/src/dev/run_prettier_on_changed.ts @@ -0,0 +1,87 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import execa from 'execa'; +// @ts-ignore +import SimpleGit from 'simple-git'; +import { run } from '@kbn/dev-utils'; +import dedent from 'dedent'; +import Util from 'util'; + +import pkg from '../../package.json'; +import { REPO_ROOT } from './constants'; +import { File } from './file'; +import * as Eslint from './eslint'; + +run(async function getChangedFiles({ log }) { + const simpleGit = new SimpleGit(REPO_ROOT); + + const getStatus = Util.promisify(simpleGit.status.bind(simpleGit)); + const gitStatus = await getStatus(); + + if (gitStatus.files.length > 0) { + throw new Error( + dedent(`You should run prettier formatter on a clean branch. + Found not committed changes to: + ${gitStatus.files.map((f: { path: string }) => f.path).join('\n')}`) + ); + } + + const revParse = Util.promisify(simpleGit.revparse.bind(simpleGit)); + const currentBranch = await revParse(['--abbrev-ref', 'HEAD']); + const headBranch = pkg.branch; + + const diff = Util.promisify(simpleGit.diff.bind(simpleGit)); + + const changedFileStatuses: string = await diff([ + '--name-status', + `${headBranch}...${currentBranch}`, + ]); + + const changedFiles = changedFileStatuses + .split('\n') + // Ignore blank lines + .filter(line => line.trim().length > 0) + // git diff --name-status outputs lines with two OR three parts + // separated by a tab character + .map(line => line.trim().split('\t')) + .map(([status, ...paths]) => { + // ignore deleted files + if (status === 'D') { + return undefined; + } + + // the status is always in the first column + // .. If the file is edited the line will only have two columns + // .. If the file is renamed it will have three columns + // .. In any case, the last column is the CURRENT path to the file + return new File(paths[paths.length - 1]); + }) + .filter((file): file is File => Boolean(file)); + + const pathsToLint = Eslint.pickFilesToLint(log, changedFiles).map(f => f.getAbsolutePath()); + + if (pathsToLint.length > 0) { + log.debug('[prettier] run on %j files: ', pathsToLint.length, pathsToLint); + } + + while (pathsToLint.length > 0) { + await execa('npx', ['prettier@2.0.4', '--write', ...pathsToLint.splice(0, 100)]); + } +}); diff --git a/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table.js b/src/legacy/core_plugins/kibana/public/__tests__/vis_type_table/agg_table.js similarity index 94% rename from src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table.js rename to src/legacy/core_plugins/kibana/public/__tests__/vis_type_table/agg_table.js index a23407a599ae27..b212ecf578dd1f 100644 --- a/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table.js +++ b/src/legacy/core_plugins/kibana/public/__tests__/vis_type_table/agg_table.js @@ -22,11 +22,18 @@ import moment from 'moment'; import ngMock from 'ng_mock'; import expect from '@kbn/expect'; import sinon from 'sinon'; -import { npStart } from '../../legacy_imports'; +import './legacy'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { npStart } from 'ui/new_platform'; import { round } from 'lodash'; -import { getAngularModule } from '../../get_inner_angular'; -import { initTableVisLegacyModule } from '../../table_vis_legacy_module'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { getInnerAngular } from '../../../../../../plugins/vis_type_table/public/get_inner_angular'; + +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { initTableVisLegacyModule } from '../../../../../../plugins/vis_type_table/public/table_vis_legacy_module'; import { tabifiedData } from './tabified_data'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { configureAppAngularModule } from '../../../../../../plugins/kibana_legacy/public/angular'; describe('Table Vis - AggTable Directive', function() { let $rootScope; @@ -34,7 +41,8 @@ describe('Table Vis - AggTable Directive', function() { let settings; const initLocalAngular = () => { - const tableVisModule = getAngularModule('kibana/table_vis', npStart.core); + const tableVisModule = getInnerAngular('kibana/table_vis', npStart.core); + configureAppAngularModule(tableVisModule, npStart.core, true); initTableVisLegacyModule(tableVisModule); }; diff --git a/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table_group.js b/src/legacy/core_plugins/kibana/public/__tests__/vis_type_table/agg_table_group.js similarity index 81% rename from src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table_group.js rename to src/legacy/core_plugins/kibana/public/__tests__/vis_type_table/agg_table_group.js index 40a0993ccb0175..3cd7de393d66a8 100644 --- a/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table_group.js +++ b/src/legacy/core_plugins/kibana/public/__tests__/vis_type_table/agg_table_group.js @@ -20,17 +20,24 @@ import $ from 'jquery'; import ngMock from 'ng_mock'; import expect from '@kbn/expect'; -import { npStart } from '../../legacy_imports'; -import { getAngularModule } from '../../get_inner_angular'; -import { initTableVisLegacyModule } from '../../table_vis_legacy_module'; +import './legacy'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { getInnerAngular } from '../../../../../../plugins/vis_type_table/public/get_inner_angular'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { initTableVisLegacyModule } from '../../../../../../plugins/vis_type_table/public/table_vis_legacy_module'; import { tabifiedData } from './tabified_data'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { npStart } from 'ui/new_platform'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { configureAppAngularModule } from '../../../../../../plugins/kibana_legacy/public/angular'; describe('Table Vis - AggTableGroup Directive', function() { let $rootScope; let $compile; const initLocalAngular = () => { - const tableVisModule = getAngularModule('kibana/table_vis', npStart.core); + const tableVisModule = getInnerAngular('kibana/table_vis', npStart.core); + configureAppAngularModule(tableVisModule, npStart.core, true); initTableVisLegacyModule(tableVisModule); }; diff --git a/src/legacy/core_plugins/vis_type_table/public/legacy.ts b/src/legacy/core_plugins/kibana/public/__tests__/vis_type_table/legacy.ts similarity index 69% rename from src/legacy/core_plugins/vis_type_table/public/legacy.ts rename to src/legacy/core_plugins/kibana/public/__tests__/vis_type_table/legacy.ts index 3d5f8c1b3efe92..c6467a5beae686 100644 --- a/src/legacy/core_plugins/vis_type_table/public/legacy.ts +++ b/src/legacy/core_plugins/kibana/public/__tests__/vis_type_table/legacy.ts @@ -16,19 +16,23 @@ * specific language governing permissions and limitations * under the License. */ - import { PluginInitializerContext } from 'kibana/public'; -import { npSetup, npStart } from './legacy_imports'; -import { plugin } from '.'; - -import { TablePluginSetupDependencies } from './plugin'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { npStart, npSetup } from 'ui/new_platform'; +import { + TableVisPlugin, + TablePluginSetupDependencies, + // eslint-disable-next-line @kbn/eslint/no-restricted-paths +} from '../../../../../../plugins/vis_type_table/public/plugin'; const plugins: Readonly = { expressions: npSetup.plugins.expressions, visualizations: npSetup.plugins.visualizations, }; -const pluginInstance = plugin({} as PluginInitializerContext); +const pluginInstance = new TableVisPlugin({} as PluginInitializerContext); export const setup = pluginInstance.setup(npSetup.core, plugins); -export const start = pluginInstance.start(npStart.core, { data: npStart.plugins.data }); +export const start = pluginInstance.start(npStart.core, { + data: npStart.plugins.data, +}); diff --git a/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/tabified_data.js b/src/legacy/core_plugins/kibana/public/__tests__/vis_type_table/tabified_data.js similarity index 100% rename from src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/tabified_data.js rename to src/legacy/core_plugins/kibana/public/__tests__/vis_type_table/tabified_data.js diff --git a/src/legacy/core_plugins/kibana/public/discover/build_services.ts b/src/legacy/core_plugins/kibana/public/discover/build_services.ts index a3a99a0ded523c..c56e50f3b27ffe 100644 --- a/src/legacy/core_plugins/kibana/public/discover/build_services.ts +++ b/src/legacy/core_plugins/kibana/public/discover/build_services.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { createHashHistory, History } from 'history'; +import { History } from 'history'; import { Capabilities, @@ -51,7 +51,7 @@ export interface DiscoverServices { data: DataPublicPluginStart; docLinks: DocLinksStart; DocViewer: DocViewerComponent; - history: History; + history: () => History; theme: ChartsPluginStart['theme']; filterManager: FilterManager; indexPatterns: IndexPatternsContract; @@ -67,7 +67,8 @@ export interface DiscoverServices { } export async function buildServices( core: CoreStart, - plugins: DiscoverStartPlugins + plugins: DiscoverStartPlugins, + getHistory: () => History ): Promise { const services = { savedObjectsClient: core.savedObjects.client, @@ -77,6 +78,7 @@ export async function buildServices( overlays: core.overlays, }; const savedObjectService = createSavedSearchesLoader(services); + return { addBasePath: core.http.basePath.prepend, capabilities: core.application.capabilities, @@ -85,11 +87,11 @@ export async function buildServices( data: plugins.data, docLinks: core.docLinks, DocViewer: plugins.discover.docViews.DocViewer, - history: createHashHistory(), theme: plugins.charts.theme, filterManager: plugins.data.query.filterManager, getSavedSearchById: async (id: string) => savedObjectService.get(id), getSavedSearchUrlById: async (id: string) => savedObjectService.urlFor(id), + history: getHistory, indexPatterns: plugins.data.indexPatterns, inspector: plugins.inspector, // @ts-ignore diff --git a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts index 0a81ca0222b0a0..156267bdfa87e0 100644 --- a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts +++ b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +import { createHashHistory } from 'history'; import { DiscoverServices } from './build_services'; import { createGetterSetter } from '../../../../../plugins/kibana_utils/public'; import { search } from '../../../../../plugins/data/public'; @@ -52,6 +53,11 @@ export const [getUrlTracker, setUrlTracker] = createGetterSetter<{ setTrackedUrl: (url: string) => void; }>('urlTracker'); +/** + * Makes sure discover and context are using one instance of history + */ +export const getHistory = _.once(() => createHashHistory()); + export const { getRequestInspectorStats, getResponseInspectorStats, tabifyAggResponse } = search; export { unhashUrl, diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context.js b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context.js index 5b03b313e4e3e6..032ec7af09a301 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context.js +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context.js @@ -81,6 +81,7 @@ function ContextAppRouteController($routeParams, $scope, $route) { defaultStepSize: getServices().uiSettings.get('context:defaultSize'), timeFieldName: indexPattern.timeFieldName, storeInSessionStorage: getServices().uiSettings.get('state:storeInSessionStorage'), + history: getServices().history(), }); this.state = { ...appState.getState() }; this.anchorId = $routeParams.id; diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_state.ts b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_state.ts index ed59143b163f69..b46995d44d826d 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_state.ts +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_state.ts @@ -17,7 +17,7 @@ * under the License. */ import _ from 'lodash'; -import { createBrowserHistory, History } from 'history'; +import { History } from 'history'; import { createStateContainer, createKbnUrlStateStorage, @@ -71,9 +71,9 @@ interface GetStateParams { */ storeInSessionStorage?: boolean; /** - * Browser history used for testing + * History instance to use */ - history?: History; + history: History; } interface GetStateReturn { @@ -126,7 +126,7 @@ export function getState({ }: GetStateParams): GetStateReturn { const stateStorage = createKbnUrlStateStorage({ useHash: storeInSessionStorage, - history: history ? history : createBrowserHistory(), + history, }); const globalStateInitial = stateStorage.get(GLOBAL_STATE_URL_KEY) as GlobalState; diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js index 72276a38f6ac21..567cfda45cc0d1 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js @@ -57,8 +57,7 @@ const { core, chrome, data, - docTitle, - history, + history: getHistory, indexPatterns, filterManager, share, @@ -117,6 +116,7 @@ app.config($routeProvider => { reloadOnSearch: false, resolve: { savedObjects: function($route, Promise) { + const history = getHistory(); const savedSearchId = $route.current.params.id; return ensureDefaultIndexPattern(core, data, history).then(() => { const { appStateContainer } = getState({ history }); @@ -205,6 +205,8 @@ function discoverController( return isDefaultType($scope.indexPattern) ? $scope.indexPattern.timeFieldName : undefined; }; + const history = getHistory(); + const { appStateContainer, startSync: startStateSync, @@ -214,6 +216,7 @@ function discoverController( isAppStateDirty, kbnUrlStateStorage, getPreviousAppState, + resetInitialAppState, } = getState({ defaultAppState: getStateDefaults(), storeInSessionStorage: config.get('state:storeInSessionStorage'), @@ -373,6 +376,8 @@ function discoverController( // If the save wasn't successful, put the original values back. if (!response.id || response.error) { savedSearch.title = currentTitle; + } else { + resetInitialAppState(); } return response; }); @@ -758,7 +763,7 @@ function discoverController( } else { // Update defaults so that "reload saved query" functions correctly setAppState(getStateDefaults()); - docTitle.change(savedSearch.lastSavedTitle); + chrome.docTitle.change(savedSearch.lastSavedTitle); } } }); diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/sidebar/discover_field.test.tsx b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/sidebar/discover_field.test.tsx index 9a6bd65813d184..fdae2c0c16c9f2 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/sidebar/discover_field.test.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/sidebar/discover_field.test.tsx @@ -31,11 +31,11 @@ import { IndexPatternField } from '../../../../../../../../plugins/data/public'; jest.mock('../../../kibana_services', () => ({ getServices: () => ({ - history: { + history: () => ({ location: { search: '', }, - }, + }), capabilities: { visualize: { show: true, diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/sidebar/discover_sidebar.test.tsx b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/sidebar/discover_sidebar.test.tsx index 0df14515adc6d4..29451c075bcad5 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/sidebar/discover_sidebar.test.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/sidebar/discover_sidebar.test.tsx @@ -36,11 +36,11 @@ import { SavedObject } from '../../../../../../../../core/types'; jest.mock('../../../kibana_services', () => ({ getServices: () => ({ - history: { + history: () => ({ location: { search: '', }, - }, + }), capabilities: { visualize: { show: true, diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/sidebar/lib/visualize_url_utils.ts b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/sidebar/lib/visualize_url_utils.ts index d146d212055b76..968ceeeab73a5f 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/components/sidebar/lib/visualize_url_utils.ts +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/components/sidebar/lib/visualize_url_utils.ts @@ -125,7 +125,7 @@ export function getVisualizeUrl( services: DiscoverServices ) { const aggsTermSize = services.uiSettings.get('discover:aggs:terms:size'); - const urlParams = parse(services.history.location.search) as Record; + const urlParams = parse(services.history().location.search) as Record; if ( (field.type === KBN_FIELD_TYPES.GEO_POINT || field.type === KBN_FIELD_TYPES.GEO_SHAPE) && diff --git a/src/legacy/core_plugins/kibana/public/discover/plugin.ts b/src/legacy/core_plugins/kibana/public/discover/plugin.ts index d05e96ccaaf0b0..42883abe98171b 100644 --- a/src/legacy/core_plugins/kibana/public/discover/plugin.ts +++ b/src/legacy/core_plugins/kibana/public/discover/plugin.ts @@ -31,7 +31,7 @@ import { registerFeature } from './np_ready/register_feature'; import './kibana_services'; import { EmbeddableStart, EmbeddableSetup } from '../../../../../plugins/embeddable/public'; import { getInnerAngularModule, getInnerAngularModuleEmbeddable } from './get_inner_angular'; -import { setAngularModule, setServices, setUrlTracker } from './kibana_services'; +import { getHistory, setAngularModule, setServices, setUrlTracker } from './kibana_services'; import { NavigationPublicPluginStart as NavigationStart } from '../../../../../plugins/navigation/public'; import { ChartsPluginStart } from '../../../../../plugins/charts/public'; import { buildServices } from './build_services'; @@ -98,6 +98,10 @@ export class DiscoverPlugin implements Plugin { stop: stopUrlTracker, setActiveUrl: setTrackedUrl, } = createKbnUrlTracker({ + // we pass getter here instead of plain `history`, + // so history is lazily created (when app is mounted) + // this prevents redundant `#` when not in discover app + getHistory, baseUrl: core.http.basePath.prepend('/app/kibana'), defaultSubUrl: '#/discover', storageKey: `lastUrl:${core.http.basePath.get()}:discover`, @@ -174,7 +178,7 @@ export class DiscoverPlugin implements Plugin { if (this.servicesInitialized) { return { core, plugins }; } - const services = await buildServices(core, plugins); + const services = await buildServices(core, plugins, getHistory); setServices(services); this.servicesInitialized = true; diff --git a/src/legacy/core_plugins/kibana/public/kibana.js b/src/legacy/core_plugins/kibana/public/kibana.js index 20c46765dcb302..ea0d5ad3790b13 100644 --- a/src/legacy/core_plugins/kibana/public/kibana.js +++ b/src/legacy/core_plugins/kibana/public/kibana.js @@ -49,8 +49,9 @@ import { showAppRedirectNotification } from '../../../../plugins/kibana_legacy/p import 'leaflet'; import { localApplicationService } from './local_application_service'; -npSetup.plugins.kibanaLegacy.forwardApp('doc', 'discover', { keepPrefix: true }); -npSetup.plugins.kibanaLegacy.forwardApp('context', 'discover', { keepPrefix: true }); +npSetup.plugins.kibanaLegacy.registerLegacyAppAlias('doc', 'discover', { keepPrefix: true }); +npSetup.plugins.kibanaLegacy.registerLegacyAppAlias('context', 'discover', { keepPrefix: true }); + localApplicationService.attachToAngular(routes); routes.enable(); diff --git a/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts b/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts index 14564cfd9ee784..f38c410e6832f7 100644 --- a/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts +++ b/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts @@ -98,14 +98,29 @@ export class LocalApplicationService { } }); - npStart.plugins.kibanaLegacy.getForwards().forEach(({ legacyAppId, newAppId, keepPrefix }) => { - angularRouteManager.when(matchAllWithPrefix(legacyAppId), { - resolveRedirectTo: ($location: ILocationService) => { - const url = $location.url(); - return `/${newAppId}${keepPrefix ? url : url.replace(legacyAppId, '')}`; + npStart.plugins.kibanaLegacy.getForwards().forEach(forwardDefinition => { + angularRouteManager.when(matchAllWithPrefix(forwardDefinition.legacyAppId), { + outerAngularWrapperRoute: true, + reloadOnSearch: false, + reloadOnUrl: false, + template: '', + controller($location: ILocationService) { + const newPath = forwardDefinition.rewritePath($location.url()); + npStart.core.application.navigateToApp(forwardDefinition.newAppId, { path: newPath }); }, }); }); + + npStart.plugins.kibanaLegacy + .getLegacyAppAliases() + .forEach(({ legacyAppId, newAppId, keepPrefix }) => { + angularRouteManager.when(matchAllWithPrefix(legacyAppId), { + resolveRedirectTo: ($location: ILocationService) => { + const url = $location.url(); + return `/${newAppId}${keepPrefix ? url : url.replace(legacyAppId, '')}`; + }, + }); + }); } } diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_indices.test.ts b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_indices.test.ts index 40583af7177fee..b1500f8303b666 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_indices.test.ts +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/lib/get_indices.test.ts @@ -20,7 +20,7 @@ import { getIndices } from './get_indices'; import { IndexPatternCreationConfig } from '../../../../../../../../../plugins/index_pattern_management/public'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { LegacyApiCaller } from '../../../../../../../../../plugins/data/public/search'; +import { LegacyApiCaller } from '../../../../../../../../../plugins/data/public/search/legacy'; export const successfulResponse = { hits: { diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/constants.ts b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/constants.ts new file mode 100644 index 00000000000000..56da031eb4ee86 --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/constants.ts @@ -0,0 +1,22 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export const TAB_INDEXED_FIELDS = 'indexedFields'; +export const TAB_SCRIPTED_FIELDS = 'scriptedFields'; +export const TAB_SOURCE_FILTERS = 'sourceFilters'; diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/create_edit_field/create_edit_field.html b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/create_edit_field.html similarity index 100% rename from src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/create_edit_field/create_edit_field.html rename to src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/create_edit_field.html diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/create_edit_field/create_edit_field.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/create_edit_field/create_edit_field.js deleted file mode 100644 index d8b3196d48fd18..00000000000000 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/create_edit_field/create_edit_field.js +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { IndexPatternField } from '../../../../../../../../../plugins/data/public'; -import { RegistryFieldFormatEditorsProvider } from 'ui/registry/field_format_editors'; -import { docTitle } from 'ui/doc_title'; -import { KbnUrlProvider } from 'ui/url'; -import uiRoutes from 'ui/routes'; -import { toastNotifications } from 'ui/notify'; -import { npStart } from 'ui/new_platform'; - -import template from './create_edit_field.html'; -import { getEditFieldBreadcrumbs, getCreateFieldBreadcrumbs } from '../../breadcrumbs'; - -import React from 'react'; -import { render, unmountComponentAtNode } from 'react-dom'; -import { FieldEditor } from 'ui/field_editor'; -import { I18nContext } from 'ui/i18n'; -import { i18n } from '@kbn/i18n'; - -import { IndexHeader } from '../index_header'; - -const REACT_FIELD_EDITOR_ID = 'reactFieldEditor'; -const renderFieldEditor = ( - $scope, - indexPattern, - field, - { getConfig, $http, fieldFormatEditors, redirectAway } -) => { - $scope.$$postDigest(() => { - const node = document.getElementById(REACT_FIELD_EDITOR_ID); - if (!node) { - return; - } - - render( - - - - , - node - ); - }); -}; - -const destroyFieldEditor = () => { - const node = document.getElementById(REACT_FIELD_EDITOR_ID); - node && unmountComponentAtNode(node); -}; - -uiRoutes - .when('/management/kibana/index_patterns/:indexPatternId/field/:fieldName*', { - mode: 'edit', - k7Breadcrumbs: getEditFieldBreadcrumbs, - }) - .when('/management/kibana/index_patterns/:indexPatternId/create-field/', { - mode: 'create', - k7Breadcrumbs: getCreateFieldBreadcrumbs, - }) - .defaults(/management\/kibana\/index_patterns\/[^\/]+\/(field|create-field)(\/|$)/, { - template, - mapBreadcrumbs($route, breadcrumbs) { - const { indexPattern } = $route.current.locals; - return breadcrumbs.map(crumb => { - if (crumb.id !== indexPattern.id) { - return crumb; - } - - return { - ...crumb, - display: indexPattern.title, - }; - }); - }, - resolve: { - indexPattern: function($route, Promise, redirectWhenMissing) { - const { indexPatterns } = npStart.plugins.data; - return Promise.resolve(indexPatterns.get($route.current.params.indexPatternId)).catch( - redirectWhenMissing('/management/kibana/index_patterns') - ); - }, - }, - controllerAs: 'fieldSettings', - controller: function FieldEditorPageController( - $scope, - $route, - $timeout, - $http, - Private, - config - ) { - const getConfig = (...args) => config.get(...args); - const fieldFormatEditors = Private(RegistryFieldFormatEditorsProvider); - const kbnUrl = Private(KbnUrlProvider); - - this.mode = $route.current.mode; - this.indexPattern = $route.current.locals.indexPattern; - - if (this.mode === 'edit') { - const fieldName = $route.current.params.fieldName; - this.field = this.indexPattern.fields.getByName(fieldName); - - if (!this.field) { - const message = i18n.translate('kbn.management.editIndexPattern.scripted.noFieldLabel', { - defaultMessage: - "'{indexPatternTitle}' index pattern doesn't have a scripted field called '{fieldName}'", - values: { indexPatternTitle: this.indexPattern.title, fieldName }, - }); - toastNotifications.add(message); - - kbnUrl.redirectToRoute(this.indexPattern, 'edit'); - return; - } - } else if (this.mode === 'create') { - this.field = new IndexPatternField(this.indexPattern, { - scripted: true, - type: 'number', - }); - } else { - const errorMessage = i18n.translate( - 'kbn.management.editIndexPattern.scripted.unknownModeErrorMessage', - { - defaultMessage: 'unknown fieldSettings mode {mode}', - values: { mode: this.mode }, - } - ); - throw new Error(errorMessage); - } - - const fieldName = - this.field.name || - i18n.translate('kbn.management.editIndexPattern.scripted.newFieldPlaceholder', { - defaultMessage: 'New Scripted Field', - }); - docTitle.change([fieldName, this.indexPattern.title]); - - renderFieldEditor($scope, this.indexPattern, this.field, { - getConfig, - $http, - fieldFormatEditors, - redirectAway: () => { - $timeout(() => { - kbnUrl.changeToRoute( - this.indexPattern, - this.field.scripted ? 'scriptedFields' : 'indexedFields' - ); - }); - }, - }); - - $scope.$on('$destroy', () => { - destroyFieldEditor(); - }); - }, - }); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/create_edit_field/create_edit_field.tsx b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/create_edit_field/create_edit_field.tsx new file mode 100644 index 00000000000000..4839870f0f3c8a --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/create_edit_field/create_edit_field.tsx @@ -0,0 +1,111 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React from 'react'; +import { withRouter, RouteComponentProps } from 'react-router-dom'; +// @ts-ignore +import { FieldEditor } from 'ui/field_editor'; + +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { IndexHeader } from '../index_header'; +import { IndexPattern, IndexPatternField } from '../../../../../../../../../plugins/data/public'; +import { ChromeDocTitle, NotificationsStart } from '../../../../../../../../../core/public'; +import { TAB_SCRIPTED_FIELDS, TAB_INDEXED_FIELDS } from '../constants'; + +interface CreateEditFieldProps extends RouteComponentProps { + indexPattern: IndexPattern; + mode?: string; + fieldName?: string; + fieldFormatEditors: any; + getConfig: (name: string) => any; + services: { + notifications: NotificationsStart; + docTitle: ChromeDocTitle; + http: Function; + }; +} + +const newFieldPlaceholder = i18n.translate( + 'kbn.management.editIndexPattern.scripted.newFieldPlaceholder', + { + defaultMessage: 'New Scripted Field', + } +); + +export const CreateEditField = withRouter( + ({ + indexPattern, + mode, + fieldName, + fieldFormatEditors, + getConfig, + services, + history, + }: CreateEditFieldProps) => { + const field = + mode === 'edit' && fieldName + ? indexPattern.fields.getByName(fieldName) + : new IndexPatternField(indexPattern, { + scripted: true, + type: 'number', + }); + + const url = `/management/kibana/index_patterns/${indexPattern.id}`; + + if (mode === 'edit') { + if (!field) { + const message = i18n.translate('kbn.management.editIndexPattern.scripted.noFieldLabel', { + defaultMessage: + "'{indexPatternTitle}' index pattern doesn't have a scripted field called '{fieldName}'", + values: { indexPatternTitle: indexPattern.title, fieldName }, + }); + services.notifications.toasts.addWarning(message); + history.push(url); + } + } + + const docFieldName = field?.name || newFieldPlaceholder; + + services.docTitle.change([docFieldName, indexPattern.title]); + + const redirectAway = () => { + history.push(`${url}?_a=(tab:${field?.scripted ? TAB_SCRIPTED_FIELDS : TAB_INDEXED_FIELDS})`); + }; + + return ( + + + + + + + + + ); + } +); diff --git a/src/legacy/core_plugins/vis_type_table/public/legacy_imports.ts b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/create_edit_field/index.ts similarity index 93% rename from src/legacy/core_plugins/vis_type_table/public/legacy_imports.ts rename to src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/create_edit_field/index.ts index 1030e971d64504..473a8f5b57c825 100644 --- a/src/legacy/core_plugins/vis_type_table/public/legacy_imports.ts +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/create_edit_field/index.ts @@ -17,4 +17,4 @@ * under the License. */ -export { npSetup, npStart } from 'ui/new_platform'; +export { CreateEditField } from './create_edit_field'; diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js index 156f4d5a71e63f..1dd240764de6ef 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/edit_index_pattern.js @@ -18,15 +18,18 @@ */ import _ from 'lodash'; +import { HashRouter } from 'react-router-dom'; import { IndexHeader } from './index_header'; -import './create_edit_field'; +import { CreateEditField } from './create_edit_field'; import { docTitle } from 'ui/doc_title'; import { KbnUrlProvider } from 'ui/url'; import { IndicesEditSectionsProvider } from './edit_sections'; import { fatalError, toastNotifications } from 'ui/notify'; +import { RegistryFieldFormatEditorsProvider } from 'ui/registry/field_format_editors'; import uiRoutes from 'ui/routes'; import { uiModules } from 'ui/modules'; import template from './edit_index_pattern.html'; +import createEditFieldtemplate from './create_edit_field.html'; import { fieldWildcardMatcher } from '../../../../../../../../plugins/kibana_utils/public'; import { subscribeWithScope } from '../../../../../../../../plugins/kibana_legacy/public'; import React from 'react'; @@ -37,8 +40,12 @@ import { ScriptedFieldsTable } from './scripted_fields_table'; import { i18n } from '@kbn/i18n'; import { I18nContext } from 'ui/i18n'; import { npStart } from 'ui/new_platform'; - -import { getEditBreadcrumbs } from '../breadcrumbs'; +import { + getEditBreadcrumbs, + getEditFieldBreadcrumbs, + getCreateFieldBreadcrumbs, +} from '../breadcrumbs'; +import { TAB_INDEXED_FIELDS, TAB_SCRIPTED_FIELDS, TAB_SOURCE_FILTERS } from './constants'; import { createEditIndexPatternPageStateContainer } from './edit_index_pattern_state_container'; const REACT_SOURCE_FILTERS_DOM_ELEMENT_ID = 'reactSourceFiltersTable'; @@ -46,9 +53,7 @@ const REACT_INDEXED_FIELDS_DOM_ELEMENT_ID = 'reactIndexedFieldsTable'; const REACT_SCRIPTED_FIELDS_DOM_ELEMENT_ID = 'reactScriptedFieldsTable'; const REACT_INDEX_HEADER_DOM_ELEMENT_ID = 'reactIndexHeader'; -const TAB_INDEXED_FIELDS = 'indexedFields'; -const TAB_SCRIPTED_FIELDS = 'scriptedFields'; -const TAB_SOURCE_FILTERS = 'sourceFilters'; +const EDIT_FIELD_PATH = '/management/kibana/index_patterns/{{indexPattern.id}}/field/{{name}}'; function updateSourceFiltersTable($scope) { $scope.$$postDigest(() => { @@ -98,8 +103,8 @@ function updateScriptedFieldsTable($scope) { fieldFilter={$scope.fieldFilter} scriptedFieldLanguageFilter={$scope.scriptedFieldLanguageFilter} helpers={{ - redirectToRoute: (obj, route) => { - $scope.kbnUrl.changeToRoute(obj, route); + redirectToRoute: field => { + $scope.kbnUrl.changePath(EDIT_FIELD_PATH, field); $scope.$apply(); }, getRouteHref: (obj, route) => $scope.kbnUrl.getRouteHref(obj, route), @@ -141,8 +146,8 @@ function updateIndexedFieldsTable($scope) { fieldWildcardMatcher={$scope.fieldWildcardMatcher} indexedFieldTypeFilter={$scope.indexedFieldTypeFilter} helpers={{ - redirectToRoute: (obj, route) => { - $scope.kbnUrl.changeToRoute(obj, route); + redirectToRoute: field => { + $scope.kbnUrl.changePath(EDIT_FIELD_PATH, field); $scope.$apply(); }, getFieldInfo: $scope.getFieldInfo, @@ -435,3 +440,84 @@ uiModules renderIndexHeader($scope, config); }); + +// routes for create edit field. Will be removed after migartion all component to react. +const REACT_FIELD_EDITOR_ID = 'reactFieldEditor'; +const renderCreateEditField = ($scope, $route, getConfig, $http, fieldFormatEditors) => { + $scope.$$postDigest(() => { + const node = document.getElementById(REACT_FIELD_EDITOR_ID); + if (!node) { + return; + } + + render( + + + + + , + node + ); + }); +}; + +const destroyCreateEditField = () => { + const node = document.getElementById(REACT_FIELD_EDITOR_ID); + node && unmountComponentAtNode(node); +}; + +uiRoutes + .when('/management/kibana/index_patterns/:indexPatternId/field/:fieldName*', { + mode: 'edit', + k7Breadcrumbs: getEditFieldBreadcrumbs, + }) + .when('/management/kibana/index_patterns/:indexPatternId/create-field/', { + mode: 'create', + k7Breadcrumbs: getCreateFieldBreadcrumbs, + }) + .defaults(/management\/kibana\/index_patterns\/[^\/]+\/(field|create-field)(\/|$)/, { + template: createEditFieldtemplate, + mapBreadcrumbs($route, breadcrumbs) { + const { indexPattern } = $route.current.locals; + return breadcrumbs.map(crumb => { + if (crumb.id !== indexPattern.id) { + return crumb; + } + + return { + ...crumb, + display: indexPattern.title, + }; + }); + }, + resolve: { + indexPattern: function($route, Promise, redirectWhenMissing) { + const { indexPatterns } = npStart.plugins.data; + return Promise.resolve(indexPatterns.get($route.current.params.indexPatternId)).catch( + redirectWhenMissing('/management/kibana/index_patterns') + ); + }, + }, + controllerAs: 'fieldSettings', + controller: function FieldEditorPageController($scope, $route, $http, Private, config) { + const getConfig = (...args) => config.get(...args); + const fieldFormatEditors = Private(RegistryFieldFormatEditorsProvider); + + renderCreateEditField($scope, $route, getConfig, $http, fieldFormatEditors); + + $scope.$on('$destroy', () => { + destroyCreateEditField(); + }); + }, + }); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/index_header/index_header.tsx b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/index_header/index_header.tsx index 866d10ecb0e19d..deac85d9a32e9a 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/index_header/index_header.tsx +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/index_header/index_header.tsx @@ -30,8 +30,8 @@ import { import { IIndexPattern } from '../../../../../../../../../plugins/data/public'; interface IndexHeaderProps { - defaultIndex: string; indexPattern: IIndexPattern; + defaultIndex?: string; setDefault?: () => void; refreshFields?: () => void; deleteIndexPattern?: () => void; @@ -77,7 +77,7 @@ export function IndexHeader({ )} - +

{indexPattern.title}

diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/indexed_fields_table/__snapshots__/indexed_fields_table.test.tsx.snap b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/indexed_fields_table/__snapshots__/indexed_fields_table.test.tsx.snap index e6c81a3f67ec82..db2a032b1e4d9c 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/indexed_fields_table/__snapshots__/indexed_fields_table.test.tsx.snap +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/indexed_fields_table/__snapshots__/indexed_fields_table.test.tsx.snap @@ -18,7 +18,6 @@ exports[`IndexedFieldsTable should filter based on the query bar 1`] = ` "indexPattern": undefined, "info": Array [], "name": "Elastic", - "routes": undefined, "searchable": true, "type": "name", }, @@ -46,7 +45,6 @@ exports[`IndexedFieldsTable should filter based on the type filter 1`] = ` "indexPattern": undefined, "info": Array [], "name": "timestamp", - "routes": undefined, "type": "date", }, ] @@ -73,7 +71,6 @@ exports[`IndexedFieldsTable should render normally 1`] = ` "indexPattern": undefined, "info": Array [], "name": "Elastic", - "routes": undefined, "searchable": true, "type": "name", }, @@ -84,7 +81,6 @@ exports[`IndexedFieldsTable should render normally 1`] = ` "indexPattern": undefined, "info": Array [], "name": "timestamp", - "routes": undefined, "type": "date", }, Object { @@ -94,7 +90,6 @@ exports[`IndexedFieldsTable should render normally 1`] = ` "indexPattern": undefined, "info": Array [], "name": "conflictingField", - "routes": undefined, "type": "conflict", }, ] diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/indexed_fields_table/indexed_fields_table.test.tsx b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/indexed_fields_table/indexed_fields_table.test.tsx index 8e877c4fe8a16e..e7e7a8b89c73d1 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/indexed_fields_table/indexed_fields_table.test.tsx +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/indexed_fields_table/indexed_fields_table.test.tsx @@ -21,6 +21,7 @@ import React from 'react'; import { shallow } from 'enzyme'; import { IndexPatternField, IIndexPattern } from '../../../../../../../../../plugins/data/public'; import { IndexedFieldsTable } from './indexed_fields_table'; +import { IndexedFieldItem } from './types'; jest.mock('@elastic/eui', () => ({ EuiFlexGroup: 'eui-flex-group', @@ -37,7 +38,7 @@ jest.mock('./components/table', () => ({ })); const helpers = { - redirectToRoute: (obj: any, route: string) => {}, + redirectToRoute: (field: IndexedFieldItem) => {}, getFieldInfo: () => [], }; diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/indexed_fields_table/indexed_fields_table.tsx b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/indexed_fields_table/indexed_fields_table.tsx index 93d5ccf39b2839..650b7fa8c5b16a 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/indexed_fields_table/indexed_fields_table.tsx +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/indexed_fields_table/indexed_fields_table.tsx @@ -30,7 +30,7 @@ interface IndexedFieldsTableProps { fieldFilter?: string; indexedFieldTypeFilter?: string; helpers: { - redirectToRoute: (obj: any, route: string) => void; + redirectToRoute: (field: IndexedFieldItem) => void; getFieldInfo: (indexPattern: IIndexPattern, field: string) => string[]; }; fieldWildcardMatcher: (filters: any[]) => (val: any) => boolean; @@ -73,7 +73,6 @@ export class IndexedFieldsTable extends Component< return { ...field, displayName: field.displayName, - routes: field.routes, indexPattern: field.indexPattern, format: getFieldFormat(indexPattern, field.name), excluded: fieldWildcardMatch ? fieldWildcardMatch(field.name) : false, @@ -113,7 +112,7 @@ export class IndexedFieldsTable extends Component< this.props.helpers.redirectToRoute(field, 'edit')} + editField={field => this.props.helpers.redirectToRoute(field)} /> ); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/scripted_fields_table/scripted_fields_table.tsx b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/scripted_fields_table/scripted_fields_table.tsx index ba044296a693a9..e8dfbd6496057f 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/scripted_fields_table/scripted_fields_table.tsx +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/scripted_fields_table/scripted_fields_table.tsx @@ -155,7 +155,7 @@ export class ScriptedFieldsTable extends Component<
this.props.helpers.redirectToRoute(field, 'edit')} + editField={field => this.props.helpers.redirectToRoute(field)} deleteField={this.startDeleteField} /> diff --git a/src/legacy/core_plugins/vis_type_table/index.ts b/src/legacy/core_plugins/vis_type_table/index.ts deleted file mode 100644 index 04ca9da7de32b8..00000000000000 --- a/src/legacy/core_plugins/vis_type_table/index.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { resolve } from 'path'; -import { Legacy } from 'kibana'; - -import { LegacyPluginApi, LegacyPluginInitializer } from '../../../../src/legacy/types'; - -const tableVisPluginInitializer: LegacyPluginInitializer = ({ Plugin }: LegacyPluginApi) => - new Plugin({ - id: 'table_vis', - require: ['kibana', 'elasticsearch'], - publicDir: resolve(__dirname, 'public'), - uiExports: { - styleSheetPaths: resolve(__dirname, 'public/index.scss'), - hacks: [resolve(__dirname, 'public/legacy')], - injectDefaultVars: server => ({}), - }, - init: (server: Legacy.Server) => ({}), - config(Joi: any) { - return Joi.object({ - enabled: Joi.boolean().default(true), - }).default(); - }, - } as Legacy.PluginSpecOptions); - -// eslint-disable-next-line import/no-default-export -export default tableVisPluginInitializer; diff --git a/src/legacy/core_plugins/vis_type_table/package.json b/src/legacy/core_plugins/vis_type_table/package.json deleted file mode 100644 index 2809b0e0478365..00000000000000 --- a/src/legacy/core_plugins/vis_type_table/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "table_vis", - "version": "kibana" -} diff --git a/src/legacy/core_plugins/vis_type_table/public/agg_table/_index.scss b/src/legacy/core_plugins/vis_type_table/public/agg_table/_index.scss deleted file mode 100644 index b19d4a887a7f39..00000000000000 --- a/src/legacy/core_plugins/vis_type_table/public/agg_table/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import 'agg_table'; diff --git a/src/legacy/core_plugins/vis_type_table/public/paginated_table/_index.scss b/src/legacy/core_plugins/vis_type_table/public/paginated_table/_index.scss deleted file mode 100644 index 9473b847d3c2bd..00000000000000 --- a/src/legacy/core_plugins/vis_type_table/public/paginated_table/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import './table_cell_filter'; diff --git a/src/legacy/core_plugins/vis_type_table/public/table_vis_type.ts b/src/legacy/core_plugins/vis_type_table/public/table_vis_type.ts deleted file mode 100644 index 43816121bc23bc..00000000000000 --- a/src/legacy/core_plugins/vis_type_table/public/table_vis_type.ts +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { AggGroupNames } from '../../../../plugins/data/public'; -import { Schemas } from '../../../../plugins/vis_default_editor/public'; -import { Vis } from '../../../../plugins/visualizations/public'; -import { tableVisResponseHandler } from './table_vis_response_handler'; -// @ts-ignore -import tableVisTemplate from './table_vis.html'; -import { TableOptions } from './components/table_vis_options'; -import { TableVisualizationController } from './vis_controller'; - -export const tableVisTypeDefinition = { - type: 'table', - name: 'table', - title: i18n.translate('visTypeTable.tableVisTitle', { - defaultMessage: 'Data Table', - }), - icon: 'visTable', - description: i18n.translate('visTypeTable.tableVisDescription', { - defaultMessage: 'Display values in a table', - }), - visualization: TableVisualizationController, - visConfig: { - defaults: { - perPage: 10, - showPartialRows: false, - showMetricsAtAllLevels: false, - sort: { - columnIndex: null, - direction: null, - }, - showTotal: false, - totalFunc: 'sum', - percentageCol: '', - }, - template: tableVisTemplate, - }, - editorConfig: { - optionsTemplate: TableOptions, - schemas: new Schemas([ - { - group: AggGroupNames.Metrics, - name: 'metric', - title: i18n.translate('visTypeTable.tableVisEditorConfig.schemas.metricTitle', { - defaultMessage: 'Metric', - }), - aggFilter: ['!geo_centroid', '!geo_bounds'], - aggSettings: { - top_hits: { - allowStrings: true, - }, - }, - min: 1, - defaults: [{ type: 'count', schema: 'metric' }], - }, - { - group: AggGroupNames.Buckets, - name: 'bucket', - title: i18n.translate('visTypeTable.tableVisEditorConfig.schemas.bucketTitle', { - defaultMessage: 'Split rows', - }), - aggFilter: ['!filter'], - }, - { - group: AggGroupNames.Buckets, - name: 'split', - title: i18n.translate('visTypeTable.tableVisEditorConfig.schemas.splitTitle', { - defaultMessage: 'Split table', - }), - min: 0, - max: 1, - aggFilter: ['!filter'], - }, - ]), - }, - responseHandler: tableVisResponseHandler, - hierarchicalData: (vis: Vis) => { - return Boolean(vis.params.showPartialRows || vis.params.showMetricsAtAllLevels); - }, -}; diff --git a/src/legacy/core_plugins/vis_type_table/public/vis_controller.ts b/src/legacy/core_plugins/vis_type_table/public/vis_controller.ts deleted file mode 100644 index 5bb730d2f9b105..00000000000000 --- a/src/legacy/core_plugins/vis_type_table/public/vis_controller.ts +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import angular, { IModule, auto, IRootScopeService, IScope, ICompileService } from 'angular'; -import $ from 'jquery'; - -import { VisParams, ExprVis } from '../../../../plugins/visualizations/public'; -import { npStart } from './legacy_imports'; -import { getAngularModule } from './get_inner_angular'; -import { initTableVisLegacyModule } from './table_vis_legacy_module'; - -const innerAngularName = 'kibana/table_vis'; - -export class TableVisualizationController { - private tableVisModule: IModule | undefined; - private injector: auto.IInjectorService | undefined; - el: JQuery; - vis: ExprVis; - $rootScope: IRootScopeService | null = null; - $scope: (IScope & { [key: string]: any }) | undefined; - $compile: ICompileService | undefined; - - constructor(domeElement: Element, vis: ExprVis) { - this.el = $(domeElement); - this.vis = vis; - } - - getInjector() { - if (!this.injector) { - const mountpoint = document.createElement('div'); - mountpoint.setAttribute('style', 'height: 100%; width: 100%;'); - this.injector = angular.bootstrap(mountpoint, [innerAngularName]); - this.el.append(mountpoint); - } - - return this.injector; - } - - initLocalAngular() { - if (!this.tableVisModule) { - this.tableVisModule = getAngularModule(innerAngularName, npStart.core); - initTableVisLegacyModule(this.tableVisModule); - } - } - - async render(esResponse: object, visParams: VisParams) { - this.initLocalAngular(); - - return new Promise(async (resolve, reject) => { - if (!this.$rootScope) { - const $injector = this.getInjector(); - this.$rootScope = $injector.get('$rootScope'); - this.$compile = $injector.get('$compile'); - } - const updateScope = () => { - if (!this.$scope) { - return; - } - this.$scope.vis = this.vis; - this.$scope.visState = { params: visParams }; - this.$scope.esResponse = esResponse; - - this.$scope.visParams = visParams; - this.$scope.renderComplete = resolve; - this.$scope.renderFailed = reject; - this.$scope.resize = Date.now(); - this.$scope.$apply(); - }; - - if (!this.$scope && this.$compile) { - this.$scope = this.$rootScope.$new(); - this.$scope.uiState = this.vis.getUiState(); - updateScope(); - this.el.find('div').append(this.$compile(this.vis.type!.visConfig.template)(this.$scope)); - this.$scope.$apply(); - } else { - updateScope(); - } - }); - } - - destroy() { - if (this.$rootScope) { - this.$rootScope.$destroy(); - this.$rootScope = null; - } - } -} diff --git a/src/legacy/ui/public/field_editor/field_editor.js b/src/legacy/ui/public/field_editor/field_editor.js index 43461c4c689be6..e90cb110ac3048 100644 --- a/src/legacy/ui/public/field_editor/field_editor.js +++ b/src/legacy/ui/public/field_editor/field_editor.js @@ -66,7 +66,7 @@ import { ScriptingHelpFlyout } from './components/scripting_help'; import { FieldFormatEditor } from './components/field_format_editor'; import { FIELD_TYPES_BY_LANG, DEFAULT_FIELD_TYPES } from './constants'; -import { copyField, executeScript, isScriptValid } from './lib'; +import { executeScript, isScriptValid } from './lib'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -100,7 +100,6 @@ export class FieldEditor extends PureComponent { indexPattern: PropTypes.object.isRequired, field: PropTypes.object.isRequired, helpers: PropTypes.shape({ - Field: PropTypes.func.isRequired, getConfig: PropTypes.func.isRequired, $http: PropTypes.func.isRequired, fieldFormatEditors: PropTypes.object.isRequired, @@ -111,11 +110,7 @@ export class FieldEditor extends PureComponent { constructor(props) { super(props); - const { - field, - indexPattern, - helpers: { Field }, - } = props; + const { field, indexPattern } = props; this.state = { isReady: false, @@ -125,7 +120,7 @@ export class FieldEditor extends PureComponent { fieldTypes: [], fieldTypeFormats: [], existingFieldNames: indexPattern.fields.map(f => f.name), - field: copyField(field, indexPattern, Field), + field: { ...field, format: field.format }, fieldFormatId: undefined, fieldFormatParams: {}, showScriptingHelp: false, @@ -730,7 +725,7 @@ export class FieldEditor extends PureComponent { }; saveField = async () => { - const field = this.state.field.toActualField(); + const field = this.state.field; const { indexPattern } = this.props; const { fieldFormatId } = this.state; diff --git a/src/legacy/ui/public/field_editor/lib/__tests__/copy_field.test.js b/src/legacy/ui/public/field_editor/lib/__tests__/copy_field.test.js deleted file mode 100644 index 2cee45742ab81d..00000000000000 --- a/src/legacy/ui/public/field_editor/lib/__tests__/copy_field.test.js +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { copyField } from '../copy_field'; - -const field = { - name: 'test_field', - scripted: true, - type: 'number', - lang: 'painless', -}; - -describe('copyField', () => { - it('should copy a field', () => { - const copiedField = copyField(field, {}, {}); - copiedField.name = 'test_name_change'; - - // Check that copied field has `toActualField()` method - expect(typeof copiedField.toActualField).toEqual('function'); - - // Check that we did not modify the original field object when - // modifying copied field - expect(field.toActualField).toEqual(undefined); - expect(field.name).toEqual('test_field'); - - expect(copiedField).not.toEqual(field); - expect(copiedField.name).toEqual('test_name_change'); - expect(copiedField.scripted).toEqual(field.scripted); - expect(copiedField.type).toEqual(field.type); - expect(copiedField.lang).toEqual(field.lang); - }); -}); diff --git a/src/legacy/ui/public/field_editor/lib/copy_field.js b/src/legacy/ui/public/field_editor/lib/copy_field.js deleted file mode 100644 index bfc1cb8480d5d4..00000000000000 --- a/src/legacy/ui/public/field_editor/lib/copy_field.js +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { has } from 'lodash'; - -/** - * Fully clones a Field object, so that modifications can be performed on - * the copy without affecting original field. Field objects contain - * enumerable and non-eumerable properties that may or may not be writable. - * The function copies all properties as property descriptors into - * `newFieldProps`, overrides getter and setter, and returns a new object - * created from that. - * - * @param {object} field - Field object to copy - * @param {object} indexPattern - index pattern object the field belongs to - * @param {object} Field - Field object type - * @return {object} the cloned object - */ -export const copyField = (field, indexPattern, Field) => { - const changes = {}; - const newFieldProps = { - // When we are ready to save the copied field back into the index pattern, - // we use `toActualField()` to retrieve an actual `Field` type object, using - // its original properties with our "changes" applied. - toActualField: { - value: () => { - return new Field(indexPattern, { - ...field.$$spec, - ...changes, - }); - }, - }, - }; - - // Index pattern `Field` objects are created with custom property - // descriptors using `ObjDefine`. - // - // Each property of a `Field` type object could be enumerable/non-enumerable, - // writable/not writable, configurable/not configurable, and have custom - // getter and setter. We can't use the original `field` object directly for - // creating a new field or editing a new field, since we need all the - // properties to be editable. - // - // A normal copy of `field` (i.e. `const newField = { ...field }`) will only - // copy enumerable properties and copy each property's descriptors (not - // writable, etc). - // - // So we copy `field`'s **property descriptors** into `newFieldProps` - // and modify them so that they are "writable" with a getter/setter that - // stores and retrieves changes into/from another object (`changes`). - Object.getOwnPropertyNames(field).forEach(function(prop) { - const desc = Object.getOwnPropertyDescriptor(field, prop); - - newFieldProps[prop] = { - enumerable: desc.enumerable, - get: function() { - return has(changes, prop) ? changes[prop] : field[prop]; - }, - set: function(v) { - changes[prop] = v; - }, - }; - }); - - return Object.create(null, newFieldProps); -}; diff --git a/src/legacy/ui/public/field_editor/lib/index.js b/src/legacy/ui/public/field_editor/lib/index.js index c74bb0cc2ef8ab..c9dd9d03b74f7b 100644 --- a/src/legacy/ui/public/field_editor/lib/index.js +++ b/src/legacy/ui/public/field_editor/lib/index.js @@ -17,5 +17,4 @@ * under the License. */ -export { copyField } from './copy_field'; export { executeScript, isScriptValid } from './validate_script'; diff --git a/src/legacy/ui/public/i18n/index.tsx b/src/legacy/ui/public/i18n/index.tsx index 4d0f5d3a5bd567..c918554563fcb7 100644 --- a/src/legacy/ui/public/i18n/index.tsx +++ b/src/legacy/ui/public/i18n/index.tsx @@ -44,7 +44,7 @@ export function wrapInI18nContext

(ComponentToWrap: React.ComponentType

) { } uiModules - .get('i18n') + .get('i18n', ['ngSanitize']) .provider('i18n', I18nProvider) .filter('i18n', i18nFilter) .directive('i18nId', i18nDirective); diff --git a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js index f577a29ce90b91..f14f26613ef019 100644 --- a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js +++ b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js @@ -242,6 +242,7 @@ export const npSetup = { }, kibanaLegacy: { registerLegacyApp: () => {}, + registerLegacyAppAlias: () => {}, forwardApp: () => {}, config: { defaultAppId: 'home', @@ -362,6 +363,7 @@ export const npStart = { kibanaLegacy: { getApps: () => [], getForwards: () => [], + getLegacyAppAliases: () => [], config: { defaultAppId: 'home', }, diff --git a/src/plugins/dashboard/public/application/actions/clone_panel_action.test.tsx b/src/plugins/dashboard/public/application/actions/clone_panel_action.test.tsx new file mode 100644 index 00000000000000..17943333d25b04 --- /dev/null +++ b/src/plugins/dashboard/public/application/actions/clone_panel_action.test.tsx @@ -0,0 +1,155 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { isErrorEmbeddable, IContainer } from '../../embeddable_plugin'; +import { DashboardContainer, DashboardPanelState } from '../embeddable'; +import { getSampleDashboardInput, getSampleDashboardPanel } from '../test_helpers'; +import { + CONTACT_CARD_EMBEDDABLE, + ContactCardEmbeddableFactory, + ContactCardEmbeddable, + ContactCardEmbeddableInput, + ContactCardEmbeddableOutput, +} from '../../embeddable_plugin_test_samples'; +import { coreMock } from '../../../../../core/public/mocks'; +import { CoreStart } from 'kibana/public'; +import { ClonePanelAction } from '.'; + +// eslint-disable-next-line +import { embeddablePluginMock } from 'src/plugins/embeddable/public/mocks'; + +const { setup, doStart } = embeddablePluginMock.createInstance(); +setup.registerEmbeddableFactory( + CONTACT_CARD_EMBEDDABLE, + new ContactCardEmbeddableFactory((() => null) as any, {} as any) +); +const start = doStart(); + +let container: DashboardContainer; +let embeddable: ContactCardEmbeddable; +let coreStart: CoreStart; +beforeEach(async () => { + coreStart = coreMock.createStart(); + coreStart.savedObjects.client = { + ...coreStart.savedObjects.client, + get: jest.fn().mockImplementation(() => ({ attributes: { title: 'Holy moly' } })), + find: jest.fn().mockImplementation(() => ({ total: 15 })), + create: jest.fn().mockImplementation(() => ({ id: 'brandNewSavedObject' })), + }; + + const options = { + ExitFullScreenButton: () => null, + SavedObjectFinder: () => null, + application: {} as any, + embeddable: start, + inspector: {} as any, + notifications: {} as any, + overlays: coreStart.overlays, + savedObjectMetaData: {} as any, + uiActions: {} as any, + }; + const input = getSampleDashboardInput({ + panels: { + '123': getSampleDashboardPanel({ + explicitInput: { firstName: 'Kibanana', id: '123' }, + type: CONTACT_CARD_EMBEDDABLE, + }), + }, + }); + container = new DashboardContainer(input, options); + + const contactCardEmbeddable = await container.addNewEmbeddable< + ContactCardEmbeddableInput, + ContactCardEmbeddableOutput, + ContactCardEmbeddable + >(CONTACT_CARD_EMBEDDABLE, { + firstName: 'Kibana', + }); + + if (isErrorEmbeddable(contactCardEmbeddable)) { + throw new Error('Failed to create embeddable'); + } else { + embeddable = contactCardEmbeddable; + } +}); + +test('Clone adds a new embeddable', async () => { + const dashboard = embeddable.getRoot() as IContainer; + const originalPanelCount = Object.keys(dashboard.getInput().panels).length; + const originalPanelKeySet = new Set(Object.keys(dashboard.getInput().panels)); + const action = new ClonePanelAction(coreStart); + await action.execute({ embeddable }); + expect(Object.keys(container.getInput().panels).length).toEqual(originalPanelCount + 1); + const newPanelId = Object.keys(container.getInput().panels).find( + key => !originalPanelKeySet.has(key) + ); + expect(newPanelId).toBeDefined(); + const newPanel = container.getInput().panels[newPanelId!]; + expect(newPanel.type).toEqual(embeddable.type); +}); + +test('Clones an embeddable without a saved object ID', async () => { + const dashboard = embeddable.getRoot() as IContainer; + const panel = dashboard.getInput().panels[embeddable.id] as DashboardPanelState; + const action = new ClonePanelAction(coreStart); + // @ts-ignore + const newPanel = await action.cloneEmbeddable(panel, embeddable.type); + expect(newPanel.type).toEqual(embeddable.type); +}); + +test('Clones an embeddable with a saved object ID', async () => { + const dashboard = embeddable.getRoot() as IContainer; + const panel = dashboard.getInput().panels[embeddable.id] as DashboardPanelState; + panel.explicitInput.savedObjectId = 'holySavedObjectBatman'; + const action = new ClonePanelAction(coreStart); + // @ts-ignore + const newPanel = await action.cloneEmbeddable(panel, embeddable.type); + expect(coreStart.savedObjects.client.get).toHaveBeenCalledTimes(1); + expect(coreStart.savedObjects.client.find).toHaveBeenCalledTimes(1); + expect(coreStart.savedObjects.client.create).toHaveBeenCalledTimes(1); + expect(newPanel.type).toEqual(embeddable.type); +}); + +test('Gets a unique title ', async () => { + coreStart.savedObjects.client.find = jest.fn().mockImplementation(({ search }) => { + if (search === '"testFirstTitle"') return { total: 1 }; + else if (search === '"testSecondTitle"') return { total: 41 }; + else if (search === '"testThirdTitle"') return { total: 90 }; + }); + const action = new ClonePanelAction(coreStart); + // @ts-ignore + expect(await action.getUniqueTitle('testFirstTitle', embeddable.type)).toEqual( + 'testFirstTitle (copy)' + ); + // @ts-ignore + expect(await action.getUniqueTitle('testSecondTitle (copy 39)', embeddable.type)).toEqual( + 'testSecondTitle (copy 40)' + ); + // @ts-ignore + expect(await action.getUniqueTitle('testSecondTitle (copy 20)', embeddable.type)).toEqual( + 'testSecondTitle (copy 40)' + ); + // @ts-ignore + expect(await action.getUniqueTitle('testThirdTitle', embeddable.type)).toEqual( + 'testThirdTitle (copy 89)' + ); + // @ts-ignore + expect(await action.getUniqueTitle('testThirdTitle (copy 10000)', embeddable.type)).toEqual( + 'testThirdTitle (copy 89)' + ); +}); diff --git a/src/plugins/dashboard/public/application/actions/clone_panel_action.tsx b/src/plugins/dashboard/public/application/actions/clone_panel_action.tsx new file mode 100644 index 00000000000000..4d15e7e899fa89 --- /dev/null +++ b/src/plugins/dashboard/public/application/actions/clone_panel_action.tsx @@ -0,0 +1,158 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { CoreStart } from 'src/core/public'; +import uuid from 'uuid'; +import { ActionByType, IncompatibleActionError } from '../../ui_actions_plugin'; +import { ViewMode, PanelState, IEmbeddable } from '../../embeddable_plugin'; +import { SavedObject } from '../../../../saved_objects/public'; +import { PanelNotFoundError, EmbeddableInput } from '../../../../embeddable/public'; +import { + placePanelBeside, + IPanelPlacementBesideArgs, +} from '../embeddable/panel/dashboard_panel_placement'; +import { DashboardPanelState, DASHBOARD_CONTAINER_TYPE, DashboardContainer } from '..'; + +export const ACTION_CLONE_PANEL = 'clonePanel'; + +export interface ClonePanelActionContext { + embeddable: IEmbeddable; +} + +export class ClonePanelAction implements ActionByType { + public readonly type = ACTION_CLONE_PANEL; + public readonly id = ACTION_CLONE_PANEL; + public order = 11; + + constructor(private core: CoreStart) {} + + public getDisplayName({ embeddable }: ClonePanelActionContext) { + if (!embeddable.getRoot() || !embeddable.getRoot().isContainer) { + throw new IncompatibleActionError(); + } + return i18n.translate('dashboard.panel.clonePanel', { + defaultMessage: 'Clone panel', + }); + } + + public getIconType({ embeddable }: ClonePanelActionContext) { + if (!embeddable.getRoot() || !embeddable.getRoot().isContainer) { + throw new IncompatibleActionError(); + } + return 'copy'; + } + + public async isCompatible({ embeddable }: ClonePanelActionContext) { + return Boolean( + embeddable.getInput()?.viewMode !== ViewMode.VIEW && + embeddable.getRoot() && + embeddable.getRoot().isContainer && + embeddable.getRoot().type === DASHBOARD_CONTAINER_TYPE + ); + } + + public async execute({ embeddable }: ClonePanelActionContext) { + if (!embeddable.getRoot() || !embeddable.getRoot().isContainer) { + throw new IncompatibleActionError(); + } + + const dashboard = embeddable.getRoot() as DashboardContainer; + const panelToClone = dashboard.getInput().panels[embeddable.id] as DashboardPanelState; + if (!panelToClone) { + throw new PanelNotFoundError(); + } + + dashboard.showPlaceholderUntil( + this.cloneEmbeddable(panelToClone, embeddable.type), + placePanelBeside, + { + width: panelToClone.gridData.w, + height: panelToClone.gridData.h, + currentPanels: dashboard.getInput().panels, + placeBesideId: panelToClone.explicitInput.id, + } as IPanelPlacementBesideArgs + ); + } + + private async getUniqueTitle(rawTitle: string, embeddableType: string): Promise { + const clonedTag = i18n.translate('dashboard.panel.title.clonedTag', { + defaultMessage: 'copy', + }); + const cloneRegex = new RegExp(`\\(${clonedTag}\\)`, 'g'); + const cloneNumberRegex = new RegExp(`\\(${clonedTag} [0-9]+\\)`, 'g'); + const baseTitle = rawTitle + .replace(cloneNumberRegex, '') + .replace(cloneRegex, '') + .trim(); + + const similarSavedObjects = await this.core.savedObjects.client.find({ + type: embeddableType, + perPage: 0, + fields: ['title'], + searchFields: ['title'], + search: `"${baseTitle}"`, + }); + const similarBaseTitlesCount: number = similarSavedObjects.total - 1; + + return similarBaseTitlesCount <= 0 + ? baseTitle + ` (${clonedTag})` + : baseTitle + ` (${clonedTag} ${similarBaseTitlesCount})`; + } + + private async cloneEmbeddable( + panelToClone: DashboardPanelState, + embeddableType: string + ): Promise> { + const panelState: PanelState = { + type: embeddableType, + explicitInput: { + ...panelToClone.explicitInput, + id: uuid.v4(), + }, + }; + let newTitle: string = ''; + if (panelToClone.explicitInput.savedObjectId) { + // Fetch existing saved object + const savedObjectToClone = await this.core.savedObjects.client.get( + embeddableType, + panelToClone.explicitInput.savedObjectId + ); + + // Clone the saved object + newTitle = await this.getUniqueTitle(savedObjectToClone.attributes.title, embeddableType); + const clonedSavedObject = await this.core.savedObjects.client.create( + embeddableType, + { + ..._.cloneDeep(savedObjectToClone.attributes), + title: newTitle, + }, + { references: _.cloneDeep(savedObjectToClone.references) } + ); + panelState.explicitInput.savedObjectId = clonedSavedObject.id; + } + this.core.notifications.toasts.addSuccess({ + title: i18n.translate('dashboard.panel.clonedToast', { + defaultMessage: 'Cloned panel', + }), + 'data-test-subj': 'addObjectToContainerSuccess', + }); + return panelState; + } +} diff --git a/src/plugins/dashboard/public/application/actions/index.ts b/src/plugins/dashboard/public/application/actions/index.ts index 23c26dbd280f8e..d7a84fb79f6af3 100644 --- a/src/plugins/dashboard/public/application/actions/index.ts +++ b/src/plugins/dashboard/public/application/actions/index.ts @@ -27,3 +27,8 @@ export { ReplacePanelActionContext, ACTION_REPLACE_PANEL, } from './replace_panel_action'; +export { + ClonePanelAction, + ClonePanelActionContext, + ACTION_CLONE_PANEL, +} from './clone_panel_action'; diff --git a/src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx b/src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx index 50089f1f061f4e..8346fd900caef8 100644 --- a/src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx +++ b/src/plugins/dashboard/public/application/embeddable/dashboard_container.tsx @@ -23,6 +23,7 @@ import { I18nProvider } from '@kbn/i18n/react'; import { RefreshInterval, TimeRange, Query, Filter } from 'src/plugins/data/public'; import { CoreStart } from 'src/core/public'; import { Start as InspectorStartContract } from 'src/plugins/inspector/public'; +import uuid from 'uuid'; import { UiActionsStart } from '../../ui_actions_plugin'; import { Container, @@ -32,6 +33,7 @@ import { EmbeddableFactory, IEmbeddable, EmbeddableStart, + PanelState, } from '../../embeddable_plugin'; import { DASHBOARD_CONTAINER_TYPE } from './dashboard_constants'; import { createPanelState } from './panel'; @@ -42,6 +44,8 @@ import { KibanaReactContext, KibanaReactContextValue, } from '../../../../kibana_react/public'; +import { PLACEHOLDER_EMBEDDABLE } from './placeholder'; +import { PanelPlacementMethod, IPanelPlacementArgs } from './panel/dashboard_panel_placement'; export interface DashboardContainerInput extends ContainerInput { viewMode: ViewMode; @@ -120,7 +124,61 @@ export class DashboardContainer extends Container = {} ): DashboardPanelState { const panelState = super.createNewPanelState(factory, partial); - return createPanelState(panelState, Object.values(this.input.panels)); + return createPanelState(panelState, this.input.panels); + } + + public showPlaceholderUntil( + newStateComplete: Promise>, + placementMethod?: PanelPlacementMethod, + placementArgs?: TPlacementMethodArgs + ): void { + const originalPanelState = { + type: PLACEHOLDER_EMBEDDABLE, + explicitInput: { + id: uuid.v4(), + disabledActions: [ + 'ACTION_CUSTOMIZE_PANEL', + 'CUSTOM_TIME_RANGE', + 'clonePanel', + 'replacePanel', + 'togglePanel', + ], + }, + } as PanelState; + const placeholderPanelState = createPanelState( + originalPanelState, + this.input.panels, + placementMethod, + placementArgs + ); + this.updateInput({ + panels: { + ...this.input.panels, + [placeholderPanelState.explicitInput.id]: placeholderPanelState, + }, + }); + newStateComplete.then((newPanelState: Partial) => { + const finalPanels = { ...this.input.panels }; + delete finalPanels[placeholderPanelState.explicitInput.id]; + const newPanelId = newPanelState.explicitInput?.id + ? newPanelState.explicitInput.id + : uuid.v4(); + finalPanels[newPanelId] = { + ...placeholderPanelState, + ...newPanelState, + gridData: { + ...placeholderPanelState.gridData, + i: newPanelId, + }, + explicitInput: { + ...newPanelState.explicitInput, + id: newPanelId, + }, + }; + this.updateInput({ + panels: finalPanels, + }); + }); } public render(dom: HTMLElement) { diff --git a/src/plugins/dashboard/public/application/embeddable/panel/create_panel_state.test.ts b/src/plugins/dashboard/public/application/embeddable/panel/create_panel_state.test.ts index 409cae8b49a531..7c11ac8a5031bf 100644 --- a/src/plugins/dashboard/public/application/embeddable/panel/create_panel_state.test.ts +++ b/src/plugins/dashboard/public/application/embeddable/panel/create_panel_state.test.ts @@ -26,7 +26,7 @@ import { CONTACT_CARD_EMBEDDABLE } from '../../../embeddable_plugin_test_samples interface TestInput extends EmbeddableInput { test: string; } -const panels: DashboardPanelState[] = []; +const panels: { [key: string]: DashboardPanelState } = {}; test('createPanelState adds a new panel state in 0,0 position', () => { const panelState = createPanelState( @@ -34,7 +34,7 @@ test('createPanelState adds a new panel state in 0,0 position', () => { type: CONTACT_CARD_EMBEDDABLE, explicitInput: { test: 'hi', id: '123' }, }, - [] + panels ); expect(panelState.explicitInput.test).toBe('hi'); expect(panelState.type).toBe(CONTACT_CARD_EMBEDDABLE); @@ -44,7 +44,7 @@ test('createPanelState adds a new panel state in 0,0 position', () => { expect(panelState.gridData.h).toBe(DEFAULT_PANEL_HEIGHT); expect(panelState.gridData.w).toBe(DEFAULT_PANEL_WIDTH); - panels.push(panelState); + panels[panelState.explicitInput.id] = panelState; }); test('createPanelState adds a second new panel state', () => { @@ -58,7 +58,7 @@ test('createPanelState adds a second new panel state', () => { expect(panelState.gridData.h).toBe(DEFAULT_PANEL_HEIGHT); expect(panelState.gridData.w).toBe(DEFAULT_PANEL_WIDTH); - panels.push(panelState); + panels[panelState.explicitInput.id] = panelState; }); test('createPanelState adds a third new panel state', () => { @@ -74,17 +74,17 @@ test('createPanelState adds a third new panel state', () => { expect(panelState.gridData.h).toBe(DEFAULT_PANEL_HEIGHT); expect(panelState.gridData.w).toBe(DEFAULT_PANEL_WIDTH); - panels.push(panelState); + panels[panelState.explicitInput.id] = panelState; }); test('createPanelState adds a new panel state in the top most position', () => { - const panelsWithEmptySpace = panels.filter(panel => panel.gridData.x === 0); + delete panels['456']; const panelState = createPanelState( { type: CONTACT_CARD_EMBEDDABLE, explicitInput: { test: 'bye', id: '987' }, }, - panelsWithEmptySpace + panels ); expect(panelState.gridData.x).toBe(DEFAULT_PANEL_WIDTH); expect(panelState.gridData.y).toBe(0); diff --git a/src/plugins/dashboard/public/application/embeddable/panel/create_panel_state.ts b/src/plugins/dashboard/public/application/embeddable/panel/create_panel_state.ts index f3a48368fe1b3d..79116a57869d35 100644 --- a/src/plugins/dashboard/public/application/embeddable/panel/create_panel_state.ts +++ b/src/plugins/dashboard/public/application/embeddable/panel/create_panel_state.ts @@ -19,98 +19,45 @@ import _ from 'lodash'; import { PanelState, EmbeddableInput } from '../../../embeddable_plugin'; -import { - DASHBOARD_GRID_COLUMN_COUNT, - DEFAULT_PANEL_HEIGHT, - DEFAULT_PANEL_WIDTH, -} from '../dashboard_constants'; +import { DEFAULT_PANEL_HEIGHT, DEFAULT_PANEL_WIDTH } from '../dashboard_constants'; import { DashboardPanelState } from '../types'; - -// Look for the smallest y and x value where the default panel will fit. -function findTopLeftMostOpenSpace( - width: number, - height: number, - currentPanels: DashboardPanelState[] -) { - let maxY = -1; - - currentPanels.forEach(panel => { - maxY = Math.max(panel.gridData.y + panel.gridData.h, maxY); - }); - - // Handle case of empty grid. - if (maxY < 0) { - return { x: 0, y: 0 }; - } - - const grid = new Array(maxY); - for (let y = 0; y < maxY; y++) { - grid[y] = new Array(DASHBOARD_GRID_COLUMN_COUNT).fill(0); - } - - currentPanels.forEach(panel => { - for (let x = panel.gridData.x; x < panel.gridData.x + panel.gridData.w; x++) { - for (let y = panel.gridData.y; y < panel.gridData.y + panel.gridData.h; y++) { - const row = grid[y]; - if (row === undefined) { - throw new Error( - `Attempted to access a row that doesn't exist at ${y} for panel ${JSON.stringify( - panel - )}` - ); - } - grid[y][x] = 1; - } - } - }); - - for (let y = 0; y < maxY; y++) { - for (let x = 0; x < DASHBOARD_GRID_COLUMN_COUNT; x++) { - if (grid[y][x] === 1) { - // Space is filled - continue; - } else { - for (let h = y; h < Math.min(y + height, maxY); h++) { - for (let w = x; w < Math.min(x + width, DASHBOARD_GRID_COLUMN_COUNT); w++) { - const spaceIsEmpty = grid[h][w] === 0; - const fitsPanelWidth = w === x + width - 1; - // If the panel is taller than any other panel in the current grid, it can still fit in the space, hence - // we check the minimum of maxY and the panel height. - const fitsPanelHeight = h === Math.min(y + height - 1, maxY - 1); - - if (spaceIsEmpty && fitsPanelWidth && fitsPanelHeight) { - // Found space - return { x, y }; - } else if (grid[h][w] === 1) { - // x, y spot doesn't work, break. - break; - } - } - } - } - } - } - return { x: 0, y: maxY }; -} +import { + IPanelPlacementArgs, + findTopLeftMostOpenSpace, + PanelPlacementMethod, +} from './dashboard_panel_placement'; /** * Creates and initializes a basic panel state. */ -export function createPanelState( +export function createPanelState< + TEmbeddableInput extends EmbeddableInput, + TPlacementMethodArgs extends IPanelPlacementArgs = IPanelPlacementArgs +>( panelState: PanelState, - currentPanels: DashboardPanelState[] + currentPanels: { [key: string]: DashboardPanelState }, + placementMethod?: PanelPlacementMethod, + placementArgs?: TPlacementMethodArgs ): DashboardPanelState { - const { x, y } = findTopLeftMostOpenSpace( - DEFAULT_PANEL_WIDTH, - DEFAULT_PANEL_HEIGHT, - currentPanels - ); + const defaultPlacementArgs = { + width: DEFAULT_PANEL_WIDTH, + height: DEFAULT_PANEL_HEIGHT, + currentPanels, + }; + const finalPlacementArgs = placementArgs + ? { + ...defaultPlacementArgs, + ...placementArgs, + } + : defaultPlacementArgs; + + const gridDataLocation = placementMethod + ? placementMethod(finalPlacementArgs as TPlacementMethodArgs) + : findTopLeftMostOpenSpace(defaultPlacementArgs); + return { gridData: { - w: DEFAULT_PANEL_WIDTH, - h: DEFAULT_PANEL_HEIGHT, - x, - y, + ...gridDataLocation, i: panelState.explicitInput.id, }, ...panelState, diff --git a/src/plugins/dashboard/public/application/embeddable/panel/dashboard_panel_placement.ts b/src/plugins/dashboard/public/application/embeddable/panel/dashboard_panel_placement.ts new file mode 100644 index 00000000000000..70a6c83418587d --- /dev/null +++ b/src/plugins/dashboard/public/application/embeddable/panel/dashboard_panel_placement.ts @@ -0,0 +1,167 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { PanelNotFoundError } from '../../../embeddable_plugin'; +import { DashboardPanelState, GridData, DASHBOARD_GRID_COLUMN_COUNT } from '..'; + +export type PanelPlacementMethod = ( + args: PlacementArgs +) => Omit; + +export interface IPanelPlacementArgs { + width: number; + height: number; + currentPanels: { [key: string]: DashboardPanelState }; +} + +export interface IPanelPlacementBesideArgs extends IPanelPlacementArgs { + placeBesideId: string; +} + +// Look for the smallest y and x value where the default panel will fit. +export function findTopLeftMostOpenSpace({ + width, + height, + currentPanels, +}: IPanelPlacementArgs): Omit { + let maxY = -1; + + const currentPanelsArray = Object.values(currentPanels); + currentPanelsArray.forEach(panel => { + maxY = Math.max(panel.gridData.y + panel.gridData.h, maxY); + }); + + // Handle case of empty grid. + if (maxY < 0) { + return { x: 0, y: 0, w: width, h: height }; + } + + const grid = new Array(maxY); + for (let y = 0; y < maxY; y++) { + grid[y] = new Array(DASHBOARD_GRID_COLUMN_COUNT).fill(0); + } + + currentPanelsArray.forEach(panel => { + for (let x = panel.gridData.x; x < panel.gridData.x + panel.gridData.w; x++) { + for (let y = panel.gridData.y; y < panel.gridData.y + panel.gridData.h; y++) { + const row = grid[y]; + if (row === undefined) { + throw new Error( + `Attempted to access a row that doesn't exist at ${y} for panel ${JSON.stringify( + panel + )}` + ); + } + grid[y][x] = 1; + } + } + }); + + for (let y = 0; y < maxY; y++) { + for (let x = 0; x < DASHBOARD_GRID_COLUMN_COUNT; x++) { + if (grid[y][x] === 1) { + // Space is filled + continue; + } else { + for (let h = y; h < Math.min(y + height, maxY); h++) { + for (let w = x; w < Math.min(x + width, DASHBOARD_GRID_COLUMN_COUNT); w++) { + const spaceIsEmpty = grid[h][w] === 0; + const fitsPanelWidth = w === x + width - 1; + // If the panel is taller than any other panel in the current grid, it can still fit in the space, hence + // we check the minimum of maxY and the panel height. + const fitsPanelHeight = h === Math.min(y + height - 1, maxY - 1); + + if (spaceIsEmpty && fitsPanelWidth && fitsPanelHeight) { + // Found space + return { x, y, w: width, h: height }; + } else if (grid[h][w] === 1) { + // x, y spot doesn't work, break. + break; + } + } + } + } + } + } + return { x: 0, y: maxY, w: width, h: height }; +} + +interface IplacementDirection { + grid: Omit; + fits: boolean; +} + +export function placePanelBeside({ + width, + height, + currentPanels, + placeBesideId, +}: IPanelPlacementBesideArgs): Omit { + // const clonedPanels = _.cloneDeep(currentPanels); + if (!placeBesideId) { + throw new Error('Place beside method called without placeBesideId'); + } + const panelToPlaceBeside = currentPanels[placeBesideId]; + if (!panelToPlaceBeside) { + throw new PanelNotFoundError(); + } + const beside = panelToPlaceBeside.gridData; + const otherPanels: GridData[] = []; + _.forOwn(currentPanels, (panel: DashboardPanelState, key: string | undefined) => { + otherPanels.push(panel.gridData); + }); + + const possiblePlacementDirections: IplacementDirection[] = [ + { grid: { x: beside.x + beside.w, y: beside.y, w: width, h: height }, fits: true }, // right + { grid: { x: beside.x - width, y: beside.y, w: width, h: height }, fits: true }, // left + { grid: { x: beside.x, y: beside.y + beside.h, w: width, h: height }, fits: true }, // bottom + ]; + + for (const direction of possiblePlacementDirections) { + if ( + direction.grid.x >= 0 && + direction.grid.x + direction.grid.w <= DASHBOARD_GRID_COLUMN_COUNT && + direction.grid.y >= 0 + ) { + const intersection = otherPanels.some((currentPanelGrid: GridData) => { + return ( + direction.grid.x + direction.grid.w > currentPanelGrid.x && + direction.grid.x < currentPanelGrid.x + currentPanelGrid.w && + direction.grid.y < currentPanelGrid.y + currentPanelGrid.h && + direction.grid.y + direction.grid.h > currentPanelGrid.y + ); + }); + if (!intersection) { + return direction.grid; + } + } else { + direction.fits = false; + } + } + // if we get here that means there is no blank space around the panel we are placing beside. This means it's time to mess up the dashboard's groove. Fun! + const [, , bottomPlacement] = possiblePlacementDirections; + for (const currentPanelGrid of otherPanels) { + if (bottomPlacement.grid.y <= currentPanelGrid.y) { + const movedPanel = _.cloneDeep(currentPanels[currentPanelGrid.i]); + movedPanel.gridData.y = movedPanel.gridData.y + bottomPlacement.grid.h; + currentPanels[currentPanelGrid.i] = movedPanel; + } + } + return bottomPlacement.grid; +} diff --git a/src/plugins/dashboard/public/application/embeddable/placeholder/index.ts b/src/plugins/dashboard/public/application/embeddable/placeholder/index.ts new file mode 100644 index 00000000000000..7c65d50ce3fea1 --- /dev/null +++ b/src/plugins/dashboard/public/application/embeddable/placeholder/index.ts @@ -0,0 +1,21 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export * from './placeholder_embeddable'; +export * from './placeholder_embeddable_factory'; diff --git a/src/plugins/dashboard/public/application/embeddable/placeholder/placeholder_embeddable.tsx b/src/plugins/dashboard/public/application/embeddable/placeholder/placeholder_embeddable.tsx new file mode 100644 index 00000000000000..1a5c3386bdeda0 --- /dev/null +++ b/src/plugins/dashboard/public/application/embeddable/placeholder/placeholder_embeddable.tsx @@ -0,0 +1,52 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import ReactDOM from 'react-dom'; +import { EuiLoadingChart } from '@elastic/eui'; +import classNames from 'classnames'; +import { Embeddable, EmbeddableInput, IContainer } from '../../../embeddable_plugin'; + +export const PLACEHOLDER_EMBEDDABLE = 'placeholder'; + +export class PlaceholderEmbeddable extends Embeddable { + public readonly type = PLACEHOLDER_EMBEDDABLE; + private node?: HTMLElement; + + constructor(initialInput: EmbeddableInput, parent?: IContainer) { + super(initialInput, {}, parent); + this.input = initialInput; + } + public render(node: HTMLElement) { + if (this.node) { + ReactDOM.unmountComponentAtNode(this.node); + } + this.node = node; + + const classes = classNames('embPanel', 'embPanel-isLoading'); + ReactDOM.render( +

+ +
, + node + ); + } + + public reload() {} +} diff --git a/src/plugins/dashboard/public/application/embeddable/placeholder/placeholder_embeddable_factory.ts b/src/plugins/dashboard/public/application/embeddable/placeholder/placeholder_embeddable_factory.ts new file mode 100644 index 00000000000000..30a93989649a7a --- /dev/null +++ b/src/plugins/dashboard/public/application/embeddable/placeholder/placeholder_embeddable_factory.ts @@ -0,0 +1,45 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; + +import { + EmbeddableFactoryDefinition, + EmbeddableInput, + IContainer, +} from '../../../embeddable_plugin'; +import { PlaceholderEmbeddable, PLACEHOLDER_EMBEDDABLE } from './placeholder_embeddable'; + +export class PlaceholderEmbeddableFactory implements EmbeddableFactoryDefinition { + public readonly type = PLACEHOLDER_EMBEDDABLE; + + public async isEditable() { + return false; + } + + public async create(initialInput: EmbeddableInput, parent?: IContainer) { + return new PlaceholderEmbeddable(initialInput, parent); + } + + public getDisplayName() { + return i18n.translate('dashboard.placeholder.factory.displayName', { + defaultMessage: 'placeholder', + }); + } +} diff --git a/src/plugins/dashboard/public/plugin.tsx b/src/plugins/dashboard/public/plugin.tsx index 322d734d9f39f4..203c784d9df4e3 100644 --- a/src/plugins/dashboard/public/plugin.tsx +++ b/src/plugins/dashboard/public/plugin.tsx @@ -67,9 +67,12 @@ import { ExpandPanelActionContext, ReplacePanelAction, ReplacePanelActionContext, + ClonePanelAction, + ClonePanelActionContext, ACTION_EXPAND_PANEL, ACTION_REPLACE_PANEL, RenderDeps, + ACTION_CLONE_PANEL, } from './application'; import { DashboardAppLinkGeneratorState, @@ -78,6 +81,7 @@ import { } from './url_generator'; import { createSavedDashboardLoader } from './saved_dashboards'; import { DashboardConstants } from './dashboard_constants'; +import { PlaceholderEmbeddableFactory } from './application/embeddable/placeholder'; declare module '../../share/public' { export interface UrlGeneratorStateMapping { @@ -115,6 +119,7 @@ declare module '../../../plugins/ui_actions/public' { export interface ActionContextMapping { [ACTION_EXPAND_PANEL]: ExpandPanelActionContext; [ACTION_REPLACE_PANEL]: ReplacePanelActionContext; + [ACTION_CLONE_PANEL]: ClonePanelActionContext; } } @@ -173,6 +178,9 @@ export class DashboardPlugin const factory = new DashboardContainerFactory(getStartServices); embeddable.registerEmbeddableFactory(factory.type, factory); + const placeholderFactory = new PlaceholderEmbeddableFactory(); + embeddable.registerEmbeddableFactory(placeholderFactory.type, placeholderFactory); + const { appMounted, appUnMounted, stop: stopUrlTracker } = createKbnUrlTracker({ baseUrl: core.http.basePath.prepend('/app/kibana'), defaultSubUrl: `#${DashboardConstants.LANDING_PAGE_PATH}`, @@ -297,6 +305,11 @@ export class DashboardPlugin ); uiActions.registerAction(changeViewAction); uiActions.attachAction(CONTEXT_MENU_TRIGGER, changeViewAction); + + const clonePanelAction = new ClonePanelAction(core); + uiActions.registerAction(clonePanelAction); + uiActions.attachAction(CONTEXT_MENU_TRIGGER, clonePanelAction); + const savedDashboardLoader = createSavedDashboardLoader({ savedObjectsClient: core.savedObjects.client, indexPatterns, diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index 06a46065baa847..4fa6b506ea5960 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -255,6 +255,7 @@ export { AggregationRestrictions as IndexPatternAggRestrictions, // TODO: exported only in stub_index_pattern test. Move into data plugin and remove export. FieldList as IndexPatternFieldList, + Field, } from './index_patterns'; export { @@ -293,6 +294,7 @@ import { convertIPRangeToString, intervalOptions, // only used in Discover isDateHistogramBucketAggConfig, + isNumberType, isStringType, isType, parentPipelineType, @@ -363,7 +365,6 @@ export { SearchRequest, SearchResponse, SearchError, - SearchStrategyProvider, ISearchSource, SearchSource, createSearchSource, @@ -393,6 +394,7 @@ export const search = { InvalidEsCalendarIntervalError, InvalidEsIntervalFormatError, isDateHistogramBucketAggConfig, + isNumberType, isStringType, isType, isValidEsInterval, diff --git a/src/plugins/data/public/index_patterns/fields/field.ts b/src/plugins/data/public/index_patterns/fields/field.ts index 03a5b61f9b116b..0fb92393d56f71 100644 --- a/src/plugins/data/public/index_patterns/fields/field.ts +++ b/src/plugins/data/public/index_patterns/fields/field.ts @@ -46,9 +46,6 @@ export class Field implements IFieldType { displayName?: string; indexPattern?: IndexPattern; format: any; - routes: Record = { - edit: '/management/kibana/index_patterns/{{indexPattern.id}}/field/{{name}}', - }; $$spec: FieldSpec; constructor( @@ -147,7 +144,3 @@ export class Field implements IFieldType { return obj.create(); } } - -Field.prototype.routes = { - edit: '/management/kibana/index_patterns/{{indexPattern.id}}/field/{{name}}', -}; diff --git a/src/plugins/data/public/index_patterns/fields/field_list.ts b/src/plugins/data/public/index_patterns/fields/field_list.ts index 03214a8c96427a..d6067280fd7b67 100644 --- a/src/plugins/data/public/index_patterns/fields/field_list.ts +++ b/src/plugins/data/public/index_patterns/fields/field_list.ts @@ -70,11 +70,12 @@ export class FieldList extends Array implements IFieldList { this.splice(fieldIndex, 1); }; - update = (field: Field) => { - const index = this.findIndex(f => f.name === field.name); - this.splice(index, 1, field); - this.setByName(field); - this.removeByGroup(field); - this.setByGroup(field); + update = (field: FieldSpec) => { + const newField = new Field(this.indexPattern, field, this.shortDotsEnable); + const index = this.findIndex(f => f.name === newField.name); + this.splice(index, 1, newField); + this.setByName(newField); + this.removeByGroup(newField); + this.setByGroup(newField); }; } diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 7d902c88616c51..b086927a6c17e5 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -460,6 +460,53 @@ export interface FetchOptions { searchStrategyId?: string; } +// Warning: (ae-missing-release-tag) "Field" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +class Field implements IFieldType { + // Warning: (ae-forgotten-export) The symbol "FieldSpec" needs to be exported by the entry point index.d.ts + // + // (undocumented) + $$spec: FieldSpec; + constructor(indexPattern: IndexPattern, spec: FieldSpec | Field, shortDotsEnable?: boolean); + // (undocumented) + aggregatable?: boolean; + // (undocumented) + count?: number; + // (undocumented) + displayName?: string; + // (undocumented) + esTypes?: string[]; + // (undocumented) + filterable?: boolean; + // (undocumented) + format: any; + // (undocumented) + indexPattern?: IndexPattern; + // (undocumented) + lang?: string; + // (undocumented) + name: string; + // (undocumented) + script?: string; + // (undocumented) + scripted?: boolean; + // (undocumented) + searchable?: boolean; + // (undocumented) + sortable?: boolean; + // (undocumented) + subType?: IFieldSubType; + // (undocumented) + type: string; + // (undocumented) + visualizable?: boolean; +} + +export { Field } + +export { Field as IndexPatternField } + // Warning: (ae-missing-release-tag) "FieldFormatConfig" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -836,19 +883,19 @@ export class IndexPattern implements IIndexPattern { }[]; }; // (undocumented) - getFieldByName(name: string): IndexPatternField | void; + getFieldByName(name: string): Field | void; // (undocumented) getIndex(): string; // (undocumented) - getNonScriptedFields(): IndexPatternField[]; + getNonScriptedFields(): Field[]; // (undocumented) - getScriptedFields(): IndexPatternField[]; + getScriptedFields(): Field[]; // (undocumented) getSourceFiltering(): { excludes: any[]; }; // (undocumented) - getTimeField(): IndexPatternField | undefined; + getTimeField(): Field | undefined; // (undocumented) id?: string; // (undocumented) @@ -931,66 +978,21 @@ export interface IndexPatternAttributes { typeMeta: string; } -// Warning: (ae-missing-release-tag) "Field" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export class IndexPatternField implements IFieldType { - // Warning: (ae-forgotten-export) The symbol "FieldSpec" needs to be exported by the entry point index.d.ts - // - // (undocumented) - $$spec: FieldSpec; - constructor(indexPattern: IndexPattern, spec: FieldSpec | IndexPatternField, shortDotsEnable?: boolean); - // (undocumented) - aggregatable?: boolean; - // (undocumented) - count?: number; - // (undocumented) - displayName?: string; - // (undocumented) - esTypes?: string[]; - // (undocumented) - filterable?: boolean; - // (undocumented) - format: any; - // (undocumented) - indexPattern?: IndexPattern; - // (undocumented) - lang?: string; - // (undocumented) - name: string; - // (undocumented) - routes: Record; - // (undocumented) - script?: string; - // (undocumented) - scripted?: boolean; - // (undocumented) - searchable?: boolean; - // (undocumented) - sortable?: boolean; - // (undocumented) - subType?: IFieldSubType; - // (undocumented) - type: string; - // (undocumented) - visualizable?: boolean; -} - // Warning: (ae-missing-release-tag) "FieldList" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export class IndexPatternFieldList extends Array implements IFieldList { +export class IndexPatternFieldList extends Array implements IFieldList { constructor(indexPattern: IndexPattern, specs?: FieldSpec[], shortDotsEnable?: boolean); // (undocumented) add: (field: Record) => void; // (undocumented) - getByName: (name: string) => IndexPatternField | undefined; + getByName: (name: string) => Field | undefined; // (undocumented) getByType: (type: string) => any[]; // (undocumented) remove: (field: IFieldType) => void; // (undocumented) - update: (field: IndexPatternField) => void; + update: (field: Record) => void; } // Warning: (ae-missing-release-tag) "indexPatterns" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -1557,8 +1559,9 @@ export const search: { InvalidEsCalendarIntervalError: typeof InvalidEsCalendarIntervalError; InvalidEsIntervalFormatError: typeof InvalidEsIntervalFormatError; isDateHistogramBucketAggConfig: typeof isDateHistogramBucketAggConfig; + isNumberType: (agg: import("./search").AggConfig) => boolean; isStringType: (agg: import("./search").AggConfig) => boolean; - isType: (type: string) => (agg: import("./search").AggConfig) => boolean; + isType: (...types: string[]) => (agg: import("./search").AggConfig) => boolean; isValidEsInterval: typeof isValidEsInterval; isValidInterval: typeof isValidInterval; parentPipelineType: string; @@ -1736,21 +1739,6 @@ export interface SearchSourceFields { version?: boolean; } -// Warning: (ae-missing-release-tag) "SearchStrategyProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export interface SearchStrategyProvider { - // (undocumented) - id: string; - // (undocumented) - isViable: (indexPattern: IndexPattern) => boolean; - // Warning: (ae-forgotten-export) The symbol "SearchStrategySearchParams" needs to be exported by the entry point index.d.ts - // Warning: (ae-forgotten-export) The symbol "SearchStrategyResponse" needs to be exported by the entry point index.d.ts - // - // (undocumented) - search: (params: SearchStrategySearchParams) => SearchStrategyResponse; -} - // Warning: (ae-missing-release-tag) "SortDirection" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -1901,21 +1889,21 @@ export type TSearchStrategyProvider = (context: ISearc // src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "getRoutes" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:383:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:383:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:383:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:383:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:388:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:389:1 - (ae-forgotten-export) The symbol "convertDateRangeToString" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:391:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:400:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:401:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:402:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:405:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:406:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:409:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:410:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:413:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:384:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:384:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:384:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:384:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:389:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:390:1 - (ae-forgotten-export) The symbol "convertDateRangeToString" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:392:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:401:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:402:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:403:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:407:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:408:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:411:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:412:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:415:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:33:33 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:37:1 - (ae-forgotten-export) The symbol "QueryStateChange" needs to be exported by the entry point index.d.ts // src/plugins/data/public/types.ts:52:5 - (ae-forgotten-export) The symbol "createFiltersFromEvent" needs to be exported by the entry point index.d.ts diff --git a/src/plugins/data/public/search/aggs/buckets/migrate_include_exclude_format.ts b/src/plugins/data/public/search/aggs/buckets/migrate_include_exclude_format.ts index 0beeb1c3722752..116f8cfad60f6d 100644 --- a/src/plugins/data/public/search/aggs/buckets/migrate_include_exclude_format.ts +++ b/src/plugins/data/public/search/aggs/buckets/migrate_include_exclude_format.ts @@ -21,20 +21,22 @@ import { isString, isObject } from 'lodash'; import { IBucketAggConfig, BucketAggType, BucketAggParam } from './bucket_agg_type'; import { IAggConfig } from '../agg_config'; -export const isType = (type: string) => { +export const isType = (...types: string[]) => { return (agg: IAggConfig): boolean => { const field = agg.params.field; - return field && field.type === type; + return types.some(type => field && field.type === type); }; }; +export const isNumberType = isType('number'); export const isStringType = isType('string'); +export const isStringOrNumberType = isType('string', 'number'); export const migrateIncludeExcludeFormat = { serialize(this: BucketAggParam, value: any, agg: IBucketAggConfig) { if (this.shouldShow && !this.shouldShow(agg)) return; - if (!value || isString(value)) return value; + if (!value || isString(value) || Array.isArray(value)) return value; else return value.pattern; }, write( @@ -44,7 +46,12 @@ export const migrateIncludeExcludeFormat = { ) { const value = aggConfig.getParam(this.name); - if (isObject(value)) { + if (Array.isArray(value) && value.length > 0 && isNumberType(aggConfig)) { + const parsedValue = value.filter((val): val is number => Number.isFinite(val)); + if (parsedValue.length) { + output.params[this.name] = parsedValue; + } + } else if (isObject(value)) { output.params[this.name] = value.pattern; } else if (value && isStringType(aggConfig)) { output.params[this.name] = value; diff --git a/src/plugins/data/public/search/aggs/buckets/terms.test.ts b/src/plugins/data/public/search/aggs/buckets/terms.test.ts index 0dc052bd1fdf6d..9769efb6da7494 100644 --- a/src/plugins/data/public/search/aggs/buckets/terms.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/terms.test.ts @@ -75,5 +75,65 @@ describe('Terms Agg', () => { expect(params.include).toBe('404'); expect(params.exclude).toBe('400'); }); + + test('accepts string from string field type and writes this value', () => { + const aggConfigs = getAggConfigs({ + include: 'include value', + exclude: 'exclude value', + field: { + name: 'string_field', + type: 'string', + }, + orderAgg: { + type: 'count', + }, + }); + + const { [BUCKET_TYPES.TERMS]: params } = aggConfigs.aggs[0].toDsl(); + + expect(params.field).toBe('string_field'); + expect(params.include).toBe('include value'); + expect(params.exclude).toBe('exclude value'); + }); + + test('accepts empty array from number field type and does not write a value', () => { + const aggConfigs = getAggConfigs({ + include: [], + exclude: [], + field: { + name: 'empty_number_field', + type: 'number', + }, + orderAgg: { + type: 'count', + }, + }); + + const { [BUCKET_TYPES.TERMS]: params } = aggConfigs.aggs[0].toDsl(); + + expect(params.field).toBe('empty_number_field'); + expect(params.include).toBe(undefined); + expect(params.exclude).toBe(undefined); + }); + + test('filters array with empty strings from number field type and writes only numbers', () => { + const aggConfigs = getAggConfigs({ + include: [1.1, 2, '', 3.33, ''], + exclude: ['', 4, 5.555, '', 6], + field: { + name: 'number_field', + type: 'number', + }, + orderAgg: { + type: 'count', + }, + }); + + const { [BUCKET_TYPES.TERMS]: params } = aggConfigs.aggs[0].toDsl(); + + expect(params.field).toBe('number_field'); + expect(params.include).toStrictEqual([1.1, 2, 3.33]); + expect(params.exclude).toStrictEqual([4, 5.555, 6]); + }); }); }); diff --git a/src/plugins/data/public/search/aggs/buckets/terms.ts b/src/plugins/data/public/search/aggs/buckets/terms.ts index 5baa38af0e8d61..698e0dfb1d3404 100644 --- a/src/plugins/data/public/search/aggs/buckets/terms.ts +++ b/src/plugins/data/public/search/aggs/buckets/terms.ts @@ -22,7 +22,10 @@ import { i18n } from '@kbn/i18n'; import { BucketAggType, IBucketAggConfig } from './bucket_agg_type'; import { BUCKET_TYPES } from './bucket_agg_types'; import { createFilterTerms } from './create_filter/terms'; -import { isStringType, migrateIncludeExcludeFormat } from './migrate_include_exclude_format'; +import { + isStringOrNumberType, + migrateIncludeExcludeFormat, +} from './migrate_include_exclude_format'; import { IAggConfigs } from '../agg_configs'; import { Adapters } from '../../../../../inspector/public'; @@ -266,7 +269,7 @@ export const getTermsBucketAgg = ({ getInternalStartServices }: TermsBucketAggDe }), type: 'string', advanced: true, - shouldShow: isStringType, + shouldShow: isStringOrNumberType, ...migrateIncludeExcludeFormat, }, { @@ -276,7 +279,7 @@ export const getTermsBucketAgg = ({ getInternalStartServices }: TermsBucketAggDe }), type: 'string', advanced: true, - shouldShow: isStringType, + shouldShow: isStringOrNumberType, ...migrateIncludeExcludeFormat, }, ], diff --git a/src/plugins/data/public/search/aggs/test_helpers/mock_data_services.ts b/src/plugins/data/public/search/aggs/test_helpers/mock_data_services.ts index d1d591771743c7..e807e084c683a2 100644 --- a/src/plugins/data/public/search/aggs/test_helpers/mock_data_services.ts +++ b/src/plugins/data/public/search/aggs/test_helpers/mock_data_services.ts @@ -18,8 +18,8 @@ */ // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { coreMock } from '../../../../../../../src/core/public/mocks'; -import { dataPluginMock } from '../../../../public/mocks'; +import { coreMock } from '../../../../../../core/public/mocks'; +import { dataPluginMock } from '../../../mocks'; import { setFieldFormats, setIndexPatterns, @@ -29,7 +29,7 @@ import { setQueryService, setSearchService, setUiSettings, -} from '../../../../public/services'; +} from '../../../services'; /** * Testing helper which calls all of the service setters used in the @@ -49,4 +49,9 @@ export function mockDataServices() { setQueryService(data.query); setSearchService(data.search); setUiSettings(core.uiSettings); + + return { + core, + data, + }; } diff --git a/src/plugins/data/public/search/fetch/get_search_params.test.ts b/src/plugins/data/public/search/fetch/get_search_params.test.ts new file mode 100644 index 00000000000000..edf18405e8ff71 --- /dev/null +++ b/src/plugins/data/public/search/fetch/get_search_params.test.ts @@ -0,0 +1,70 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { getSearchParams } from './get_search_params'; +import { IUiSettingsClient } from 'kibana/public'; + +function getConfigStub(config: any = {}) { + return { + get: key => config[key], + } as IUiSettingsClient; +} + +describe('getSearchParams', () => { + test('includes rest_total_hits_as_int', () => { + const config = getConfigStub(); + const searchParams = getSearchParams(config); + expect(searchParams.rest_total_hits_as_int).toBe(true); + }); + + test('includes ignore_unavailable', () => { + const config = getConfigStub(); + const searchParams = getSearchParams(config); + expect(searchParams.ignore_unavailable).toBe(true); + }); + + test('includes ignore_throttled according to search:includeFrozen', () => { + let config = getConfigStub({ 'search:includeFrozen': true }); + let searchParams = getSearchParams(config); + expect(searchParams.ignore_throttled).toBe(false); + + config = getConfigStub({ 'search:includeFrozen': false }); + searchParams = getSearchParams(config); + expect(searchParams.ignore_throttled).toBe(true); + }); + + test('includes max_concurrent_shard_requests according to courier:maxConcurrentShardRequests', () => { + let config = getConfigStub({ 'courier:maxConcurrentShardRequests': 0 }); + let searchParams = getSearchParams(config); + expect(searchParams.max_concurrent_shard_requests).toBe(undefined); + + config = getConfigStub({ 'courier:maxConcurrentShardRequests': 5 }); + searchParams = getSearchParams(config); + expect(searchParams.max_concurrent_shard_requests).toBe(5); + }); + + test('includes timeout according to esShardTimeout if greater than 0', () => { + const config = getConfigStub(); + let searchParams = getSearchParams(config, 0); + expect(searchParams.timeout).toBe(undefined); + + searchParams = getSearchParams(config, 100); + expect(searchParams.timeout).toBe('100ms'); + }); +}); diff --git a/src/plugins/data/public/search/search_strategy/get_search_params.ts b/src/plugins/data/public/search/fetch/get_search_params.ts similarity index 81% rename from src/plugins/data/public/search/search_strategy/get_search_params.ts rename to src/plugins/data/public/search/fetch/get_search_params.ts index 9fb8f2c728c6f0..f0c43bd2e74cd1 100644 --- a/src/plugins/data/public/search/search_strategy/get_search_params.ts +++ b/src/plugins/data/public/search/fetch/get_search_params.ts @@ -17,18 +17,10 @@ * under the License. */ -import { IUiSettingsClient } from '../../../../../core/public'; +import { IUiSettingsClient } from 'kibana/public'; const sessionId = Date.now(); -export function getMSearchParams(config: IUiSettingsClient) { - return { - rest_total_hits_as_int: true, - ignore_throttled: getIgnoreThrottled(config), - max_concurrent_shard_requests: getMaxConcurrentShardRequests(config), - }; -} - export function getSearchParams(config: IUiSettingsClient, esShardTimeout: number = 0) { return { rest_total_hits_as_int: true, @@ -40,11 +32,11 @@ export function getSearchParams(config: IUiSettingsClient, esShardTimeout: numbe }; } -function getIgnoreThrottled(config: IUiSettingsClient) { +export function getIgnoreThrottled(config: IUiSettingsClient) { return !config.get('search:includeFrozen'); } -function getMaxConcurrentShardRequests(config: IUiSettingsClient) { +export function getMaxConcurrentShardRequests(config: IUiSettingsClient) { const maxConcurrentShardRequests = config.get('courier:maxConcurrentShardRequests'); return maxConcurrentShardRequests > 0 ? maxConcurrentShardRequests : undefined; } diff --git a/src/plugins/data/public/search/fetch/index.ts b/src/plugins/data/public/search/fetch/index.ts index 8a80b716add321..39845ec31bfaaa 100644 --- a/src/plugins/data/public/search/fetch/index.ts +++ b/src/plugins/data/public/search/fetch/index.ts @@ -18,5 +18,14 @@ */ export * from './types'; -export { fetchSoon } from './fetch_soon'; -export { RequestFailure } from './errors'; +export { + getSearchParams, + getPreference, + getTimeout, + getIgnoreThrottled, + getMaxConcurrentShardRequests, +} from './get_search_params'; + +export { SearchError, getSearchErrorType } from './search_error'; +export { RequestFailure } from './request_error'; +export { handleResponse } from './handle_response'; diff --git a/src/plugins/data/public/search/fetch/errors.ts b/src/plugins/data/public/search/fetch/request_error.ts similarity index 100% rename from src/plugins/data/public/search/fetch/errors.ts rename to src/plugins/data/public/search/fetch/request_error.ts diff --git a/src/plugins/data/public/search/search_strategy/search_error.ts b/src/plugins/data/public/search/fetch/search_error.ts similarity index 100% rename from src/plugins/data/public/search/search_strategy/search_error.ts rename to src/plugins/data/public/search/fetch/search_error.ts diff --git a/src/plugins/data/public/search/fetch/types.ts b/src/plugins/data/public/search/fetch/types.ts index e8de0576b8a72f..475b2abbc019f4 100644 --- a/src/plugins/data/public/search/fetch/types.ts +++ b/src/plugins/data/public/search/fetch/types.ts @@ -20,6 +20,9 @@ import { IUiSettingsClient } from '../../../../../core/public'; import { ISearchStart } from '../types'; +export type SearchRequest = any; +export type SearchResponse = any; + export interface FetchOptions { abortSignal?: AbortSignal; searchStrategyId?: string; diff --git a/src/plugins/data/public/search/index.ts b/src/plugins/data/public/search/index.ts index cce973d632f417..75c0eb8b6f0229 100644 --- a/src/plugins/data/public/search/index.ts +++ b/src/plugins/data/public/search/index.ts @@ -44,9 +44,13 @@ export { esSearchStrategyProvider, getEsPreference } from './es_search'; export { IKibanaSearchResponse, IKibanaSearchRequest } from '../../common/search'; -export { LegacyApiCaller, SearchRequest, SearchResponse } from './es_client'; - -export { SearchError, SearchStrategyProvider, getSearchErrorType } from './search_strategy'; +export { + SearchError, + FetchOptions, + SearchRequest, + SearchResponse, + getSearchErrorType, +} from './fetch'; export { ISearchSource, @@ -59,5 +63,3 @@ export { export { SearchInterceptor } from './search_interceptor'; export { RequestTimeoutError } from './request_timeout_error'; - -export { FetchOptions } from './fetch'; diff --git a/src/plugins/data/public/search/fetch/call_client.test.ts b/src/plugins/data/public/search/legacy/call_client.test.ts similarity index 91% rename from src/plugins/data/public/search/fetch/call_client.test.ts rename to src/plugins/data/public/search/legacy/call_client.test.ts index 7a99b7c064515b..f919187d46784d 100644 --- a/src/plugins/data/public/search/fetch/call_client.test.ts +++ b/src/plugins/data/public/search/legacy/call_client.test.ts @@ -18,16 +18,17 @@ */ import { callClient } from './call_client'; -import { handleResponse } from './handle_response'; -import { FetchHandlers } from './types'; -import { SearchStrategySearchParams, defaultSearchStrategy } from '../search_strategy'; +import { SearchStrategySearchParams } from './types'; +import { defaultSearchStrategy } from './default_search_strategy'; +import { FetchHandlers } from '../fetch'; +import { handleResponse } from '../fetch/handle_response'; const mockAbortFn = jest.fn(); -jest.mock('./handle_response', () => ({ +jest.mock('../fetch/handle_response', () => ({ handleResponse: jest.fn((request, response) => response), })); -jest.mock('../search_strategy', () => { +jest.mock('./default_search_strategy', () => { return { defaultSearchStrategy: { search: jest.fn(({ searchRequests }: SearchStrategySearchParams) => { diff --git a/src/plugins/data/public/search/fetch/call_client.ts b/src/plugins/data/public/search/legacy/call_client.ts similarity index 89% rename from src/plugins/data/public/search/fetch/call_client.ts rename to src/plugins/data/public/search/legacy/call_client.ts index b3c4c682fa60c0..c484c46aa4879f 100644 --- a/src/plugins/data/public/search/fetch/call_client.ts +++ b/src/plugins/data/public/search/legacy/call_client.ts @@ -17,10 +17,9 @@ * under the License. */ -import { handleResponse } from './handle_response'; -import { FetchOptions, FetchHandlers } from './types'; -import { defaultSearchStrategy } from '../search_strategy'; -import { SearchRequest } from '..'; +import { FetchOptions, FetchHandlers, handleResponse } from '../fetch'; +import { defaultSearchStrategy } from './default_search_strategy'; +import { SearchRequest } from '../index'; export function callClient( searchRequests: SearchRequest[], diff --git a/src/plugins/data/public/search/search_strategy/default_search_strategy.test.ts b/src/plugins/data/public/search/legacy/default_search_strategy.test.ts similarity index 83% rename from src/plugins/data/public/search/search_strategy/default_search_strategy.test.ts rename to src/plugins/data/public/search/legacy/default_search_strategy.test.ts index 210a0e5fd1ac78..835b02b3cd5c74 100644 --- a/src/plugins/data/public/search/search_strategy/default_search_strategy.test.ts +++ b/src/plugins/data/public/search/legacy/default_search_strategy.test.ts @@ -17,10 +17,10 @@ * under the License. */ -import { IUiSettingsClient } from '../../../../../core/public'; -import { SearchStrategySearchParams } from './types'; +import { IUiSettingsClient } from 'kibana/public'; import { defaultSearchStrategy } from './default_search_strategy'; import { searchStartMock } from '../mocks'; +import { SearchStrategySearchParams } from './types'; const { search } = defaultSearchStrategy; @@ -38,12 +38,6 @@ const searchMockResponse: any = Promise.resolve([]); searchMockResponse.abort = jest.fn(); const searchMock = jest.fn().mockReturnValue(searchMockResponse); -const newSearchMockResponse: any = Promise.resolve([]); -newSearchMockResponse.abort = jest.fn(); -const newSearchMock = jest.fn().mockReturnValue({ - toPromise: () => searchMockResponse, -}); - describe('defaultSearchStrategy', function() { describe('search', function() { let searchArgs: MockedKeys>; @@ -58,7 +52,6 @@ describe('defaultSearchStrategy', function() { const searchService = searchStartMock; searchService.aggs.calculateAutoTimeExpression = jest.fn().mockReturnValue('1d'); - searchService.search = newSearchMock; searchService.__LEGACY.esClient.search = searchMock; searchService.__LEGACY.esClient.msearch = msearchMock; @@ -112,18 +105,5 @@ describe('defaultSearchStrategy', function() { search({ ...searchArgs, config }).abort(); expect(msearchMockResponse.abort).toHaveBeenCalled(); }); - - test('should call new search service', () => { - const config = getConfigStub(); - search({ ...searchArgs, config }); - expect(newSearchMock).toHaveBeenCalledTimes(1); - }); - - test('should properly abort with new search service', async () => { - const abortSpy = jest.spyOn(AbortController.prototype, 'abort'); - const config = getConfigStub({}); - search({ ...searchArgs, config }).abort(); - expect(abortSpy).toHaveBeenCalled(); - }); }); }); diff --git a/src/plugins/data/public/search/search_strategy/default_search_strategy.ts b/src/plugins/data/public/search/legacy/default_search_strategy.ts similarity index 64% rename from src/plugins/data/public/search/search_strategy/default_search_strategy.ts rename to src/plugins/data/public/search/legacy/default_search_strategy.ts index 2bd88f51587a8a..1552410f9090ca 100644 --- a/src/plugins/data/public/search/search_strategy/default_search_strategy.ts +++ b/src/plugins/data/public/search/legacy/default_search_strategy.ts @@ -17,23 +17,19 @@ * under the License. */ +import { getPreference, getTimeout } from '../fetch'; +import { getMSearchParams } from './get_msearch_params'; import { SearchStrategyProvider, SearchStrategySearchParams } from './types'; -import { isDefault } from '../../index_patterns'; -import { getSearchParams, getMSearchParams, getPreference, getTimeout } from './get_search_params'; +// @deprecated export const defaultSearchStrategy: SearchStrategyProvider = { id: 'default', search: params => { - return params.config.get('courier:batchSearches') ? msearch(params) : search(params); - }, - - isViable: indexPattern => { - return indexPattern && isDefault(indexPattern); + return msearch(params); }, }; -// @deprecated function msearch({ searchRequests, searchService, @@ -65,29 +61,3 @@ function msearch({ abort: searching.abort, }; } - -function search({ - searchRequests, - searchService, - config, - esShardTimeout, -}: SearchStrategySearchParams) { - const abortController = new AbortController(); - const searchParams = getSearchParams(config, esShardTimeout); - const promises = searchRequests.map(({ index, indexType, body }) => { - const params = { - index: index.title || index, - body, - ...searchParams, - }; - const { signal } = abortController; - return searchService - .search({ params, indexType }, { signal }) - .toPromise() - .then(({ rawResponse }) => rawResponse); - }); - return { - searching: Promise.all(promises), - abort: () => abortController.abort(), - }; -} diff --git a/src/plugins/data/public/search/es_client/get_es_client.ts b/src/plugins/data/public/search/legacy/es_client/get_es_client.ts similarity index 100% rename from src/plugins/data/public/search/es_client/get_es_client.ts rename to src/plugins/data/public/search/legacy/es_client/get_es_client.ts diff --git a/src/plugins/data/public/search/es_client/index.ts b/src/plugins/data/public/search/legacy/es_client/index.ts similarity index 91% rename from src/plugins/data/public/search/es_client/index.ts rename to src/plugins/data/public/search/legacy/es_client/index.ts index b1e0ce31168242..78ac83af642d83 100644 --- a/src/plugins/data/public/search/es_client/index.ts +++ b/src/plugins/data/public/search/legacy/es_client/index.ts @@ -18,4 +18,4 @@ */ export { getEsClient } from './get_es_client'; -export { SearchRequest, SearchResponse, LegacyApiCaller } from './types'; +export { LegacyApiCaller } from './types'; diff --git a/src/plugins/data/public/search/es_client/types.ts b/src/plugins/data/public/search/legacy/es_client/types.ts similarity index 94% rename from src/plugins/data/public/search/es_client/types.ts rename to src/plugins/data/public/search/legacy/es_client/types.ts index 3ca0513a14238d..7a56b9b0cb00a8 100644 --- a/src/plugins/data/public/search/es_client/types.ts +++ b/src/plugins/data/public/search/legacy/es_client/types.ts @@ -17,8 +17,7 @@ * under the License. */ -export type SearchRequest = any; -export type SearchResponse = any; +import { SearchRequest, SearchResponse } from '../../fetch'; export interface LegacyApiCaller { search: (searchRequest: SearchRequest) => LegacyApiCallerResponse; diff --git a/src/plugins/data/public/search/fetch/fetch_soon.test.ts b/src/plugins/data/public/search/legacy/fetch_soon.test.ts similarity index 96% rename from src/plugins/data/public/search/fetch/fetch_soon.test.ts rename to src/plugins/data/public/search/legacy/fetch_soon.test.ts index a8d593c8501f68..b2e17798ccc9fa 100644 --- a/src/plugins/data/public/search/fetch/fetch_soon.test.ts +++ b/src/plugins/data/public/search/legacy/fetch_soon.test.ts @@ -19,9 +19,9 @@ import { fetchSoon } from './fetch_soon'; import { callClient } from './call_client'; -import { IUiSettingsClient } from '../../../../../core/public'; -import { FetchHandlers, FetchOptions } from './types'; -import { SearchRequest, SearchResponse } from '..'; +import { IUiSettingsClient } from 'kibana/public'; +import { FetchHandlers, FetchOptions } from '../fetch/types'; +import { SearchRequest, SearchResponse } from '../index'; function getConfigStub(config: any = {}) { return { diff --git a/src/plugins/data/public/search/fetch/fetch_soon.ts b/src/plugins/data/public/search/legacy/fetch_soon.ts similarity index 95% rename from src/plugins/data/public/search/fetch/fetch_soon.ts rename to src/plugins/data/public/search/legacy/fetch_soon.ts index b1405747426ee9..18fa410a5bef03 100644 --- a/src/plugins/data/public/search/fetch/fetch_soon.ts +++ b/src/plugins/data/public/search/legacy/fetch_soon.ts @@ -18,8 +18,8 @@ */ import { callClient } from './call_client'; -import { FetchHandlers, FetchOptions } from './types'; -import { SearchRequest, SearchResponse } from '..'; +import { FetchHandlers, FetchOptions } from '../fetch/types'; +import { SearchRequest, SearchResponse } from '../index'; /** * This function introduces a slight delay in the request process to allow multiple requests to queue diff --git a/src/plugins/data/public/search/search_strategy/get_search_params.test.ts b/src/plugins/data/public/search/legacy/get_msearch_params.test.ts similarity index 60% rename from src/plugins/data/public/search/search_strategy/get_search_params.test.ts rename to src/plugins/data/public/search/legacy/get_msearch_params.test.ts index 76f3105d7f942e..9f16d5b408178d 100644 --- a/src/plugins/data/public/search/search_strategy/get_search_params.test.ts +++ b/src/plugins/data/public/search/legacy/get_msearch_params.test.ts @@ -17,7 +17,7 @@ * under the License. */ -import { getMSearchParams, getSearchParams } from './get_search_params'; +import { getMSearchParams } from './get_msearch_params'; import { IUiSettingsClient } from '../../../../../core/public'; function getConfigStub(config: any = {}) { @@ -64,46 +64,3 @@ describe('getMSearchParams', () => { expect(msearchParams.hasOwnProperty('timeout')).toBe(false); }); }); - -describe('getSearchParams', () => { - test('includes rest_total_hits_as_int', () => { - const config = getConfigStub(); - const searchParams = getSearchParams(config); - expect(searchParams.rest_total_hits_as_int).toBe(true); - }); - - test('includes ignore_unavailable', () => { - const config = getConfigStub(); - const searchParams = getSearchParams(config); - expect(searchParams.ignore_unavailable).toBe(true); - }); - - test('includes ignore_throttled according to search:includeFrozen', () => { - let config = getConfigStub({ 'search:includeFrozen': true }); - let searchParams = getSearchParams(config); - expect(searchParams.ignore_throttled).toBe(false); - - config = getConfigStub({ 'search:includeFrozen': false }); - searchParams = getSearchParams(config); - expect(searchParams.ignore_throttled).toBe(true); - }); - - test('includes max_concurrent_shard_requests according to courier:maxConcurrentShardRequests', () => { - let config = getConfigStub({ 'courier:maxConcurrentShardRequests': 0 }); - let searchParams = getSearchParams(config); - expect(searchParams.max_concurrent_shard_requests).toBe(undefined); - - config = getConfigStub({ 'courier:maxConcurrentShardRequests': 5 }); - searchParams = getSearchParams(config); - expect(searchParams.max_concurrent_shard_requests).toBe(5); - }); - - test('includes timeout according to esShardTimeout if greater than 0', () => { - const config = getConfigStub(); - let searchParams = getSearchParams(config, 0); - expect(searchParams.timeout).toBe(undefined); - - searchParams = getSearchParams(config, 100); - expect(searchParams.timeout).toBe('100ms'); - }); -}); diff --git a/src/plugins/data/public/search/legacy/get_msearch_params.ts b/src/plugins/data/public/search/legacy/get_msearch_params.ts new file mode 100644 index 00000000000000..48d13903c972fe --- /dev/null +++ b/src/plugins/data/public/search/legacy/get_msearch_params.ts @@ -0,0 +1,29 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { IUiSettingsClient } from 'kibana/public'; +import { getIgnoreThrottled, getMaxConcurrentShardRequests } from '../fetch'; + +export function getMSearchParams(config: IUiSettingsClient) { + return { + rest_total_hits_as_int: true, + ignore_throttled: getIgnoreThrottled(config), + max_concurrent_shard_requests: getMaxConcurrentShardRequests(config), + }; +} diff --git a/src/plugins/data/public/search/legacy/index.ts b/src/plugins/data/public/search/legacy/index.ts new file mode 100644 index 00000000000000..e2ae72824f3f49 --- /dev/null +++ b/src/plugins/data/public/search/legacy/index.ts @@ -0,0 +1,21 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { fetchSoon } from './fetch_soon'; +export { getEsClient, LegacyApiCaller } from './es_client'; diff --git a/src/plugins/data/public/search/search_strategy/types.ts b/src/plugins/data/public/search/legacy/types.ts similarity index 89% rename from src/plugins/data/public/search/search_strategy/types.ts rename to src/plugins/data/public/search/legacy/types.ts index 764370d8ff6497..3812cec7a2aa20 100644 --- a/src/plugins/data/public/search/search_strategy/types.ts +++ b/src/plugins/data/public/search/legacy/types.ts @@ -17,21 +17,20 @@ * under the License. */ -import { IndexPattern } from '../..'; -import { FetchHandlers } from '../fetch/types'; +import { FetchHandlers } from '../fetch'; import { SearchRequest, SearchResponse } from '..'; +export interface SearchStrategySearchParams extends FetchHandlers { + searchRequests: SearchRequest[]; +} + +// @deprecated export interface SearchStrategyProvider { id: string; search: (params: SearchStrategySearchParams) => SearchStrategyResponse; - isViable: (indexPattern: IndexPattern) => boolean; } export interface SearchStrategyResponse { searching: Promise; abort: () => void; } - -export interface SearchStrategySearchParams extends FetchHandlers { - searchRequests: SearchRequest[]; -} diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index a539736991adb4..916278a96659b4 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -22,12 +22,12 @@ import { Plugin, CoreSetup, CoreStart, PackageInfo } from '../../../../core/publ import { SYNC_SEARCH_STRATEGY, syncSearchStrategyProvider } from './sync_search_strategy'; import { ISearchSetup, ISearchStart, TSearchStrategyProvider, TSearchStrategiesMap } from './types'; import { TStrategyTypes } from './strategy_types'; -import { getEsClient, LegacyApiCaller } from './es_client'; +import { getEsClient, LegacyApiCaller } from './legacy'; import { ES_SEARCH_STRATEGY, DEFAULT_SEARCH_STRATEGY } from '../../common/search'; -import { esSearchStrategyProvider } from './es_search/es_search_strategy'; +import { esSearchStrategyProvider } from './es_search'; import { IndexPatternsContract } from '../index_patterns/index_patterns'; import { createSearchSource } from './search_source'; -import { QuerySetup } from '../query/query_service'; +import { QuerySetup } from '../query'; import { GetInternalStartServicesFn } from '../types'; import { SearchInterceptor } from './search_interceptor'; import { diff --git a/src/plugins/data/public/search/search_source/search_source.test.ts b/src/plugins/data/public/search/search_source/search_source.test.ts index 6bad093d31402b..6e878844664ad2 100644 --- a/src/plugins/data/public/search/search_source/search_source.test.ts +++ b/src/plugins/data/public/search/search_source/search_source.test.ts @@ -20,8 +20,26 @@ import { SearchSource } from './search_source'; import { IndexPattern, SortDirection } from '../..'; import { mockDataServices } from '../aggs/test_helpers'; +import { setSearchService } from '../../services'; +import { searchStartMock } from '../mocks'; +import { fetchSoon } from '../legacy'; +import { CoreStart } from 'kibana/public'; +import { Observable } from 'rxjs'; -jest.mock('../fetch', () => ({ +// Setup search service mock +searchStartMock.search = jest.fn(() => { + return new Observable(subscriber => { + setTimeout(() => { + subscriber.next({ + rawResponse: '', + }); + subscriber.complete(); + }, 100); + }); +}) as any; +setSearchService(searchStartMock); + +jest.mock('../legacy', () => ({ fetchSoon: jest.fn().mockResolvedValue({}), })); @@ -44,8 +62,11 @@ const indexPattern2 = ({ } as unknown) as IndexPattern; describe('SearchSource', function() { + let uiSettingsMock: jest.Mocked; beforeEach(() => { - mockDataServices(); + const { core } = mockDataServices(); + uiSettingsMock = core.uiSettings; + jest.clearAllMocks(); }); describe('#setField()', function() { @@ -151,6 +172,36 @@ describe('SearchSource', function() { }); }); + describe('#legacy fetch()', () => { + beforeEach(() => { + uiSettingsMock.get.mockImplementation(() => { + return true; // batchSearches = true + }); + }); + + afterEach(() => { + uiSettingsMock.get.mockImplementation(() => { + return false; // batchSearches = false + }); + }); + + it('should call msearch', async () => { + const searchSource = new SearchSource({ index: indexPattern }); + const options = {}; + await searchSource.fetch(options); + expect(fetchSoon).toBeCalledTimes(1); + }); + }); + + describe('#search service fetch()', () => { + it('should call msearch', async () => { + const searchSource = new SearchSource({ index: indexPattern }); + const options = {}; + await searchSource.fetch(options); + expect(searchStartMock.search).toBeCalledTimes(1); + }); + }); + describe('#serialize', function() { it('should reference index patterns', () => { const indexPattern123 = { id: '123' } as IndexPattern; diff --git a/src/plugins/data/public/search/search_source/search_source.ts b/src/plugins/data/public/search/search_source/search_source.ts index c70db7bb82ef7f..9d2bb889953cf2 100644 --- a/src/plugins/data/public/search/search_source/search_source.ts +++ b/src/plugins/data/public/search/search_source/search_source.ts @@ -70,17 +70,19 @@ */ import _ from 'lodash'; +import { map } from 'rxjs/operators'; import { SavedObjectReference } from 'kibana/public'; import { normalizeSortRequest } from './normalize_sort_request'; import { filterDocvalueFields } from './filter_docvalue_fields'; import { fieldWildcardFilter } from '../../../../kibana_utils/public'; import { IIndexPattern, SearchRequest } from '../..'; import { SearchSourceOptions, SearchSourceFields } from './types'; -import { fetchSoon, FetchOptions, RequestFailure } from '../fetch'; +import { FetchOptions, RequestFailure, getSearchParams, handleResponse } from '../fetch'; import { getSearchService, getUiSettings, getInjectedMetadata } from '../../services'; import { getEsQueryConfig, buildEsQuery, Filter } from '../../../common'; import { getHighlightRequest } from '../../../common/field_formats'; +import { fetchSoon } from '../legacy'; export type ISearchSource = Pick; @@ -185,18 +187,29 @@ export class SearchSource { } /** - * Fetch this source and reject the returned Promise on error - * - * @async + * Run a search using the search service + * @return {Observable>} */ - async fetch(options: FetchOptions = {}) { - await this.requestIsStarting(options); - - const searchRequest = await this.flatten(); - this.history = [searchRequest]; + private fetch$(searchRequest: SearchRequest, signal?: AbortSignal) { + const esShardTimeout = getInjectedMetadata().getInjectedVar('esShardTimeout') as number; + const searchParams = getSearchParams(getUiSettings(), esShardTimeout); + const params = { + index: searchRequest.index.title || searchRequest.index, + body: searchRequest.body, + ...searchParams, + }; + return getSearchService() + .search({ params, indexType: searchRequest.indexType }, { signal }) + .pipe(map(({ rawResponse }) => handleResponse(searchRequest, rawResponse))); + } + /** + * Run a search using the search service + * @return {Promise>} + */ + private async legacyFetch(searchRequest: SearchRequest, options: FetchOptions) { const esShardTimeout = getInjectedMetadata().getInjectedVar('esShardTimeout') as number; - const response = await fetchSoon( + return await fetchSoon( searchRequest, { ...(this.searchStrategyId && { searchStrategyId: this.searchStrategyId }), @@ -208,6 +221,24 @@ export class SearchSource { esShardTimeout, } ); + } + /** + * Fetch this source and reject the returned Promise on error + * + * @async + */ + async fetch(options: FetchOptions = {}) { + await this.requestIsStarting(options); + + const searchRequest = await this.flatten(); + this.history = [searchRequest]; + + let response; + if (getUiSettings().get('courier:batchSearches')) { + response = await this.legacyFetch(searchRequest, options); + } else { + response = this.fetch$(searchRequest, options.abortSignal).toPromise(); + } if (response.error) { throw new RequestFailure(null, response); @@ -246,7 +277,6 @@ export class SearchSource { /** * Called by requests of this search source when they are started - * @param {Courier.Request} request * @param options * @return {Promise} */ @@ -430,7 +460,6 @@ export class SearchSource { * and `kibanaSavedObjectMeta.searchSourceJSON.filter[].meta.index`. * * Using `createSearchSource`, the instance can be re-created. - * @param searchSource The search source to serialize * @public */ public serialize() { const references: SavedObjectReference[] = []; diff --git a/src/plugins/data/public/search/search_strategy/no_op_search_strategy.ts b/src/plugins/data/public/search/search_strategy/no_op_search_strategy.ts deleted file mode 100644 index dc7331e614a0e4..00000000000000 --- a/src/plugins/data/public/search/search_strategy/no_op_search_strategy.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { SearchError } from './search_error'; -import { SearchStrategyProvider } from './types'; - -export const noOpSearchStrategy: SearchStrategyProvider = { - id: 'noOp', - - search: () => { - const searchError = new SearchError({ - status: '418', // "I'm a teapot" error - title: i18n.translate( - 'data.search.searchSource.noSearchStrategyRegisteredErrorMessageTitle', - { - defaultMessage: 'No search strategy registered', - } - ), - message: i18n.translate( - 'data.search.searchSource.noSearchStrategyRegisteredErrorMessageDescription', - { - defaultMessage: `Couldn't find a search strategy for the search request`, - } - ), - type: 'NO_OP_SEARCH_STRATEGY', - path: '', - }); - - return { - searching: Promise.reject(searchError), - abort: () => {}, - }; - }, - - isViable: () => { - return true; - }, -}; diff --git a/src/plugins/data/public/search/types.ts b/src/plugins/data/public/search/types.ts index ba6e44f47b75eb..2122e4e82ec1d7 100644 --- a/src/plugins/data/public/search/types.ts +++ b/src/plugins/data/public/search/types.ts @@ -22,7 +22,7 @@ import { createSearchSource } from './search_source'; import { SearchAggsSetup, SearchAggsStart, SearchAggsStartLegacy } from './aggs'; import { ISearch, ISearchGeneric } from './i_search'; import { TStrategyTypes } from './strategy_types'; -import { LegacyApiCaller } from './es_client'; +import { LegacyApiCaller } from './legacy/es_client'; import { SearchInterceptor } from './search_interceptor'; export interface ISearchContext { @@ -38,15 +38,6 @@ export interface ISearchStrategy { search: ISearch; } -/** - * Search strategy provider creates an instance of a search strategy with the request - * handler context bound to it. This way every search strategy can use - * whatever information they require from the request context. - */ -export type TSearchStrategyProviderEnhanced = ( - search: ISearchGeneric -) => Promise>; - export type TSearchStrategiesMap = { [K in TStrategyTypes]?: TSearchStrategyProvider; }; diff --git a/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/authorization_provider.tsx b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/authorization_provider.tsx new file mode 100644 index 00000000000000..68f1cf2045efb2 --- /dev/null +++ b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/authorization_provider.tsx @@ -0,0 +1,73 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { HttpSetup } from 'kibana/public'; +import React, { createContext, useContext } from 'react'; + +import { useRequest } from '../../../public'; + +import { Error as CustomError } from './section_error'; + +import { Privileges } from '../types'; + +interface Authorization { + isLoading: boolean; + apiError: CustomError | null; + privileges: Privileges; +} + +const initialValue: Authorization = { + isLoading: true, + apiError: null, + privileges: { + hasAllPrivileges: true, + missingPrivileges: {}, + }, +}; + +export const AuthorizationContext = createContext(initialValue); + +export const useAuthorizationContext = () => { + const ctx = useContext(AuthorizationContext); + if (!ctx) { + throw new Error('AuthorizationContext can only be used inside of AuthorizationProvider!'); + } + return ctx; +}; + +interface Props { + privilegesEndpoint: string; + children: React.ReactNode; + httpClient: HttpSetup; +} + +export const AuthorizationProvider = ({ privilegesEndpoint, httpClient, children }: Props) => { + const { isLoading, error, data: privilegesData } = useRequest(httpClient, { + path: privilegesEndpoint, + method: 'get', + }); + + const value = { + isLoading, + privileges: isLoading ? { hasAllPrivileges: true, missingPrivileges: {} } : privilegesData, + apiError: error ? error : null, + } as Authorization; + + return {children}; +}; diff --git a/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/index.ts b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/index.ts new file mode 100644 index 00000000000000..71be3cc6152ca8 --- /dev/null +++ b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/index.ts @@ -0,0 +1,30 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { + AuthorizationProvider, + AuthorizationContext, + useAuthorizationContext, +} from './authorization_provider'; + +export { WithPrivileges } from './with_privileges'; + +export { NotAuthorizedSection } from './not_authorized_section'; + +export { Error, SectionError } from './section_error'; diff --git a/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/not_authorized_section.tsx b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/not_authorized_section.tsx new file mode 100644 index 00000000000000..c35f674ef9ec42 --- /dev/null +++ b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/not_authorized_section.tsx @@ -0,0 +1,30 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { EuiEmptyPrompt } from '@elastic/eui'; + +interface Props { + title: React.ReactNode; + message: React.ReactNode | string; +} + +export const NotAuthorizedSection = ({ title, message }: Props) => ( + {title}} body={

{message}

} /> +); diff --git a/x-pack/plugins/snapshot_restore/public/application/components/section_error.tsx b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/section_error.tsx similarity index 54% rename from x-pack/plugins/snapshot_restore/public/application/components/section_error.tsx rename to src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/section_error.tsx index bd9e48796779e7..3d56309adae97f 100644 --- a/x-pack/plugins/snapshot_restore/public/application/components/section_error.tsx +++ b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/section_error.tsx @@ -1,7 +1,20 @@ /* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. */ import { EuiCallOut, EuiSpacer } from '@elastic/eui'; diff --git a/x-pack/plugins/snapshot_restore/public/application/lib/authorization/components/with_privileges.tsx b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/with_privileges.tsx similarity index 70% rename from x-pack/plugins/snapshot_restore/public/application/lib/authorization/components/with_privileges.tsx rename to src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/with_privileges.tsx index 223a2882c3cab3..8f4b2b976d1411 100644 --- a/x-pack/plugins/snapshot_restore/public/application/lib/authorization/components/with_privileges.tsx +++ b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/components/with_privileges.tsx @@ -1,13 +1,25 @@ /* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. */ -import { useContext } from 'react'; +import { MissingPrivileges } from '../types'; -import { MissingPrivileges } from '../../../../../common/types'; -import { AuthorizationContext } from './authorization_provider'; +import { useAuthorizationContext } from './authorization_provider'; interface Props { /** @@ -29,7 +41,7 @@ const toArray = (value: string | string[]): string[] => Array.isArray(value) ? (value as string[]) : ([value] as string[]); export const WithPrivileges = ({ privileges: requiredPrivileges, children }: Props) => { - const { isLoading, privileges } = useContext(AuthorizationContext); + const { isLoading, privileges } = useAuthorizationContext(); const privilegesToArray: Privilege[] = toArray(requiredPrivileges).map(p => { const [section, privilege] = p.split('.'); diff --git a/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/index.ts b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/index.ts new file mode 100644 index 00000000000000..ad89052b3bb541 --- /dev/null +++ b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/index.ts @@ -0,0 +1,30 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { + WithPrivileges, + NotAuthorizedSection, + AuthorizationProvider, + AuthorizationContext, + SectionError, + Error, + useAuthorizationContext, +} from './components'; + +export { Privileges, MissingPrivileges } from './types'; diff --git a/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/types.ts b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/types.ts new file mode 100644 index 00000000000000..cdc2052122688a --- /dev/null +++ b/src/plugins/es_ui_shared/__packages_do_not_import__/authorization/types.ts @@ -0,0 +1,27 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export interface MissingPrivileges { + [key: string]: string[] | undefined; +} + +export interface Privileges { + hasAllPrivileges: boolean; + missingPrivileges: MissingPrivileges; +} diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/create_edit_field/index.js b/src/plugins/es_ui_shared/public/authorization/index.ts similarity index 92% rename from src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/create_edit_field/index.js rename to src/plugins/es_ui_shared/public/authorization/index.ts index 890a3b2622577b..3a02c0d2694f3d 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/create_edit_field/index.js +++ b/src/plugins/es_ui_shared/public/authorization/index.ts @@ -17,4 +17,4 @@ * under the License. */ -import './create_edit_field'; +export * from '../../__packages_do_not_import__/authorization'; diff --git a/src/plugins/es_ui_shared/public/index.ts b/src/plugins/es_ui_shared/public/index.ts index a0371bf351193c..7e5510d7c9c651 100644 --- a/src/plugins/es_ui_shared/public/index.ts +++ b/src/plugins/es_ui_shared/public/index.ts @@ -47,6 +47,18 @@ export { expandLiteralStrings, } from './console_lang'; +export { + AuthorizationContext, + AuthorizationProvider, + NotAuthorizedSection, + WithPrivileges, + Privileges, + MissingPrivileges, + SectionError, + Error, + useAuthorizationContext, +} from './authorization'; + /** dummy plugin, we just want esUiShared to have its own bundle */ export function plugin() { return new (class EsUiSharedPlugin { diff --git a/src/plugins/kibana_legacy/public/angular/angular_config.tsx b/src/plugins/kibana_legacy/public/angular/angular_config.tsx index 71cd57ef2d72ec..295cf27688c805 100644 --- a/src/plugins/kibana_legacy/public/angular/angular_config.tsx +++ b/src/plugins/kibana_legacy/public/angular/angular_config.tsx @@ -92,9 +92,9 @@ export const configureAppAngularModule = ( ) => { const core = 'core' in newPlatform ? newPlatform.core : newPlatform; const packageInfo = - 'injectedMetadata' in newPlatform - ? newPlatform.injectedMetadata.getLegacyMetadata() - : newPlatform.env.packageInfo; + 'env' in newPlatform + ? newPlatform.env.packageInfo + : newPlatform.injectedMetadata.getLegacyMetadata(); if ('injectedMetadata' in newPlatform) { forOwn(newPlatform.injectedMetadata.getInjectedVars(), (val, name) => { diff --git a/src/plugins/kibana_legacy/public/mocks.ts b/src/plugins/kibana_legacy/public/mocks.ts index 8e9a05b186191f..2fdd0d8b4be590 100644 --- a/src/plugins/kibana_legacy/public/mocks.ts +++ b/src/plugins/kibana_legacy/public/mocks.ts @@ -25,6 +25,7 @@ export type Start = jest.Mocked>; const createSetupContract = (): Setup => ({ forwardApp: jest.fn(), + registerLegacyAppAlias: jest.fn(), registerLegacyApp: jest.fn(), config: { defaultAppId: 'home', @@ -37,6 +38,7 @@ const createSetupContract = (): Setup => ({ const createStartContract = (): Start => ({ getApps: jest.fn(), + getLegacyAppAliases: jest.fn(), getForwards: jest.fn(), config: { defaultAppId: 'home', diff --git a/src/plugins/kibana_legacy/public/plugin.ts b/src/plugins/kibana_legacy/public/plugin.ts index 2ad620f355848a..831fc3f0d4a71f 100644 --- a/src/plugins/kibana_legacy/public/plugin.ts +++ b/src/plugins/kibana_legacy/public/plugin.ts @@ -28,12 +28,18 @@ import { Observable } from 'rxjs'; import { ConfigSchema } from '../config'; import { getDashboardConfig } from './dashboard_config'; -interface ForwardDefinition { +interface LegacyAppAliasDefinition { legacyAppId: string; newAppId: string; keepPrefix: boolean; } +interface ForwardDefinition { + legacyAppId: string; + newAppId: string; + rewritePath: (legacyPath: string) => string; +} + export type AngularRenderedAppUpdater = ( app: AppBase ) => Partial | undefined; @@ -54,7 +60,8 @@ export interface AngularRenderedApp extends App { export class KibanaLegacyPlugin { private apps: AngularRenderedApp[] = []; - private forwards: ForwardDefinition[] = []; + private legacyAppAliases: LegacyAppAliasDefinition[] = []; + private forwardDefinitions: ForwardDefinition[] = []; constructor(private readonly initializerContext: PluginInitializerContext) {} @@ -94,17 +101,55 @@ export class KibanaLegacyPlugin { * renaming or nesting plugins. For route changes after the prefix, please * use the routing mechanism of your app. * + * This method just redirects URLs within the legacy `kibana` app. + * * @param legacyAppId The name of the old app to forward URLs from * @param newAppId The name of the new app that handles the URLs now * @param options Whether the prefix of the old app is kept to nest the legacy * path into the new path */ - forwardApp: ( + registerLegacyAppAlias: ( legacyAppId: string, newAppId: string, options: { keepPrefix: boolean } = { keepPrefix: false } ) => { - this.forwards.push({ legacyAppId, newAppId, ...options }); + this.legacyAppAliases.push({ legacyAppId, newAppId, ...options }); + }, + + /** + * Forwards URLs within the legacy `kibana` app to a new platform application. + * + * @param legacyAppId The name of the old app to forward URLs from + * @param newAppId The name of the new app that handles the URLs now + * @param rewritePath Function to rewrite the legacy sub path of the app to the new path in the core app + * path into the new path + * + * Example usage: + * ``` + * kibanaLegacy.forwardApp( + * 'old', + * 'new', + * path => { + * const [, id] = /old/item\/(.*)$/.exec(path) || []; + * if (!id) { + * return '#/home'; + * } + * return '#/items/${id}'; + * } + * ); + * ``` + * This will cause the following redirects: + * + * * app/kibana#/old/ -> app/new#/home + * * app/kibana#/old/item/123 -> app/new#/items/123 + * + */ + forwardApp: ( + legacyAppId: string, + newAppId: string, + rewritePath: (legacyPath: string) => string + ) => { + this.forwardDefinitions.push({ legacyAppId, newAppId, rewritePath }); }, /** @@ -132,7 +177,12 @@ export class KibanaLegacyPlugin { * @deprecated * Just exported for wiring up with legacy platform, should not be used. */ - getForwards: () => this.forwards, + getLegacyAppAliases: () => this.legacyAppAliases, + /** + * @deprecated + * Just exported for wiring up with legacy platform, should not be used. + */ + getForwards: () => this.forwardDefinitions, config: this.initializerContext.config.get(), dashboardConfig: getDashboardConfig(!application.capabilities.dashboard.showWriteControls), }; diff --git a/src/plugins/kibana_react/public/index.ts b/src/plugins/kibana_react/public/index.ts index 9ad9f14ac5659d..9bec91b859ab77 100644 --- a/src/plugins/kibana_react/public/index.ts +++ b/src/plugins/kibana_react/public/index.ts @@ -25,7 +25,7 @@ export * from './ui_settings'; export * from './field_icon'; export * from './table_list_view'; export * from './split_panel'; -export { ValidatedDualRange } from './validated_range'; +export { ValidatedDualRange, Value } from './validated_range'; export * from './notifications'; export { Markdown, MarkdownSimple } from './markdown'; export { reactToUiComponent, uiToReactComponent } from './adapters'; diff --git a/src/plugins/kibana_react/public/validated_range/index.ts b/src/plugins/kibana_react/public/validated_range/index.ts index bc643373f5e603..7d720ec842a43e 100644 --- a/src/plugins/kibana_react/public/validated_range/index.ts +++ b/src/plugins/kibana_react/public/validated_range/index.ts @@ -17,4 +17,4 @@ * under the License. */ -export { ValidatedDualRange } from './validated_dual_range'; +export { ValidatedDualRange, Value } from './validated_dual_range'; diff --git a/src/plugins/kibana_utils/public/state_management/url/kbn_url_storage.test.ts b/src/plugins/kibana_utils/public/state_management/url/kbn_url_storage.test.ts index 6e4c505c62ebc8..513c70e60048a4 100644 --- a/src/plugins/kibana_utils/public/state_management/url/kbn_url_storage.test.ts +++ b/src/plugins/kibana_utils/public/state_management/url/kbn_url_storage.test.ts @@ -31,6 +31,7 @@ import { setStateToKbnUrl, getStateFromKbnUrl, } from './kbn_url_storage'; +import { ScopedHistory } from '../../../../../core/public'; describe('kbn_url_storage', () => { describe('getStateFromUrl & setStateToUrl', () => { @@ -187,23 +188,54 @@ describe('kbn_url_storage', () => { urlControls.update('/', true); }); - const getCurrentUrl = () => window.location.href; + const getCurrentUrl = () => history.createHref(history.location); it('should flush async url updates', async () => { const pr1 = urlControls.updateAsync(() => '/1', false); const pr2 = urlControls.updateAsync(() => '/2', false); const pr3 = urlControls.updateAsync(() => '/3', false); - expect(getCurrentUrl()).toBe('http://localhost/'); - expect(urlControls.flush()).toBe('http://localhost/3'); - expect(getCurrentUrl()).toBe('http://localhost/3'); + expect(getCurrentUrl()).toBe('/'); + expect(urlControls.flush()).toBe('/3'); + expect(getCurrentUrl()).toBe('/3'); + await Promise.all([pr1, pr2, pr3]); + expect(getCurrentUrl()).toBe('/3'); + }); + + it('flush() should return undefined, if no url updates happened', () => { + expect(urlControls.flush()).toBeUndefined(); + urlControls.updateAsync(() => '/1', false); + urlControls.updateAsync(() => '/', false); + expect(urlControls.flush()).toBeUndefined(); + }); + }); + + describe('urlControls - scoped history integration', () => { + let history: History; + let urlControls: IKbnUrlControls; + beforeEach(() => { + const parentHistory = createBrowserHistory(); + parentHistory.replace('/app/kibana/'); + history = new ScopedHistory(parentHistory, '/app/kibana/'); + urlControls = createKbnUrlControls(history); + }); + + const getCurrentUrl = () => history.createHref(history.location); + + it('should flush async url updates', async () => { + const pr1 = urlControls.updateAsync(() => '/app/kibana/1', false); + const pr2 = urlControls.updateAsync(() => '/app/kibana/2', false); + const pr3 = urlControls.updateAsync(() => '/app/kibana/3', false); + expect(getCurrentUrl()).toBe('/app/kibana/'); + expect(urlControls.flush()).toBe('/app/kibana/3'); + expect(getCurrentUrl()).toBe('/app/kibana/3'); await Promise.all([pr1, pr2, pr3]); - expect(getCurrentUrl()).toBe('http://localhost/3'); + expect(getCurrentUrl()).toBe('/app/kibana/3'); }); it('flush() should return undefined, if no url updates happened', () => { expect(urlControls.flush()).toBeUndefined(); - urlControls.updateAsync(() => 'http://localhost/1', false); - urlControls.updateAsync(() => 'http://localhost/', false); + urlControls.updateAsync(() => '/app/kibana/1', false); + urlControls.updateAsync(() => '/app/kibana/', false); expect(urlControls.flush()).toBeUndefined(); }); }); diff --git a/src/plugins/kibana_utils/public/state_management/url/kbn_url_storage.ts b/src/plugins/kibana_utils/public/state_management/url/kbn_url_storage.ts index 40a411d425a54f..337d122e2854be 100644 --- a/src/plugins/kibana_utils/public/state_management/url/kbn_url_storage.ts +++ b/src/plugins/kibana_utils/public/state_management/url/kbn_url_storage.ts @@ -154,7 +154,7 @@ export const createKbnUrlControls = ( let shouldReplace = true; function updateUrl(newUrl: string, replace = false): string | undefined { - const currentUrl = getCurrentUrl(); + const currentUrl = getCurrentUrl(history); if (newUrl === currentUrl) return undefined; // skip update const historyPath = getRelativeToHistoryPath(newUrl, history); @@ -165,7 +165,7 @@ export const createKbnUrlControls = ( history.push(historyPath); } - return getCurrentUrl(); + return getCurrentUrl(history); } // queue clean up @@ -187,7 +187,10 @@ export const createKbnUrlControls = ( function getPendingUrl() { if (updateQueue.length === 0) return undefined; - const resultUrl = updateQueue.reduce((url, nextUpdate) => nextUpdate(url), getCurrentUrl()); + const resultUrl = updateQueue.reduce( + (url, nextUpdate) => nextUpdate(url), + getCurrentUrl(history) + ); return resultUrl; } diff --git a/src/plugins/kibana_utils/public/state_management/url/kbn_url_tracker.ts b/src/plugins/kibana_utils/public/state_management/url/kbn_url_tracker.ts index af8811b1969e69..8adbbfb06e1edf 100644 --- a/src/plugins/kibana_utils/public/state_management/url/kbn_url_tracker.ts +++ b/src/plugins/kibana_utils/public/state_management/url/kbn_url_tracker.ts @@ -57,6 +57,7 @@ export function createKbnUrlTracker({ navLinkUpdater$, toastNotifications, history, + getHistory, storage, shouldTrackUrlUpdate = pathname => { const currentAppName = defaultSubUrl.slice(2); // cut hash and slash symbols @@ -103,6 +104,12 @@ export function createKbnUrlTracker({ * History object to use to track url changes. If this isn't provided, a local history instance will be created. */ history?: History; + + /** + * Lazily retrieve history instance + */ + getHistory?: () => History; + /** * Storage object to use to persist currently active url. If this isn't provided, the browser wide session storage instance will be used. */ @@ -158,7 +165,7 @@ export function createKbnUrlTracker({ function onMountApp() { unsubscribe(); - const historyInstance = history || createHashHistory(); + const historyInstance = history || (getHistory && getHistory()) || createHashHistory(); // track current hash when within app unsubscribeURLHistory = historyInstance.listen(location => { if (shouldTrackUrlUpdate(location.pathname)) { diff --git a/src/plugins/kibana_utils/public/state_management/url/parse.ts b/src/plugins/kibana_utils/public/state_management/url/parse.ts index 95041d0662f56d..6339002ea5c68b 100644 --- a/src/plugins/kibana_utils/public/state_management/url/parse.ts +++ b/src/plugins/kibana_utils/public/state_management/url/parse.ts @@ -18,12 +18,11 @@ */ import { parse as _parseUrl } from 'url'; +import { History } from 'history'; export const parseUrl = (url: string) => _parseUrl(url, true); export const parseUrlHash = (url: string) => { const hash = parseUrl(url).hash; return hash ? parseUrl(hash.slice(1)) : null; }; -export const getCurrentUrl = () => window.location.href; -export const parseCurrentUrl = () => parseUrl(getCurrentUrl()); -export const parseCurrentUrlHash = () => parseUrlHash(getCurrentUrl()); +export const getCurrentUrl = (history: History) => history.createHref(history.location); diff --git a/src/plugins/kibana_utils/public/state_sync/state_sync_state_storage/create_kbn_url_state_storage.test.ts b/src/plugins/kibana_utils/public/state_sync/state_sync_state_storage/create_kbn_url_state_storage.test.ts index cc3f1df7c1e00a..8a9a4ea71ee9ab 100644 --- a/src/plugins/kibana_utils/public/state_sync/state_sync_state_storage/create_kbn_url_state_storage.test.ts +++ b/src/plugins/kibana_utils/public/state_sync/state_sync_state_storage/create_kbn_url_state_storage.test.ts @@ -21,6 +21,7 @@ import { createKbnUrlStateStorage, IKbnUrlStateStorage } from './create_kbn_url_ import { History, createBrowserHistory } from 'history'; import { takeUntil, toArray } from 'rxjs/operators'; import { Subject } from 'rxjs'; +import { ScopedHistory } from '../../../../../core/public'; describe('KbnUrlStateStorage', () => { describe('useHash: false', () => { @@ -132,4 +133,78 @@ describe('KbnUrlStateStorage', () => { expect(await result).toEqual([{ test: 'test', ok: 1 }, { test: 'test', ok: 2 }, null]); }); }); + + describe('ScopedHistory integration', () => { + let urlStateStorage: IKbnUrlStateStorage; + let history: ScopedHistory; + const getCurrentUrl = () => history.createHref(history.location); + beforeEach(() => { + const parentHistory = createBrowserHistory(); + parentHistory.push('/kibana/app/'); + history = new ScopedHistory(parentHistory, '/kibana/app/'); + urlStateStorage = createKbnUrlStateStorage({ useHash: false, history }); + }); + + it('should persist state to url', async () => { + const state = { test: 'test', ok: 1 }; + const key = '_s'; + await urlStateStorage.set(key, state); + expect(getCurrentUrl()).toMatchInlineSnapshot(`"/kibana/app/#?_s=(ok:1,test:test)"`); + expect(urlStateStorage.get(key)).toEqual(state); + }); + + it('should flush state to url', () => { + const state = { test: 'test', ok: 1 }; + const key = '_s'; + urlStateStorage.set(key, state); + expect(getCurrentUrl()).toMatchInlineSnapshot(`"/kibana/app/"`); + expect(urlStateStorage.flush()).toBe(true); + expect(getCurrentUrl()).toMatchInlineSnapshot(`"/kibana/app/#?_s=(ok:1,test:test)"`); + expect(urlStateStorage.get(key)).toEqual(state); + + expect(urlStateStorage.flush()).toBe(false); // nothing to flush, not update + }); + + it('should cancel url updates', async () => { + const state = { test: 'test', ok: 1 }; + const key = '_s'; + const pr = urlStateStorage.set(key, state); + expect(getCurrentUrl()).toMatchInlineSnapshot(`"/kibana/app/"`); + urlStateStorage.cancel(); + await pr; + expect(getCurrentUrl()).toMatchInlineSnapshot(`"/kibana/app/"`); + expect(urlStateStorage.get(key)).toEqual(null); + }); + + it('should cancel url updates if synchronously returned to the same state', async () => { + const state1 = { test: 'test', ok: 1 }; + const state2 = { test: 'test', ok: 2 }; + const key = '_s'; + const pr1 = urlStateStorage.set(key, state1); + await pr1; + const historyLength = history.length; + const pr2 = urlStateStorage.set(key, state2); + const pr3 = urlStateStorage.set(key, state1); + await Promise.all([pr2, pr3]); + expect(history.length).toBe(historyLength); + }); + + it('should notify about url changes', async () => { + expect(urlStateStorage.change$).toBeDefined(); + const key = '_s'; + const destroy$ = new Subject(); + const result = urlStateStorage.change$!(key) + .pipe(takeUntil(destroy$), toArray()) + .toPromise(); + + history.push(`/#?${key}=(ok:1,test:test)`); + history.push(`/?query=test#?${key}=(ok:2,test:test)&some=test`); + history.push(`/?query=test#?some=test`); + + destroy$.next(); + destroy$.complete(); + + expect(await result).toEqual([{ test: 'test', ok: 1 }, { test: 'test', ok: 2 }, null]); + }); + }); }); diff --git a/src/plugins/management/public/management_service.test.ts b/src/plugins/management/public/management_service.test.ts index ceb91837921eb5..18569ef285ff3a 100644 --- a/src/plugins/management/public/management_service.test.ts +++ b/src/plugins/management/public/management_service.test.ts @@ -29,9 +29,8 @@ test('Provides default sections', () => { () => {}, coreMock.createSetup().getStartServices ); - expect(service.getAllSections().length).toEqual(3); + expect(service.getAllSections().length).toEqual(2); expect(service.getSection('kibana')).not.toBeUndefined(); - expect(service.getSection('logstash')).not.toBeUndefined(); expect(service.getSection('elasticsearch')).not.toBeUndefined(); }); diff --git a/src/plugins/management/public/management_service.ts b/src/plugins/management/public/management_service.ts index ed31a22992da85..8fc207e32e6ce7 100644 --- a/src/plugins/management/public/management_service.ts +++ b/src/plugins/management/public/management_service.ts @@ -80,7 +80,6 @@ export class ManagementService { ); register({ id: 'kibana', title: 'Kibana', order: 30, euiIconType: 'logoKibana' }); - register({ id: 'logstash', title: 'Logstash', order: 30, euiIconType: 'logoLogstash' }); register({ id: 'elasticsearch', title: 'Elasticsearch', diff --git a/src/plugins/telemetry/server/config.ts b/src/plugins/telemetry/server/config.ts index 9621a8b5619b2b..99dde0c3b3d966 100644 --- a/src/plugins/telemetry/server/config.ts +++ b/src/plugins/telemetry/server/config.ts @@ -36,8 +36,8 @@ export const configSchema = schema.object({ config: schema.string({ defaultValue: getConfigPath() }), banner: schema.boolean({ defaultValue: true }), url: schema.conditional( - schema.contextRef('dev'), - schema.literal(true), + schema.contextRef('dist'), + schema.literal(false), // Point to staging if it's not a distributable release schema.string({ defaultValue: `https://telemetry-staging.elastic.co/xpack/${ENDPOINT_VERSION}/send`, }), @@ -46,8 +46,8 @@ export const configSchema = schema.object({ }) ), optInStatusUrl: schema.conditional( - schema.contextRef('dev'), - schema.literal(true), + schema.contextRef('dist'), + schema.literal(false), // Point to staging if it's not a distributable release schema.string({ defaultValue: `https://telemetry-staging.elastic.co/opt_in_status/${ENDPOINT_VERSION}/send`, }), diff --git a/src/plugins/telemetry_collection_manager/server/encryption/encrypt.test.ts b/src/plugins/telemetry_collection_manager/server/encryption/encrypt.test.ts index c04625eb1dd427..6d64268569e06b 100644 --- a/src/plugins/telemetry_collection_manager/server/encryption/encrypt.test.ts +++ b/src/plugins/telemetry_collection_manager/server/encryption/encrypt.test.ts @@ -22,14 +22,14 @@ import { encryptTelemetry, getKID } from './encrypt'; describe('getKID', () => { it(`returns 'kibana_dev' kid for development`, async () => { - const isProd = false; - const kid = getKID(isProd); + const useProdKey = false; + const kid = getKID(useProdKey); expect(kid).toBe('kibana_dev'); }); it(`returns 'kibana_prod' kid for development`, async () => { - const isProd = true; - const kid = getKID(isProd); + const useProdKey = true; + const kid = getKID(useProdKey); expect(kid).toBe('kibana'); }); }); @@ -41,19 +41,19 @@ describe('encryptTelemetry', () => { it('encrypts payload', async () => { const payload = { some: 'value' }; - await encryptTelemetry(payload, { isProd: true }); + await encryptTelemetry(payload, { useProdKey: true }); expect(createRequestEncryptor).toBeCalledWith(telemetryJWKS); }); - it('uses kibana kid on { isProd: true }', async () => { + it('uses kibana kid on { useProdKey: true }', async () => { const payload = { some: 'value' }; - await encryptTelemetry(payload, { isProd: true }); + await encryptTelemetry(payload, { useProdKey: true }); expect(mockEncrypt).toBeCalledWith('kibana', payload); }); - it('uses kibana_dev kid on { isProd: false }', async () => { + it('uses kibana_dev kid on { useProdKey: false }', async () => { const payload = { some: 'value' }; - await encryptTelemetry(payload, { isProd: false }); + await encryptTelemetry(payload, { useProdKey: false }); expect(mockEncrypt).toBeCalledWith('kibana_dev', payload); }); }); diff --git a/src/plugins/telemetry_collection_manager/server/encryption/encrypt.ts b/src/plugins/telemetry_collection_manager/server/encryption/encrypt.ts index 44f053064cfcbd..89f34d794f0593 100644 --- a/src/plugins/telemetry_collection_manager/server/encryption/encrypt.ts +++ b/src/plugins/telemetry_collection_manager/server/encryption/encrypt.ts @@ -20,12 +20,15 @@ import { createRequestEncryptor } from '@elastic/request-crypto'; import { telemetryJWKS } from './telemetry_jwks'; -export function getKID(isProd = false): string { - return isProd ? 'kibana' : 'kibana_dev'; +export function getKID(useProdKey = false): string { + return useProdKey ? 'kibana' : 'kibana_dev'; } -export async function encryptTelemetry(payload: any, { isProd = false } = {}): Promise { - const kid = getKID(isProd); +export async function encryptTelemetry( + payload: any, + { useProdKey = false } = {} +): Promise { + const kid = getKID(useProdKey); const encryptor = await createRequestEncryptor(telemetryJWKS); const clusters = [].concat(payload); return Promise.all(clusters.map((cluster: any) => encryptor.encrypt(kid, cluster))); diff --git a/src/plugins/telemetry_collection_manager/server/plugin.ts b/src/plugins/telemetry_collection_manager/server/plugin.ts index f2f20e215c5351..0b57fae83c0fb4 100644 --- a/src/plugins/telemetry_collection_manager/server/plugin.ts +++ b/src/plugins/telemetry_collection_manager/server/plugin.ts @@ -50,12 +50,12 @@ export class TelemetryCollectionManagerPlugin private readonly collections: Array> = []; private usageGetterMethodPriority = -1; private usageCollection?: UsageCollectionSetup; - private readonly isDev: boolean; + private readonly isDistributable: boolean; private readonly version: string; constructor(initializerContext: PluginInitializerContext) { this.logger = initializerContext.logger.get(); - this.isDev = initializerContext.env.mode.dev; + this.isDistributable = initializerContext.env.packageInfo.dist; this.version = initializerContext.env.packageInfo.version; } @@ -158,7 +158,7 @@ export class TelemetryCollectionManagerPlugin if (config.unencrypted) { return optInStats; } - return encryptTelemetry(optInStats, { isProd: !this.isDev }); + return encryptTelemetry(optInStats, { useProdKey: this.isDistributable }); } } catch (err) { this.logger.debug(`Failed to collect any opt in stats with registered collections.`); @@ -176,7 +176,6 @@ export class TelemetryCollectionManagerPlugin ) => { const context: StatsCollectionContext = { logger: this.logger.get(collection.title), - isDev: this.isDev, version: this.version, ...collection.customContext, }; @@ -206,7 +205,7 @@ export class TelemetryCollectionManagerPlugin return usageData; } - return encryptTelemetry(usageData, { isProd: !this.isDev }); + return encryptTelemetry(usageData, { useProdKey: this.isDistributable }); } } catch (err) { this.logger.debug( @@ -225,7 +224,6 @@ export class TelemetryCollectionManagerPlugin ): Promise { const context: StatsCollectionContext = { logger: this.logger.get(collection.title), - isDev: this.isDev, version: this.version, ...collection.customContext, }; diff --git a/src/plugins/telemetry_collection_manager/server/types.ts b/src/plugins/telemetry_collection_manager/server/types.ts index e23d6a4c388f41..d3a47694d38a76 100644 --- a/src/plugins/telemetry_collection_manager/server/types.ts +++ b/src/plugins/telemetry_collection_manager/server/types.ts @@ -101,7 +101,6 @@ export interface ESLicense { export interface StatsCollectionContext { logger: Logger; - isDev: boolean; version: string; } diff --git a/src/plugins/vis_default_editor/public/components/agg_params_map.ts b/src/plugins/vis_default_editor/public/components/agg_params_map.ts index 5af3cfc5b09289..9bc3146b9903bb 100644 --- a/src/plugins/vis_default_editor/public/components/agg_params_map.ts +++ b/src/plugins/vis_default_editor/public/components/agg_params_map.ts @@ -58,6 +58,8 @@ const buckets = { size: controls.SizeParamEditor, }, [BUCKET_TYPES.TERMS]: { + include: controls.IncludeExcludeParamEditor, + exclude: controls.IncludeExcludeParamEditor, orderBy: controls.OrderByParamEditor, orderAgg: controls.OrderAggParamEditor, order: wrapWithInlineComp(controls.OrderParamEditor), diff --git a/src/plugins/vis_default_editor/public/components/controls/components/number_list/utils.ts b/src/plugins/vis_default_editor/public/components/controls/components/number_list/utils.ts index c2ac63c98cbea0..ebe348b0507bc5 100644 --- a/src/plugins/vis_default_editor/public/components/controls/components/number_list/utils.ts +++ b/src/plugins/vis_default_editor/public/components/controls/components/number_list/utils.ts @@ -119,7 +119,7 @@ function getNextModel(list: NumberRowModel[], range: NumberListRange): NumberRow }; } -function getInitModelList(list: Array): NumberRowModel[] { +function getInitModelList(list: Array): NumberRowModel[] { return list.length ? list.map(num => ({ value: (num === undefined ? EMPTY_STRING : num) as NumberRowModel['value'], diff --git a/src/plugins/vis_default_editor/public/components/controls/components/simple_number_list.tsx b/src/plugins/vis_default_editor/public/components/controls/components/simple_number_list.tsx new file mode 100644 index 00000000000000..becf8e47ef5736 --- /dev/null +++ b/src/plugins/vis_default_editor/public/components/controls/components/simple_number_list.tsx @@ -0,0 +1,140 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { Fragment, useCallback, useEffect, useMemo, useState } from 'react'; +import { isArray } from 'lodash'; +import { EuiButtonEmpty, EuiFlexItem, EuiFormRow, EuiSpacer, htmlIdGenerator } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EMPTY_STRING, getInitModelList, getRange, parse } from './number_list/utils'; +import { NumberRow, NumberRowModel } from './number_list/number_row'; +import { AggParamEditorProps } from '../../agg_param_props'; + +const generateId = htmlIdGenerator(); + +function SimpleNumberList({ + agg, + aggParam, + value, + setValue, + setTouched, +}: AggParamEditorProps>) { + const [numbers, setNumbers] = useState( + getInitModelList(value && isArray(value) ? value : [EMPTY_STRING]) + ); + const numberRange = useMemo(() => getRange('[-Infinity,Infinity]'), []); + + // This useEffect is needed to discard changes, it sets numbers a mapped value if they are different + useEffect(() => { + if ( + isArray(value) && + (value.length !== numbers.length || + !value.every((numberValue, index) => numberValue === numbers[index].value)) + ) { + setNumbers( + value.map(numberValue => ({ + id: generateId(), + value: numberValue, + isInvalid: false, + })) + ); + } + }, [numbers, value]); + + const onUpdate = useCallback( + (numberList: NumberRowModel[]) => { + setNumbers(numberList); + setValue(numberList.map(({ value: numberValue }) => numberValue)); + }, + [setValue] + ); + + const onChangeValue = useCallback( + (numberField: { id: string; value: string }) => { + onUpdate( + numbers.map(number => + number.id === numberField.id + ? { + id: numberField.id, + value: parse(numberField.value), + isInvalid: false, + } + : number + ) + ); + }, + [numbers, onUpdate] + ); + + // Add an item to the end of the list + const onAdd = useCallback(() => { + const newArray = [ + ...numbers, + { + id: generateId(), + value: EMPTY_STRING as '', + isInvalid: false, + }, + ]; + onUpdate(newArray); + }, [numbers, onUpdate]); + + const onDelete = useCallback( + (id: string) => onUpdate(numbers.filter(number => number.id !== id)), + [numbers, onUpdate] + ); + + return ( + + <> + {numbers.map((number, arrayIndex) => ( + + + {numbers.length - 1 !== arrayIndex && } + + ))} + + + + + + + + + ); +} + +export { SimpleNumberList }; diff --git a/src/plugins/vis_default_editor/public/components/controls/include_exclude.tsx b/src/plugins/vis_default_editor/public/components/controls/include_exclude.tsx new file mode 100644 index 00000000000000..f60f6ce7ce249b --- /dev/null +++ b/src/plugins/vis_default_editor/public/components/controls/include_exclude.tsx @@ -0,0 +1,49 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useEffect } from 'react'; +import { AggParamEditorProps } from '../agg_param_props'; +import { StringParamEditor } from './string'; +import { search } from '../../../../data/public'; +import { SimpleNumberList } from './components/simple_number_list'; +const { isNumberType } = search.aggs; + +export function IncludeExcludeParamEditor(props: AggParamEditorProps>) { + const { agg, value, setValue } = props; + const isAggOfNumberType = isNumberType(agg); + + // This useEffect converts value from string type to number and back when the field type is changed + useEffect(() => { + if (isAggOfNumberType && !Array.isArray(value) && value !== undefined) { + const numberArray = value + .split('|') + .map(item => parseFloat(item)) + .filter(number => Number.isFinite(number)); + setValue(numberArray.length ? numberArray : ['']); + } else if (!isAggOfNumberType && Array.isArray(value) && value !== undefined) { + setValue(value.filter(item => item !== '').join('|')); + } + }, [isAggOfNumberType, setValue, value]); + + return isAggOfNumberType ? ( + } /> + ) : ( + + ); +} diff --git a/src/plugins/vis_default_editor/public/components/controls/index.ts b/src/plugins/vis_default_editor/public/components/controls/index.ts index e8944aa667853f..cfb236e5e22e37 100644 --- a/src/plugins/vis_default_editor/public/components/controls/index.ts +++ b/src/plugins/vis_default_editor/public/components/controls/index.ts @@ -24,6 +24,7 @@ export { ExtendedBoundsParamEditor } from './extended_bounds'; export { FieldParamEditor } from './field'; export { FiltersParamEditor } from './filters'; export { HasExtendedBoundsParamEditor } from './has_extended_bounds'; +export { IncludeExcludeParamEditor } from './include_exclude'; export { IpRangesParamEditor } from './ip_ranges'; export { IpRangeTypeParamEditor } from './ip_range_type'; export { IsFilteredByCollarParamEditor } from './is_filtered_by_collar'; diff --git a/src/plugins/data/public/search/search_strategy/index.ts b/src/plugins/vis_type_table/config.ts similarity index 79% rename from src/plugins/data/public/search/search_strategy/index.ts rename to src/plugins/vis_type_table/config.ts index e3de2ea46e3eca..6749bd83de39f9 100644 --- a/src/plugins/data/public/search/search_strategy/index.ts +++ b/src/plugins/vis_type_table/config.ts @@ -17,8 +17,10 @@ * under the License. */ -export { SearchError, getSearchErrorType } from './search_error'; +import { schema, TypeOf } from '@kbn/config-schema'; -export { SearchStrategyProvider, SearchStrategySearchParams } from './types'; +export const configSchema = schema.object({ + enabled: schema.boolean({ defaultValue: true }), +}); -export { defaultSearchStrategy } from './default_search_strategy'; +export type ConfigSchema = TypeOf; diff --git a/src/plugins/vis_type_table/kibana.json b/src/plugins/vis_type_table/kibana.json new file mode 100644 index 00000000000000..bb0f6478a42408 --- /dev/null +++ b/src/plugins/vis_type_table/kibana.json @@ -0,0 +1,11 @@ +{ + "id": "visTypeTable", + "version": "kibana", + "server": true, + "ui": true, + "requiredPlugins": [ + "expressions", + "visualizations", + "data" + ] +} diff --git a/src/legacy/core_plugins/vis_type_table/public/__snapshots__/table_vis_fn.test.ts.snap b/src/plugins/vis_type_table/public/__snapshots__/table_vis_fn.test.ts.snap similarity index 100% rename from src/legacy/core_plugins/vis_type_table/public/__snapshots__/table_vis_fn.test.ts.snap rename to src/plugins/vis_type_table/public/__snapshots__/table_vis_fn.test.ts.snap diff --git a/src/legacy/core_plugins/vis_type_table/public/_table_vis.scss b/src/plugins/vis_type_table/public/_table_vis.scss similarity index 100% rename from src/legacy/core_plugins/vis_type_table/public/_table_vis.scss rename to src/plugins/vis_type_table/public/_table_vis.scss diff --git a/src/legacy/core_plugins/vis_type_table/public/agg_table/_agg_table.scss b/src/plugins/vis_type_table/public/agg_table/_agg_table.scss similarity index 100% rename from src/legacy/core_plugins/vis_type_table/public/agg_table/_agg_table.scss rename to src/plugins/vis_type_table/public/agg_table/_agg_table.scss diff --git a/src/plugins/vis_type_table/public/agg_table/_index.scss b/src/plugins/vis_type_table/public/agg_table/_index.scss new file mode 100644 index 00000000000000..340e08a76f1bdb --- /dev/null +++ b/src/plugins/vis_type_table/public/agg_table/_index.scss @@ -0,0 +1 @@ +@import './agg_table'; diff --git a/src/legacy/core_plugins/vis_type_table/public/agg_table/agg_table.html b/src/plugins/vis_type_table/public/agg_table/agg_table.html similarity index 100% rename from src/legacy/core_plugins/vis_type_table/public/agg_table/agg_table.html rename to src/plugins/vis_type_table/public/agg_table/agg_table.html diff --git a/src/legacy/core_plugins/vis_type_table/public/agg_table/agg_table.js b/src/plugins/vis_type_table/public/agg_table/agg_table.js similarity index 98% rename from src/legacy/core_plugins/vis_type_table/public/agg_table/agg_table.js rename to src/plugins/vis_type_table/public/agg_table/agg_table.js index b9e79f96e4fc13..0cd501e2d0344c 100644 --- a/src/legacy/core_plugins/vis_type_table/public/agg_table/agg_table.js +++ b/src/plugins/vis_type_table/public/agg_table/agg_table.js @@ -238,9 +238,9 @@ export function KbnAggTable(config, RecursionHelper) { } /** - * @param {[]Object} columns - the formatted columns that will be displayed + * @param {Object[]} columns - the formatted columns that will be displayed * @param {String} title - the title of the column to add to - * @param {[]Object} rows - the row data for the columns + * @param {Object[]} rows - the row data for the columns * @param {Number} insertAtIndex - the index to insert the percentage column at * @returns {Object} - cols and rows for the table to render now included percentage column(s) */ diff --git a/src/legacy/core_plugins/vis_type_table/public/agg_table/agg_table_group.html b/src/plugins/vis_type_table/public/agg_table/agg_table_group.html similarity index 100% rename from src/legacy/core_plugins/vis_type_table/public/agg_table/agg_table_group.html rename to src/plugins/vis_type_table/public/agg_table/agg_table_group.html diff --git a/src/legacy/core_plugins/vis_type_table/public/agg_table/agg_table_group.js b/src/plugins/vis_type_table/public/agg_table/agg_table_group.js similarity index 100% rename from src/legacy/core_plugins/vis_type_table/public/agg_table/agg_table_group.js rename to src/plugins/vis_type_table/public/agg_table/agg_table_group.js diff --git a/src/legacy/core_plugins/vis_type_table/public/components/table_vis_options.tsx b/src/plugins/vis_type_table/public/components/table_vis_options.tsx similarity index 96% rename from src/legacy/core_plugins/vis_type_table/public/components/table_vis_options.tsx rename to src/plugins/vis_type_table/public/components/table_vis_options.tsx index 265528f33f9cd0..68348d5ef10604 100644 --- a/src/legacy/core_plugins/vis_type_table/public/components/table_vis_options.tsx +++ b/src/plugins/vis_type_table/public/components/table_vis_options.tsx @@ -24,12 +24,8 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { VisOptionsProps } from 'src/plugins/vis_default_editor/public'; -import { search } from '../../../../../plugins/data/public'; -import { - SwitchOption, - SelectOption, - NumberInputOption, -} from '../../../../../plugins/charts/public'; +import { search } from '../../../data/public'; +import { SwitchOption, SelectOption, NumberInputOption } from '../../../charts/public'; import { TableVisParams } from '../types'; import { totalAggregations } from './utils'; diff --git a/src/legacy/core_plugins/vis_type_table/public/components/utils.ts b/src/plugins/vis_type_table/public/components/utils.ts similarity index 100% rename from src/legacy/core_plugins/vis_type_table/public/components/utils.ts rename to src/plugins/vis_type_table/public/components/utils.ts diff --git a/src/legacy/core_plugins/vis_type_table/public/get_inner_angular.ts b/src/plugins/vis_type_table/public/get_inner_angular.ts similarity index 91% rename from src/legacy/core_plugins/vis_type_table/public/get_inner_angular.ts rename to src/plugins/vis_type_table/public/get_inner_angular.ts index 6208e358b4184f..d69b9bba31b032 100644 --- a/src/legacy/core_plugins/vis_type_table/public/get_inner_angular.ts +++ b/src/plugins/vis_type_table/public/get_inner_angular.ts @@ -23,7 +23,7 @@ import angular from 'angular'; import 'angular-recursion'; import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular'; -import { CoreStart, LegacyCoreStart, IUiSettingsClient } from 'kibana/public'; +import { CoreStart, IUiSettingsClient, PluginInitializerContext } from 'kibana/public'; import { initAngularBootstrap, PaginateDirectiveProvider, @@ -32,15 +32,15 @@ import { watchMultiDecorator, KbnAccessibleClickProvider, configureAppAngularModule, -} from '../../../../plugins/kibana_legacy/public'; +} from '../../kibana_legacy/public'; initAngularBootstrap(); const thirdPartyAngularDependencies = ['ngSanitize', 'ui.bootstrap', 'RecursionHelper']; -export function getAngularModule(name: string, core: CoreStart) { +export function getAngularModule(name: string, core: CoreStart, context: PluginInitializerContext) { const uiModule = getInnerAngular(name, core); - configureAppAngularModule(uiModule, core as LegacyCoreStart, true); + configureAppAngularModule(uiModule, { core, env: context.env }, true); return uiModule; } diff --git a/src/legacy/core_plugins/vis_type_table/public/index.scss b/src/plugins/vis_type_table/public/index.scss similarity index 61% rename from src/legacy/core_plugins/vis_type_table/public/index.scss rename to src/plugins/vis_type_table/public/index.scss index 54124ebc42620b..0972c85e0dbe03 100644 --- a/src/legacy/core_plugins/vis_type_table/public/index.scss +++ b/src/plugins/vis_type_table/public/index.scss @@ -1,5 +1,3 @@ -@import 'src/legacy/ui/public/styles/styling_constants'; - // Prefix all styles with "tbv" to avoid conflicts. // Examples // tbvChart @@ -7,6 +5,6 @@ // tbvChart__legend--small // tbvChart__legend-isLoading -@import 'agg_table/index'; -@import 'paginated_table/index'; +@import './agg_table/index'; +@import './paginated_table/index'; @import './table_vis'; diff --git a/src/legacy/core_plugins/vis_type_table/public/index.ts b/src/plugins/vis_type_table/public/index.ts similarity index 92% rename from src/legacy/core_plugins/vis_type_table/public/index.ts rename to src/plugins/vis_type_table/public/index.ts index efbaf69659ea29..5621fdb0947724 100644 --- a/src/legacy/core_plugins/vis_type_table/public/index.ts +++ b/src/plugins/vis_type_table/public/index.ts @@ -16,8 +16,8 @@ * specific language governing permissions and limitations * under the License. */ - -import { PluginInitializerContext } from '../../../../core/public'; +import './index.scss'; +import { PluginInitializerContext } from 'kibana/public'; import { TableVisPlugin as Plugin } from './plugin'; export function plugin(initializerContext: PluginInitializerContext) { diff --git a/src/plugins/vis_type_table/public/paginated_table/_index.scss b/src/plugins/vis_type_table/public/paginated_table/_index.scss new file mode 100644 index 00000000000000..23d56c09b2818a --- /dev/null +++ b/src/plugins/vis_type_table/public/paginated_table/_index.scss @@ -0,0 +1 @@ +@import './_table_cell_filter'; diff --git a/src/legacy/core_plugins/vis_type_table/public/paginated_table/_table_cell_filter.scss b/src/plugins/vis_type_table/public/paginated_table/_table_cell_filter.scss similarity index 100% rename from src/legacy/core_plugins/vis_type_table/public/paginated_table/_table_cell_filter.scss rename to src/plugins/vis_type_table/public/paginated_table/_table_cell_filter.scss diff --git a/src/legacy/core_plugins/vis_type_table/public/paginated_table/paginated_table.html b/src/plugins/vis_type_table/public/paginated_table/paginated_table.html similarity index 100% rename from src/legacy/core_plugins/vis_type_table/public/paginated_table/paginated_table.html rename to src/plugins/vis_type_table/public/paginated_table/paginated_table.html diff --git a/src/legacy/core_plugins/vis_type_table/public/paginated_table/paginated_table.js b/src/plugins/vis_type_table/public/paginated_table/paginated_table.js similarity index 100% rename from src/legacy/core_plugins/vis_type_table/public/paginated_table/paginated_table.js rename to src/plugins/vis_type_table/public/paginated_table/paginated_table.js diff --git a/src/legacy/core_plugins/vis_type_table/public/paginated_table/paginated_table.test.ts b/src/plugins/vis_type_table/public/paginated_table/paginated_table.test.ts similarity index 98% rename from src/legacy/core_plugins/vis_type_table/public/paginated_table/paginated_table.test.ts rename to src/plugins/vis_type_table/public/paginated_table/paginated_table.test.ts index 7352236f03febf..23e4aee0378dc6 100644 --- a/src/legacy/core_plugins/vis_type_table/public/paginated_table/paginated_table.test.ts +++ b/src/plugins/vis_type_table/public/paginated_table/paginated_table.test.ts @@ -25,10 +25,9 @@ import 'angular-mocks'; import { getAngularModule } from '../get_inner_angular'; import { initTableVisLegacyModule } from '../table_vis_legacy_module'; -import { coreMock } from '../../../../../core/public/mocks'; +import { coreMock } from '../../../../core/public/mocks'; -jest.mock('ui/new_platform'); -jest.mock('../../../../../plugins/kibana_legacy/public/angular/angular_config', () => ({ +jest.mock('../../../kibana_legacy/public/angular/angular_config', () => ({ configureAppAngularModule: () => {}, })); @@ -73,7 +72,11 @@ describe('Table Vis - Paginated table', () => { let paginatedTable: any; const initLocalAngular = () => { - const tableVisModule = getAngularModule('kibana/table_vis', coreMock.createStart()); + const tableVisModule = getAngularModule( + 'kibana/table_vis', + coreMock.createStart(), + coreMock.createPluginInitializerContext() + ); initTableVisLegacyModule(tableVisModule); }; diff --git a/src/legacy/core_plugins/vis_type_table/public/paginated_table/rows.js b/src/plugins/vis_type_table/public/paginated_table/rows.js similarity index 100% rename from src/legacy/core_plugins/vis_type_table/public/paginated_table/rows.js rename to src/plugins/vis_type_table/public/paginated_table/rows.js diff --git a/src/legacy/core_plugins/vis_type_table/public/paginated_table/table_cell_filter.html b/src/plugins/vis_type_table/public/paginated_table/table_cell_filter.html similarity index 100% rename from src/legacy/core_plugins/vis_type_table/public/paginated_table/table_cell_filter.html rename to src/plugins/vis_type_table/public/paginated_table/table_cell_filter.html diff --git a/src/legacy/core_plugins/vis_type_table/public/plugin.ts b/src/plugins/vis_type_table/public/plugin.ts similarity index 80% rename from src/legacy/core_plugins/vis_type_table/public/plugin.ts rename to src/plugins/vis_type_table/public/plugin.ts index ea12a5320a14d4..a41d939523bcca 100644 --- a/src/legacy/core_plugins/vis_type_table/public/plugin.ts +++ b/src/plugins/vis_type_table/public/plugin.ts @@ -16,14 +16,13 @@ * specific language governing permissions and limitations * under the License. */ -import { Plugin as ExpressionsPublicPlugin } from '../../../../plugins/expressions/public'; -import { VisualizationsSetup } from '../../../../plugins/visualizations/public'; - -import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from '../../../../core/public'; +import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'kibana/public'; +import { Plugin as ExpressionsPublicPlugin } from '../../expressions/public'; +import { VisualizationsSetup } from '../../visualizations/public'; import { createTableVisFn } from './table_vis_fn'; -import { tableVisTypeDefinition } from './table_vis_type'; -import { DataPublicPluginStart } from '../../../../plugins/data/public'; +import { getTableVisTypeDefinition } from './table_vis_type'; +import { DataPublicPluginStart } from '../../data/public'; import { setFormatService } from './services'; /** @internal */ @@ -40,6 +39,7 @@ export interface TablePluginStartDependencies { /** @internal */ export class TableVisPlugin implements Plugin, void> { initializerContext: PluginInitializerContext; + createBaseVisualization: any; constructor(initializerContext: PluginInitializerContext) { this.initializerContext = initializerContext; @@ -50,8 +50,9 @@ export class TableVisPlugin implements Plugin, void> { { expressions, visualizations }: TablePluginSetupDependencies ) { expressions.registerFunction(createTableVisFn); - - visualizations.createBaseVisualization(tableVisTypeDefinition); + visualizations.createBaseVisualization( + getTableVisTypeDefinition(core, this.initializerContext) + ); } public start(core: CoreStart, { data }: TablePluginStartDependencies) { diff --git a/src/legacy/core_plugins/vis_type_table/public/services.ts b/src/plugins/vis_type_table/public/services.ts similarity index 86% rename from src/legacy/core_plugins/vis_type_table/public/services.ts rename to src/plugins/vis_type_table/public/services.ts index b4b491ac7a5552..3aaffe75e27f14 100644 --- a/src/legacy/core_plugins/vis_type_table/public/services.ts +++ b/src/plugins/vis_type_table/public/services.ts @@ -17,8 +17,8 @@ * under the License. */ -import { createGetterSetter } from '../../../../plugins/kibana_utils/public'; -import { DataPublicPluginStart } from '../../../../plugins/data/public'; +import { createGetterSetter } from '../../kibana_utils/public'; +import { DataPublicPluginStart } from '../../data/public'; export const [getFormatService, setFormatService] = createGetterSetter< DataPublicPluginStart['fieldFormats'] diff --git a/src/legacy/core_plugins/vis_type_table/public/table_vis.html b/src/plugins/vis_type_table/public/table_vis.html similarity index 100% rename from src/legacy/core_plugins/vis_type_table/public/table_vis.html rename to src/plugins/vis_type_table/public/table_vis.html diff --git a/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.js b/src/plugins/vis_type_table/public/table_vis_controller.js similarity index 100% rename from src/legacy/core_plugins/vis_type_table/public/table_vis_controller.js rename to src/plugins/vis_type_table/public/table_vis_controller.js diff --git a/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts b/src/plugins/vis_type_table/public/table_vis_controller.test.ts similarity index 89% rename from src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts rename to src/plugins/vis_type_table/public/table_vis_controller.test.ts index 8d6f88bf8dd4af..4607324ca150c6 100644 --- a/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts +++ b/src/plugins/vis_type_table/public/table_vis_controller.test.ts @@ -26,24 +26,23 @@ import $ from 'jquery'; import StubIndexPattern from 'test_utils/stub_index_pattern'; import { getAngularModule } from './get_inner_angular'; import { initTableVisLegacyModule } from './table_vis_legacy_module'; -import { tableVisTypeDefinition } from './table_vis_type'; -import { Vis } from '../../../../plugins/visualizations/public'; +import { getTableVisTypeDefinition } from './table_vis_type'; +import { Vis } from '../../visualizations/public'; // eslint-disable-next-line -import { stubFields } from '../../../../plugins/data/public/stubs'; +import { stubFields } from '../../data/public/stubs'; // eslint-disable-next-line import { tableVisResponseHandler } from './table_vis_response_handler'; -import { coreMock } from '../../../../core/public/mocks'; +import { coreMock } from '../../../core/public/mocks'; +import { IAggConfig, search } from '../../data/public'; +// TODO: remove linting disable // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { npStart } from './legacy_imports'; -import { IAggConfig, search } from '../../../../plugins/data/public'; +import { searchStartMock } from '../../data/public/search/mocks'; -// should be mocked once get rid of 'ui/new_platform' legacy imports -const { createAggConfigs } = npStart.plugins.data.search.aggs; +const { createAggConfigs } = searchStartMock.aggs; const { tabifyAggResponse } = search; -jest.mock('ui/new_platform'); -jest.mock('../../../../plugins/kibana_legacy/public/angular/angular_config', () => ({ +jest.mock('../../kibana_legacy/public/angular/angular_config', () => ({ configureAppAngularModule: () => {}, })); @@ -89,7 +88,11 @@ describe('Table Vis - Controller', () => { let stubIndexPattern: any; const initLocalAngular = () => { - const tableVisModule = getAngularModule('kibana/table_vis', coreMock.createStart()); + const tableVisModule = getAngularModule( + 'kibana/table_vis', + coreMock.createStart(), + coreMock.createPluginInitializerContext() + ); initTableVisLegacyModule(tableVisModule); }; @@ -110,9 +113,13 @@ describe('Table Vis - Controller', () => { (cfg: any) => cfg, 'time', stubFields, - coreMock.createStart() + coreMock.createSetup() ); }); + const tableVisTypeDefinition = getTableVisTypeDefinition( + coreMock.createSetup(), + coreMock.createPluginInitializerContext() + ); function getRangeVis(params?: object) { return ({ diff --git a/src/legacy/core_plugins/vis_type_table/public/table_vis_fn.test.ts b/src/plugins/vis_type_table/public/table_vis_fn.test.ts similarity index 95% rename from src/legacy/core_plugins/vis_type_table/public/table_vis_fn.test.ts rename to src/plugins/vis_type_table/public/table_vis_fn.test.ts index 36392c10f93f32..9accf8950d910b 100644 --- a/src/legacy/core_plugins/vis_type_table/public/table_vis_fn.test.ts +++ b/src/plugins/vis_type_table/public/table_vis_fn.test.ts @@ -21,7 +21,7 @@ import { createTableVisFn } from './table_vis_fn'; import { tableVisResponseHandler } from './table_vis_response_handler'; // eslint-disable-next-line -import { functionWrapper } from '../../../../plugins/expressions/common/expression_functions/specs/tests/utils'; +import { functionWrapper } from '../../expressions/common/expression_functions/specs/tests/utils'; jest.mock('./table_vis_response_handler', () => ({ tableVisResponseHandler: jest.fn().mockReturnValue({ diff --git a/src/legacy/core_plugins/vis_type_table/public/table_vis_fn.ts b/src/plugins/vis_type_table/public/table_vis_fn.ts similarity index 94% rename from src/legacy/core_plugins/vis_type_table/public/table_vis_fn.ts rename to src/plugins/vis_type_table/public/table_vis_fn.ts index a97e596e89754c..9739a7a284e6cf 100644 --- a/src/legacy/core_plugins/vis_type_table/public/table_vis_fn.ts +++ b/src/plugins/vis_type_table/public/table_vis_fn.ts @@ -19,11 +19,7 @@ import { i18n } from '@kbn/i18n'; import { tableVisResponseHandler, TableContext } from './table_vis_response_handler'; -import { - ExpressionFunctionDefinition, - KibanaDatatable, - Render, -} from '../../../../plugins/expressions/public'; +import { ExpressionFunctionDefinition, KibanaDatatable, Render } from '../../expressions/public'; export type Input = KibanaDatatable; diff --git a/src/legacy/core_plugins/vis_type_table/public/table_vis_legacy_module.ts b/src/plugins/vis_type_table/public/table_vis_legacy_module.ts similarity index 100% rename from src/legacy/core_plugins/vis_type_table/public/table_vis_legacy_module.ts rename to src/plugins/vis_type_table/public/table_vis_legacy_module.ts diff --git a/src/legacy/core_plugins/vis_type_table/public/table_vis_response_handler.ts b/src/plugins/vis_type_table/public/table_vis_response_handler.ts similarity index 100% rename from src/legacy/core_plugins/vis_type_table/public/table_vis_response_handler.ts rename to src/plugins/vis_type_table/public/table_vis_response_handler.ts diff --git a/src/plugins/vis_type_table/public/table_vis_type.ts b/src/plugins/vis_type_table/public/table_vis_type.ts new file mode 100644 index 00000000000000..26e5ac8cfd71ab --- /dev/null +++ b/src/plugins/vis_type_table/public/table_vis_type.ts @@ -0,0 +1,100 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { CoreSetup, PluginInitializerContext } from 'kibana/public'; +import { i18n } from '@kbn/i18n'; +import { AggGroupNames } from '../../data/public'; +import { Schemas } from '../../vis_default_editor/public'; +import { Vis } from '../../visualizations/public'; +import { tableVisResponseHandler } from './table_vis_response_handler'; +// @ts-ignore +import tableVisTemplate from './table_vis.html'; +import { TableOptions } from './components/table_vis_options'; +import { getTableVisualizationControllerClass } from './vis_controller'; + +export function getTableVisTypeDefinition(core: CoreSetup, context: PluginInitializerContext) { + return { + type: 'table', + name: 'table', + title: i18n.translate('visTypeTable.tableVisTitle', { + defaultMessage: 'Data Table', + }), + icon: 'visTable', + description: i18n.translate('visTypeTable.tableVisDescription', { + defaultMessage: 'Display values in a table', + }), + visualization: getTableVisualizationControllerClass(core, context), + visConfig: { + defaults: { + perPage: 10, + showPartialRows: false, + showMetricsAtAllLevels: false, + sort: { + columnIndex: null, + direction: null, + }, + showTotal: false, + totalFunc: 'sum', + percentageCol: '', + }, + template: tableVisTemplate, + }, + editorConfig: { + optionsTemplate: TableOptions, + schemas: new Schemas([ + { + group: AggGroupNames.Metrics, + name: 'metric', + title: i18n.translate('visTypeTable.tableVisEditorConfig.schemas.metricTitle', { + defaultMessage: 'Metric', + }), + aggFilter: ['!geo_centroid', '!geo_bounds'], + aggSettings: { + top_hits: { + allowStrings: true, + }, + }, + min: 1, + defaults: [{ type: 'count', schema: 'metric' }], + }, + { + group: AggGroupNames.Buckets, + name: 'bucket', + title: i18n.translate('visTypeTable.tableVisEditorConfig.schemas.bucketTitle', { + defaultMessage: 'Split rows', + }), + aggFilter: ['!filter'], + }, + { + group: AggGroupNames.Buckets, + name: 'split', + title: i18n.translate('visTypeTable.tableVisEditorConfig.schemas.splitTitle', { + defaultMessage: 'Split table', + }), + min: 0, + max: 1, + aggFilter: ['!filter'], + }, + ]), + }, + responseHandler: tableVisResponseHandler, + hierarchicalData: (vis: Vis) => { + return Boolean(vis.params.showPartialRows || vis.params.showMetricsAtAllLevels); + }, + }; +} diff --git a/src/legacy/core_plugins/vis_type_table/public/types.ts b/src/plugins/vis_type_table/public/types.ts similarity index 94% rename from src/legacy/core_plugins/vis_type_table/public/types.ts rename to src/plugins/vis_type_table/public/types.ts index c6de14b9f050c6..39023d1305cb63 100644 --- a/src/legacy/core_plugins/vis_type_table/public/types.ts +++ b/src/plugins/vis_type_table/public/types.ts @@ -17,7 +17,7 @@ * under the License. */ -import { SchemaConfig } from '../../../../plugins/visualizations/public'; +import { SchemaConfig } from '../../visualizations/public'; export enum AggTypes { SUM = 'sum', diff --git a/src/plugins/vis_type_table/public/vis_controller.ts b/src/plugins/vis_type_table/public/vis_controller.ts new file mode 100644 index 00000000000000..d49dd32c8c89c3 --- /dev/null +++ b/src/plugins/vis_type_table/public/vis_controller.ts @@ -0,0 +1,109 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { CoreSetup, PluginInitializerContext } from 'kibana/public'; +import angular, { IModule, auto, IRootScopeService, IScope, ICompileService } from 'angular'; +import $ from 'jquery'; + +import { VisParams, ExprVis } from '../../visualizations/public'; +import { getAngularModule } from './get_inner_angular'; +import { initTableVisLegacyModule } from './table_vis_legacy_module'; + +const innerAngularName = 'kibana/table_vis'; + +export function getTableVisualizationControllerClass( + core: CoreSetup, + context: PluginInitializerContext +) { + return class TableVisualizationController { + private tableVisModule: IModule | undefined; + private injector: auto.IInjectorService | undefined; + el: JQuery; + vis: ExprVis; + $rootScope: IRootScopeService | null = null; + $scope: (IScope & { [key: string]: any }) | undefined; + $compile: ICompileService | undefined; + + constructor(domeElement: Element, vis: ExprVis) { + this.el = $(domeElement); + this.vis = vis; + } + + getInjector() { + if (!this.injector) { + const mountpoint = document.createElement('div'); + mountpoint.setAttribute('style', 'height: 100%; width: 100%;'); + this.injector = angular.bootstrap(mountpoint, [innerAngularName]); + this.el.append(mountpoint); + } + + return this.injector; + } + + async initLocalAngular() { + if (!this.tableVisModule) { + const [coreStart] = await core.getStartServices(); + this.tableVisModule = getAngularModule(innerAngularName, coreStart, context); + initTableVisLegacyModule(this.tableVisModule); + } + } + + async render(esResponse: object, visParams: VisParams) { + await this.initLocalAngular(); + + return new Promise(async (resolve, reject) => { + if (!this.$rootScope) { + const $injector = this.getInjector(); + this.$rootScope = $injector.get('$rootScope'); + this.$compile = $injector.get('$compile'); + } + const updateScope = () => { + if (!this.$scope) { + return; + } + this.$scope.vis = this.vis; + this.$scope.visState = { params: visParams }; + this.$scope.esResponse = esResponse; + + this.$scope.visParams = visParams; + this.$scope.renderComplete = resolve; + this.$scope.renderFailed = reject; + this.$scope.resize = Date.now(); + this.$scope.$apply(); + }; + + if (!this.$scope && this.$compile) { + this.$scope = this.$rootScope.$new(); + this.$scope.uiState = this.vis.getUiState(); + updateScope(); + this.el.find('div').append(this.$compile(this.vis.type!.visConfig.template)(this.$scope)); + this.$scope.$apply(); + } else { + updateScope(); + } + }); + } + + destroy() { + if (this.$rootScope) { + this.$rootScope.$destroy(); + this.$rootScope = null; + } + } + }; +} diff --git a/src/plugins/vis_type_table/server/index.ts b/src/plugins/vis_type_table/server/index.ts new file mode 100644 index 00000000000000..882958a28777d1 --- /dev/null +++ b/src/plugins/vis_type_table/server/index.ts @@ -0,0 +1,34 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { PluginConfigDescriptor } from 'kibana/server'; + +import { configSchema, ConfigSchema } from '../config'; + +export const config: PluginConfigDescriptor = { + schema: configSchema, + deprecations: ({ renameFromRoot }) => [ + renameFromRoot('table_vis.enabled', 'vis_type_table.enabled'), + ], +}; + +export const plugin = () => ({ + setup() {}, + start() {}, +}); diff --git a/src/plugins/vis_type_timeseries/kibana.json b/src/plugins/vis_type_timeseries/kibana.json index 38662c6a7ff89b..9053d2543e0d0e 100644 --- a/src/plugins/vis_type_timeseries/kibana.json +++ b/src/plugins/vis_type_timeseries/kibana.json @@ -4,6 +4,6 @@ "kibanaVersion": "kibana", "server": true, "ui": true, - "requiredPlugins": ["data", "expressions", "visualizations"], + "requiredPlugins": ["charts", "data", "expressions", "visualizations"], "optionalPlugins": ["usageCollection"] } diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_types/timeseries/config.js b/src/plugins/vis_type_timeseries/public/application/components/vis_types/timeseries/config.js index 024f59c3abb1c3..d29b795b10ec83 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/vis_types/timeseries/config.js +++ b/src/plugins/vis_type_timeseries/public/application/components/vis_types/timeseries/config.js @@ -53,7 +53,7 @@ export const TimeseriesConfig = injectI18n(function(props) { point_size: '', value_template: '{{value}}', offset_time: '', - split_color_mode: 'gradient', + split_color_mode: 'kibana', axis_min: '', axis_max: '', stacked: STACKED_OPTIONS.NONE, @@ -140,10 +140,10 @@ export const TimeseriesConfig = injectI18n(function(props) { const splitColorOptions = [ { label: intl.formatMessage({ - id: 'visTypeTimeseries.timeSeries.gradientLabel', - defaultMessage: 'Gradient', + id: 'visTypeTimeseries.timeSeries.defaultPaletteLabel', + defaultMessage: 'Default palette', }), - value: 'gradient', + value: 'kibana', }, { label: intl.formatMessage({ @@ -152,6 +152,13 @@ export const TimeseriesConfig = injectI18n(function(props) { }), value: 'rainbow', }, + { + label: intl.formatMessage({ + id: 'visTypeTimeseries.timeSeries.gradientLabel', + defaultMessage: 'Gradient', + }), + value: 'gradient', + }, ]; const selectedSplitColorOption = splitColorOptions.find(option => { return model.split_color_mode === option.value; diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/index.js b/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/index.js index b1c3c7ac6b67ad..5cf1619150e5c7 100644 --- a/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/index.js +++ b/src/plugins/vis_type_timeseries/public/application/visualizations/views/timeseries/index.js @@ -33,7 +33,7 @@ import { import { EuiIcon } from '@elastic/eui'; import { getTimezone } from '../../../lib/get_timezone'; import { eventBus, ACTIVE_CURSOR } from '../../lib/active_cursor'; -import { getUISettings } from '../../../../services'; +import { getUISettings, getChartsSetup } from '../../../../services'; import { GRID_LINE_CONFIG, ICON_TYPES_MAP, STACKED_OPTIONS } from '../../constants'; import { AreaSeriesDecorator } from './decorators/area_decorator'; import { BarSeriesDecorator } from './decorators/bar_decorator'; @@ -94,6 +94,12 @@ export const TimeSeries = ({ // apply legend style change if bgColor is configured const classes = classNames('tvbVisTimeSeries', getChartClasses(backgroundColor)); + // If the color isn't configured by the user, use the color mapping service + // to assign a color from the Kibana palette. Colors will be shared across the + // session, including dashboards. + const { colors } = getChartsSetup(); + colors.mappedColors.mapKeys(series.filter(({ color }) => !color).map(({ label }) => label)); + return ( ; visualizations: VisualizationsSetup; + charts: ChartsPluginSetup; } /** @internal */ @@ -56,10 +59,11 @@ export class MetricsPlugin implements Plugin, void> { public async setup( core: CoreSetup, - { expressions, visualizations }: MetricsPluginSetupDependencies + { expressions, visualizations, charts }: MetricsPluginSetupDependencies ) { expressions.registerFunction(createMetricsFn); setUISettings(core.uiSettings); + setChartsSetup(charts); visualizations.createReactVisualization(metricsVisDefinition); } diff --git a/src/plugins/vis_type_timeseries/public/services.ts b/src/plugins/vis_type_timeseries/public/services.ts index d93a376584eac9..9aa84478fb78bf 100644 --- a/src/plugins/vis_type_timeseries/public/services.ts +++ b/src/plugins/vis_type_timeseries/public/services.ts @@ -19,6 +19,7 @@ import { I18nStart, SavedObjectsStart, IUiSettingsClient, CoreStart } from 'src/core/public'; import { createGetterSetter } from '../../kibana_utils/public'; +import { ChartsPluginSetup } from '../../charts/public'; import { DataPublicPluginStart } from '../../data/public'; export const [getUISettings, setUISettings] = createGetterSetter('UISettings'); @@ -36,3 +37,7 @@ export const [getCoreStart, setCoreStart] = createGetterSetter('CoreS export const [getDataStart, setDataStart] = createGetterSetter('DataStart'); export const [getI18n, setI18n] = createGetterSetter('I18n'); + +export const [getChartsSetup, setChartsSetup] = createGetterSetter( + 'ChartsPluginSetup' +); diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_split_colors.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_split_colors.js index ff8d9077b08711..cad8c8f2025a17 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_split_colors.js +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_split_colors.js @@ -19,7 +19,7 @@ import Color from 'color'; -export function getSplitColors(inputColor, size = 10, style = 'gradient') { +export function getSplitColors(inputColor, size = 10, style = 'kibana') { const color = new Color(inputColor); const colors = []; let workingColor = Color.hsl(color.hsl().object()); @@ -49,7 +49,7 @@ export function getSplitColors(inputColor, size = 10, style = 'gradient') { '#0F1419', '#666666', ]; - } else { + } else if (style === 'gradient') { colors.push(color.string()); const rotateBy = color.luminosity() / (size - 1); for (let i = 0; i < size - 1; i++) { diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.test.js index 0874d944033f5c..376d32d0da13f6 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.test.js +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.test.js @@ -106,7 +106,7 @@ describe('getSplits(resp, panel, series)', () => { ]); }); - test('should return a splits for terms group bys', () => { + describe('terms group bys', () => { const resp = { aggregations: { SERIES: { @@ -126,38 +126,89 @@ describe('getSplits(resp, panel, series)', () => { }, }, }; - const series = { - id: 'SERIES', - color: '#F00', - split_mode: 'terms', - terms_field: 'beat.hostname', - terms_size: 10, - metrics: [ - { id: 'AVG', type: 'avg', field: 'cpu' }, - { id: 'SIBAGG', type: 'avg_bucket', field: 'AVG' }, - ], - }; - const panel = { type: 'timeseries' }; - expect(getSplits(resp, panel, series)).toEqual([ - { - id: 'SERIES:example-01', - key: 'example-01', - label: 'example-01', - meta: { bucketSize: 10 }, - color: 'rgb(255, 0, 0)', - timeseries: { buckets: [] }, - SIBAGG: { value: 1 }, - }, - { - id: 'SERIES:example-02', - key: 'example-02', - label: 'example-02', - meta: { bucketSize: 10 }, - color: 'rgb(147, 0, 0)', - timeseries: { buckets: [] }, - SIBAGG: { value: 2 }, - }, - ]); + + test('should return a splits with no color', () => { + const series = { + id: 'SERIES', + color: '#F00', + split_mode: 'terms', + terms_field: 'beat.hostname', + terms_size: 10, + metrics: [ + { id: 'AVG', type: 'avg', field: 'cpu' }, + { id: 'SIBAGG', type: 'avg_bucket', field: 'AVG' }, + ], + }; + const panel = { type: 'timeseries' }; + expect(getSplits(resp, panel, series)).toEqual([ + { + id: 'SERIES:example-01', + key: 'example-01', + label: 'example-01', + meta: { bucketSize: 10 }, + color: undefined, + timeseries: { buckets: [] }, + SIBAGG: { value: 1 }, + }, + { + id: 'SERIES:example-02', + key: 'example-02', + label: 'example-02', + meta: { bucketSize: 10 }, + color: undefined, + timeseries: { buckets: [] }, + SIBAGG: { value: 2 }, + }, + ]); + }); + + test('should return gradient color', () => { + const series = { + id: 'SERIES', + color: '#F00', + split_mode: 'terms', + split_color_mode: 'gradient', + terms_field: 'beat.hostname', + terms_size: 10, + metrics: [ + { id: 'AVG', type: 'avg', field: 'cpu' }, + { id: 'SIBAGG', type: 'avg_bucket', field: 'AVG' }, + ], + }; + const panel = { type: 'timeseries' }; + expect(getSplits(resp, panel, series)).toEqual([ + expect.objectContaining({ + color: 'rgb(255, 0, 0)', + }), + expect.objectContaining({ + color: 'rgb(147, 0, 0)', + }), + ]); + }); + + test('should return rainbow color', () => { + const series = { + id: 'SERIES', + color: '#F00', + split_mode: 'terms', + split_color_mode: 'rainbow', + terms_field: 'beat.hostname', + terms_size: 10, + metrics: [ + { id: 'AVG', type: 'avg', field: 'cpu' }, + { id: 'SIBAGG', type: 'avg_bucket', field: 'AVG' }, + ], + }; + const panel = { type: 'timeseries' }; + expect(getSplits(resp, panel, series)).toEqual([ + expect.objectContaining({ + color: '#68BC00', + }), + expect.objectContaining({ + color: '#009CE0', + }), + ]); + }); }); test('should return a splits for filters group bys', () => { diff --git a/src/plugins/visualizations/server/saved_objects/visualization_migrations.test.ts b/src/plugins/visualizations/server/saved_objects/visualization_migrations.test.ts index 26f8278cd3d434..83d53d27e41fdc 100644 --- a/src/plugins/visualizations/server/saved_objects/visualization_migrations.test.ts +++ b/src/plugins/visualizations/server/saved_objects/visualization_migrations.test.ts @@ -1460,4 +1460,62 @@ describe('migration visualization', () => { expect(migratedParams.gauge_color_rules[1]).toEqual(params.gauge_color_rules[1]); }); }); + + describe('7.8.0 tsvb split_color_mode', () => { + const migrate = (doc: any) => + visualizationSavedObjectTypeMigrations['7.8.0']( + doc as Parameters[0], + savedObjectMigrationContext + ); + + const generateDoc = (params: any) => ({ + attributes: { + title: 'My Vis', + type: 'visualization', + description: 'This is my super cool vis.', + visState: JSON.stringify(params), + uiStateJSON: '{}', + version: 1, + kibanaSavedObjectMeta: { + searchSourceJSON: '{}', + }, + }, + }); + + it('should change a missing split_color_mode to gradient', () => { + const params = { type: 'metrics', params: { series: [{}] } }; + const testDoc1 = generateDoc(params); + const migratedTestDoc1 = migrate(testDoc1); + const series = JSON.parse(migratedTestDoc1.attributes.visState).params.series; + + expect(series[0].split_color_mode).toEqual('gradient'); + }); + + it('should not change the color mode if it is set', () => { + const params = { type: 'metrics', params: { series: [{ split_color_mode: 'gradient' }] } }; + const testDoc1 = generateDoc(params); + const migratedTestDoc1 = migrate(testDoc1); + const series = JSON.parse(migratedTestDoc1.attributes.visState).params.series; + + expect(series[0].split_color_mode).toEqual('gradient'); + }); + + it('should not change the color mode if it is non-default', () => { + const params = { type: 'metrics', params: { series: [{ split_color_mode: 'rainbow' }] } }; + const testDoc1 = generateDoc(params); + const migratedTestDoc1 = migrate(testDoc1); + const series = JSON.parse(migratedTestDoc1.attributes.visState).params.series; + + expect(series[0].split_color_mode).toEqual('rainbow'); + }); + + it('should not migrate a visualization of unknown type', () => { + const params = { type: 'unknown', params: { series: [{}] } }; + const doc = generateDoc(params); + const migratedDoc = migrate(doc); + const series = JSON.parse(migratedDoc.attributes.visState).params.series; + + expect(series[0].split_color_mode).toBeUndefined(); + }); + }); }); diff --git a/src/plugins/visualizations/server/saved_objects/visualization_migrations.ts b/src/plugins/visualizations/server/saved_objects/visualization_migrations.ts index 80783e41863eaf..94473e35a942d5 100644 --- a/src/plugins/visualizations/server/saved_objects/visualization_migrations.ts +++ b/src/plugins/visualizations/server/saved_objects/visualization_migrations.ts @@ -602,7 +602,39 @@ const migrateMatchAllQuery: SavedObjectMigrationFn = doc => { }; } } + return doc; +}; + +// [TSVB] Default color palette is changing, keep the default for older viz +const migrateTsvbDefaultColorPalettes: SavedObjectMigrationFn = doc => { + const visStateJSON = get(doc, 'attributes.visState'); + let visState; + + if (visStateJSON) { + try { + visState = JSON.parse(visStateJSON); + } catch (e) { + // Let it go, the data is invalid and we'll leave it as is + } + if (visState && visState.type === 'metrics') { + const series: any[] = get(visState, 'params.series') || []; + series.forEach(part => { + // The default value was not saved before + if (!part.split_color_mode) { + part.split_color_mode = 'gradient'; + } + }); + + return { + ...doc, + attributes: { + ...doc.attributes, + visState: JSON.stringify(visState), + }, + }; + } + } return doc; }; @@ -639,4 +671,5 @@ export const visualizationSavedObjectTypeMigrations = { '7.3.1': flow(migrateFiltersAggQueryStringQueries), '7.4.2': flow(transformSplitFiltersStringToQueryObject), '7.7.0': flow(migrateOperatorKeyTypo), + '7.8.0': flow(migrateTsvbDefaultColorPalettes), }; diff --git a/test/examples/config.js b/test/examples/config.js index 49d75da2860753..2be34459d8d06f 100644 --- a/test/examples/config.js +++ b/test/examples/config.js @@ -28,6 +28,7 @@ export default async function({ readConfigFile }) { require.resolve('./search'), require.resolve('./embeddables'), require.resolve('./ui_actions'), + require.resolve('./state_sync'), ], services: { ...functionalConfig.get('services'), diff --git a/test/examples/state_sync/index.ts b/test/examples/state_sync/index.ts new file mode 100644 index 00000000000000..3c524f0feb6192 --- /dev/null +++ b/test/examples/state_sync/index.ts @@ -0,0 +1,39 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { PluginFunctionalProviderContext } from 'test/plugin_functional/services'; + +// eslint-disable-next-line import/no-default-export +export default function({ + getService, + getPageObjects, + loadTestFile, +}: PluginFunctionalProviderContext) { + const browser = getService('browser'); + const PageObjects = getPageObjects(['common']); + + describe('state sync examples', function() { + before(async () => { + await browser.setWindowSize(1300, 900); + await PageObjects.common.navigateToApp('settings'); + }); + + loadTestFile(require.resolve('./todo_app')); + }); +} diff --git a/test/examples/state_sync/todo_app.ts b/test/examples/state_sync/todo_app.ts new file mode 100644 index 00000000000000..4933d746ca4fd8 --- /dev/null +++ b/test/examples/state_sync/todo_app.ts @@ -0,0 +1,189 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import expect from '@kbn/expect'; + +import { PluginFunctionalProviderContext } from 'test/plugin_functional/services'; + +// eslint-disable-next-line import/no-default-export +export default function({ getService, getPageObjects }: PluginFunctionalProviderContext) { + const testSubjects = getService('testSubjects'); + const find = getService('find'); + const retry = getService('retry'); + const appsMenu = getService('appsMenu'); + const browser = getService('browser'); + const PageObjects = getPageObjects(['common']); + const log = getService('log'); + + describe('TODO app', () => { + describe("TODO app with browser history (platform's ScopedHistory)", async () => { + const appId = 'stateContainersExampleBrowserHistory'; + let base: string; + + before(async () => { + base = await PageObjects.common.getHostPort(); + await appsMenu.clickLink('State containers example - browser history routing'); + }); + + it('links are rendered correctly and state is preserved in links', async () => { + const getHrefByLinkTestSubj = async (linkTestSubj: string) => + (await testSubjects.find(linkTestSubj)).getAttribute('href'); + + await expectPathname(await getHrefByLinkTestSubj('filterLinkCompleted'), '/completed'); + await expectPathname( + await getHrefByLinkTestSubj('filterLinkNotCompleted'), + '/not-completed' + ); + await expectPathname(await getHrefByLinkTestSubj('filterLinkAll'), '/'); + }); + + it('TODO app state is synced with url, back navigation works', async () => { + // checking that in initial state checkbox is unchecked and state is synced with url + expect(await testSubjects.isChecked('todoCheckbox-0')).to.be(false); + expect(await browser.getCurrentUrl()).to.contain('completed:!f'); + + // check the checkbox by clicking the label (clicking checkbox directly fails as it is "no intractable") + (await find.byCssSelector('label[for="0"]')).click(); + + // wait for react to update dom and checkbox in checked state + await retry.tryForTime(1000, async () => { + await expect(await testSubjects.isChecked('todoCheckbox-0')).to.be(true); + }); + // checking that url is updated with checked state + expect(await browser.getCurrentUrl()).to.contain('completed:!t'); + + // checking back and forward button + await browser.goBack(); + expect(await browser.getCurrentUrl()).to.contain('completed:!f'); + await retry.tryForTime(1000, async () => { + await expect(await testSubjects.isChecked('todoCheckbox-0')).to.be(false); + }); + + await browser.goForward(); + expect(await browser.getCurrentUrl()).to.contain('completed:!t'); + await retry.tryForTime(1000, async () => { + await expect(await testSubjects.isChecked('todoCheckbox-0')).to.be(true); + }); + }); + + it('links navigation works', async () => { + // click link to filter only not completed + await testSubjects.click('filterLinkNotCompleted'); + await expectPathname(await browser.getCurrentUrl(), '/not-completed'); + // checkbox should be missing because it is "completed" + await testSubjects.missingOrFail('todoCheckbox-0'); + }); + + /** + * Parses app's scoped pathname from absolute url and asserts it against `expectedPathname` + * Also checks that hashes are equal (detail of todo app that state is rendered in links) + * @param absoluteUrl + * @param expectedPathname + */ + async function expectPathname(absoluteUrl: string, expectedPathname: string) { + const scoped = await getScopedUrl(absoluteUrl); + const [pathname, newHash] = scoped.split('#'); + expect(pathname).to.be(expectedPathname); + const [, currentHash] = (await browser.getCurrentUrl()).split('#'); + expect(newHash.replace(/%27/g, "'")).to.be(currentHash.replace(/%27/g, "'")); + } + + /** + * Get's part of url scoped to this app (removed kibana's host and app's pathname) + * @param url - absolute url + */ + async function getScopedUrl(url: string): Promise { + expect(url).to.contain(base); + expect(url).to.contain(appId); + const scopedUrl = url.slice(url.indexOf(appId) + appId.length); + expect(scopedUrl).not.to.contain(appId); // app id in url only once + return scopedUrl; + } + }); + + describe('TODO app with hash history ', async () => { + before(async () => { + await appsMenu.clickLink('State containers example - hash history routing'); + }); + + it('Links are rendered correctly and state is preserved in links', async () => { + const getHrefByLinkTestSubj = async (linkTestSubj: string) => + (await testSubjects.find(linkTestSubj)).getAttribute('href'); + await expectHashPathname(await getHrefByLinkTestSubj('filterLinkCompleted'), '/completed'); + await expectHashPathname( + await getHrefByLinkTestSubj('filterLinkNotCompleted'), + '/not-completed' + ); + await expectHashPathname(await getHrefByLinkTestSubj('filterLinkAll'), '/'); + }); + + it('TODO app state is synced with url, back navigation works', async () => { + // checking that in initial state checkbox is unchecked and state is synced with url + expect(await testSubjects.isChecked('todoCheckbox-0')).to.be(false); + expect(await browser.getCurrentUrl()).to.contain('completed:!f'); + // check the checkbox by clicking the label (clicking checkbox directly fails as it is "no intractable") + (await find.byCssSelector('label[for="0"]')).click(); + + // wait for react to update dom and checkbox in checked state + await retry.tryForTime(1000, async () => { + await expect(await testSubjects.isChecked('todoCheckbox-0')).to.be(true); + }); + // checking that url is updated with checked state + expect(await browser.getCurrentUrl()).to.contain('completed:!t'); + + // checking back and forward button + await browser.goBack(); + expect(await browser.getCurrentUrl()).to.contain('completed:!f'); + await retry.tryForTime(1000, async () => { + await expect(await testSubjects.isChecked('todoCheckbox-0')).to.be(false); + }); + + await browser.goForward(); + expect(await browser.getCurrentUrl()).to.contain('completed:!t'); + await retry.tryForTime(1000, async () => { + await expect(await testSubjects.isChecked('todoCheckbox-0')).to.be(true); + }); + }); + + it('links navigation works', async () => { + // click link to filter only not completed + await testSubjects.click('filterLinkNotCompleted'); + await expectHashPathname(await browser.getCurrentUrl(), '/not-completed'); + // checkbox should be missing because it is "completed" + await testSubjects.missingOrFail('todoCheckbox-0'); + }); + + /** + * Parses app's pathname in hash from absolute url and asserts it against `expectedPathname` + * Also checks that queries in hashes are equal (detail of todo app that state is rendered in links) + * @param absoluteUrl + * @param expectedPathname + */ + async function expectHashPathname(hash: string, expectedPathname: string) { + log.debug(`expect hash pathname ${hash} to be ${expectedPathname}`); + const hashPath = hash.split('#')[1]; + const [hashPathname, hashQuery] = hashPath.split('?'); + const [, currentHash] = (await browser.getCurrentUrl()).split('#'); + const [, currentHashQuery] = currentHash.split('?'); + expect(currentHashQuery.replace(/%27/g, "'")).to.be(hashQuery.replace(/%27/g, "'")); + expect(hashPathname).to.be(expectedPathname); + } + }); + }); +} diff --git a/test/functional/apps/dashboard/panel_controls.js b/test/functional/apps/dashboard/panel_controls.js index 52c4a11360355b..6e24b9f3570a3b 100644 --- a/test/functional/apps/dashboard/panel_controls.js +++ b/test/functional/apps/dashboard/panel_controls.js @@ -113,6 +113,50 @@ export default function({ getService, getPageObjects }) { }); }); + describe('panel cloning', function() { + before(async () => { + await PageObjects.dashboard.clickNewDashboard(); + await PageObjects.timePicker.setHistoricalDataRange(); + await dashboardAddPanel.addVisualization(PIE_CHART_VIS_NAME); + }); + + after(async function() { + await PageObjects.dashboard.gotoDashboardLandingPage(); + }); + + it('clones a panel', async () => { + const initialPanelTitles = await PageObjects.dashboard.getPanelTitles(); + await dashboardPanelActions.clonePanelByTitle(PIE_CHART_VIS_NAME); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.dashboard.waitForRenderComplete(); + const postPanelTitles = await PageObjects.dashboard.getPanelTitles(); + expect(postPanelTitles.length).to.equal(initialPanelTitles.length + 1); + }); + + it('appends a clone title tag', async () => { + const panelTitles = await PageObjects.dashboard.getPanelTitles(); + expect(panelTitles[1]).to.equal(PIE_CHART_VIS_NAME + ' (copy)'); + }); + + it('retains original panel dimensions', async () => { + const panelDimensions = await PageObjects.dashboard.getPanelDimensions(); + expect(panelDimensions[0]).to.eql(panelDimensions[1]); + }); + + it('gives a correct title to the clone of a clone', async () => { + const initialPanelTitles = await PageObjects.dashboard.getPanelTitles(); + const clonedPanelName = initialPanelTitles[initialPanelTitles.length - 1]; + await dashboardPanelActions.clonePanelByTitle(clonedPanelName); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.dashboard.waitForRenderComplete(); + const postPanelTitles = await PageObjects.dashboard.getPanelTitles(); + expect(postPanelTitles.length).to.equal(initialPanelTitles.length + 1); + expect(postPanelTitles[postPanelTitles.length - 1]).to.equal( + PIE_CHART_VIS_NAME + ' (copy 1)' + ); + }); + }); + describe('panel edit controls', function() { before(async () => { await PageObjects.dashboard.clickNewDashboard(); @@ -137,6 +181,7 @@ export default function({ getService, getPageObjects }) { await dashboardPanelActions.expectExistsEditPanelAction(); await dashboardPanelActions.expectExistsReplacePanelAction(); + await dashboardPanelActions.expectExistsDuplicatePanelAction(); await dashboardPanelActions.expectExistsRemovePanelAction(); }); @@ -151,6 +196,7 @@ export default function({ getService, getPageObjects }) { await dashboardPanelActions.openContextMenu(); await dashboardPanelActions.expectExistsEditPanelAction(); await dashboardPanelActions.expectExistsReplacePanelAction(); + await dashboardPanelActions.expectExistsDuplicatePanelAction(); await dashboardPanelActions.expectExistsRemovePanelAction(); // Get rid of the timestamp in the url. @@ -166,6 +212,7 @@ export default function({ getService, getPageObjects }) { await dashboardPanelActions.openContextMenu(); await dashboardPanelActions.expectMissingEditPanelAction(); await dashboardPanelActions.expectMissingReplacePanelAction(); + await dashboardPanelActions.expectMissingDuplicatePanelAction(); await dashboardPanelActions.expectMissingRemovePanelAction(); }); @@ -174,6 +221,7 @@ export default function({ getService, getPageObjects }) { await dashboardPanelActions.openContextMenu(); await dashboardPanelActions.expectExistsEditPanelAction(); await dashboardPanelActions.expectExistsReplacePanelAction(); + await dashboardPanelActions.expectExistsDuplicatePanelAction(); await dashboardPanelActions.expectMissingRemovePanelAction(); await dashboardPanelActions.clickExpandPanelToggle(); }); diff --git a/test/functional/apps/visualize/_tsvb_time_series.ts b/test/functional/apps/visualize/_tsvb_time_series.ts index fa79190a5bf940..ac89c2b55e5140 100644 --- a/test/functional/apps/visualize/_tsvb_time_series.ts +++ b/test/functional/apps/visualize/_tsvb_time_series.ts @@ -25,7 +25,6 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { const retry = getService('retry'); const log = getService('log'); const kibanaServer = getService('kibanaServer'); - const testSubjects = getService('testSubjects'); describe('visual builder', function describeIndexTests() { beforeEach(async () => { @@ -126,20 +125,18 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { expect(actualCountMin).to.be('3 hours'); }); - // --reversed class is not implemented in @elastic\chart - describe.skip('Dark mode', () => { + describe('Dark mode', () => { before(async () => { await kibanaServer.uiSettings.update({ 'theme:darkMode': true, }); }); - it(`viz should have 'reversed' class when background color is white`, async () => { + it(`viz should have light class when background color is white`, async () => { await visualBuilder.clickPanelOptions('timeSeries'); await visualBuilder.setBackgroundColor('#FFFFFF'); - const classNames = await testSubjects.getAttribute('timeseriesChart', 'class'); - expect(classNames.includes('tvbVisTimeSeries--reversed')).to.be(true); + expect(await visualBuilder.checkTimeSeriesIsLight()).to.be(true); }); after(async () => { diff --git a/test/functional/page_objects/visual_builder_page.ts b/test/functional/page_objects/visual_builder_page.ts index b8e6c812b46bd5..12962b3a5cdef7 100644 --- a/test/functional/page_objects/visual_builder_page.ts +++ b/test/functional/page_objects/visual_builder_page.ts @@ -71,6 +71,10 @@ export function VisualBuilderPageProvider({ getService, getPageObjects }: FtrPro } } + public async checkTimeSeriesIsLight() { + return await find.existsByCssSelector('.tvbVisTimeSeriesLight'); + } + public async checkTimeSeriesLegendIsPresent() { const isPresent = await find.existsByCssSelector('.echLegend'); if (!isPresent) { diff --git a/test/functional/services/dashboard/panel_actions.js b/test/functional/services/dashboard/panel_actions.js index baea2a52208c16..b155d747f3b939 100644 --- a/test/functional/services/dashboard/panel_actions.js +++ b/test/functional/services/dashboard/panel_actions.js @@ -20,6 +20,7 @@ const REMOVE_PANEL_DATA_TEST_SUBJ = 'embeddablePanelAction-deletePanel'; const EDIT_PANEL_DATA_TEST_SUBJ = 'embeddablePanelAction-editPanel'; const REPLACE_PANEL_DATA_TEST_SUBJ = 'embeddablePanelAction-replacePanel'; +const CLONE_PANEL_DATA_TEST_SUBJ = 'embeddablePanelAction-clonePanel'; const TOGGLE_EXPAND_PANEL_DATA_TEST_SUBJ = 'embeddablePanelAction-togglePanel'; const CUSTOMIZE_PANEL_DATA_TEST_SUBJ = 'embeddablePanelAction-ACTION_CUSTOMIZE_PANEL'; const OPEN_CONTEXT_MENU_ICON_DATA_TEST_SUBJ = 'embeddablePanelToggleMenuIcon'; @@ -97,6 +98,16 @@ export function DashboardPanelActionsProvider({ getService, getPageObjects }) { await testSubjects.click(REPLACE_PANEL_DATA_TEST_SUBJ); } + async clonePanelByTitle(title) { + log.debug(`clonePanel(${title})`); + let panelOptions = null; + if (title) { + panelOptions = await this.getPanelHeading(title); + } + await this.openContextMenu(panelOptions); + await testSubjects.click(CLONE_PANEL_DATA_TEST_SUBJ); + } + async openInspectorByTitle(title) { const header = await this.getPanelHeading(title); await this.openInspector(header); @@ -123,7 +134,12 @@ export function DashboardPanelActionsProvider({ getService, getPageObjects }) { } async expectExistsReplacePanelAction() { - log.debug('expectExistsEditPanelAction'); + log.debug('expectExistsReplacePanelAction'); + await testSubjects.existOrFail(REPLACE_PANEL_DATA_TEST_SUBJ); + } + + async expectExistsDuplicatePanelAction() { + log.debug('expectExistsDuplicatePanelAction'); await testSubjects.existOrFail(REPLACE_PANEL_DATA_TEST_SUBJ); } @@ -133,7 +149,12 @@ export function DashboardPanelActionsProvider({ getService, getPageObjects }) { } async expectMissingReplacePanelAction() { - log.debug('expectMissingEditPanelAction'); + log.debug('expectMissingReplacePanelAction'); + await testSubjects.missingOrFail(REPLACE_PANEL_DATA_TEST_SUBJ); + } + + async expectMissingDuplicatePanelAction() { + log.debug('expectMissingDuplicatePanelAction'); await testSubjects.missingOrFail(REPLACE_PANEL_DATA_TEST_SUBJ); } diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index cb124cc54e5abe..c8715ac3447bd8 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -32,7 +32,7 @@ "xpack.remoteClusters": "plugins/remote_clusters", "xpack.painlessLab": "plugins/painless_lab", "xpack.reporting": ["plugins/reporting", "legacy/plugins/reporting"], - "xpack.rollupJobs": "legacy/plugins/rollup", + "xpack.rollupJobs": ["legacy/plugins/rollup", "plugins/rollup"], "xpack.searchProfiler": "plugins/searchprofiler", "xpack.security": ["legacy/plugins/security", "plugins/security"], "xpack.server": "legacy/server", diff --git a/x-pack/index.js b/x-pack/index.js index 7fbd992120ea68..1a78c24b1221bc 100644 --- a/x-pack/index.js +++ b/x-pack/index.js @@ -10,7 +10,6 @@ import { monitoring } from './legacy/plugins/monitoring'; import { reporting } from './legacy/plugins/reporting'; import { security } from './legacy/plugins/security'; import { dashboardMode } from './legacy/plugins/dashboard_mode'; -import { logstash } from './legacy/plugins/logstash'; import { beats } from './legacy/plugins/beats_management'; import { apm } from './legacy/plugins/apm'; import { maps } from './legacy/plugins/maps'; @@ -40,7 +39,6 @@ module.exports = function(kibana) { spaces(kibana), security(kibana), dashboardMode(kibana), - logstash(kibana), beats(kibana), apm(kibana), maps(kibana), diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.test.ts b/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.test.ts index 416eb879d5974f..d844ac8b5988dd 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.test.ts +++ b/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.test.ts @@ -166,6 +166,212 @@ describe('waterfall_helpers', () => { expect(waterfall.errorsCount).toEqual(0); expect(waterfall).toMatchSnapshot(); }); + it('should reparent spans', () => { + const traceItems = [ + { + processor: { event: 'transaction' }, + trace: { id: 'myTraceId' }, + service: { name: 'opbeans-node' }, + transaction: { + duration: { us: 49660 }, + name: 'GET /api', + id: 'myTransactionId1' + }, + timestamp: { us: 1549324795784006 } + } as Transaction, + { + parent: { id: 'mySpanIdD' }, + processor: { event: 'span' }, + trace: { id: 'myTraceId' }, + service: { name: 'opbeans-ruby' }, + transaction: { id: 'myTransactionId1' }, + timestamp: { us: 1549324795825633 }, + span: { + duration: { us: 481 }, + name: 'SELECT FROM products', + id: 'mySpanIdB' + }, + child_ids: ['mySpanIdA', 'mySpanIdC'] + } as Span, + { + parent: { id: 'mySpanIdD' }, + processor: { event: 'span' }, + trace: { id: 'myTraceId' }, + service: { name: 'opbeans-ruby' }, + transaction: { id: 'myTransactionId1' }, + span: { + duration: { us: 6161 }, + name: 'Api::ProductsController#index', + id: 'mySpanIdA' + }, + timestamp: { us: 1549324795824504 } + } as Span, + { + parent: { id: 'mySpanIdD' }, + processor: { event: 'span' }, + trace: { id: 'myTraceId' }, + service: { name: 'opbeans-ruby' }, + transaction: { id: 'myTransactionId1' }, + span: { + duration: { us: 532 }, + name: 'SELECT FROM product', + id: 'mySpanIdC' + }, + timestamp: { us: 1549324795827905 } + } as Span, + { + parent: { id: 'myTransactionId1' }, + processor: { event: 'span' }, + trace: { id: 'myTraceId' }, + service: { name: 'opbeans-node' }, + transaction: { id: 'myTransactionId1' }, + span: { + duration: { us: 47557 }, + name: 'GET opbeans-ruby:3000/api/products', + id: 'mySpanIdD' + }, + timestamp: { us: 1549324795785760 } + } as Span + ]; + const entryTransactionId = 'myTransactionId1'; + const waterfall = getWaterfall( + { + trace: { items: traceItems, errorDocs: [], exceedsMax: false }, + errorsPerTransaction: {} + }, + entryTransactionId + ); + const getIdAndParentId = (item: IWaterfallItem) => ({ + id: item.id, + parentId: item.parent?.id + }); + expect(waterfall.items.length).toBe(5); + expect(getIdAndParentId(waterfall.items[0])).toEqual({ + id: 'myTransactionId1', + parentId: undefined + }); + expect(getIdAndParentId(waterfall.items[1])).toEqual({ + id: 'mySpanIdD', + parentId: 'myTransactionId1' + }); + expect(getIdAndParentId(waterfall.items[2])).toEqual({ + id: 'mySpanIdB', + parentId: 'mySpanIdD' + }); + expect(getIdAndParentId(waterfall.items[3])).toEqual({ + id: 'mySpanIdA', + parentId: 'mySpanIdB' + }); + expect(getIdAndParentId(waterfall.items[4])).toEqual({ + id: 'mySpanIdC', + parentId: 'mySpanIdB' + }); + expect(waterfall.errorItems.length).toBe(0); + expect(waterfall.errorsCount).toEqual(0); + }); + it("shouldn't reparent spans when child id isn't found", () => { + const traceItems = [ + { + processor: { event: 'transaction' }, + trace: { id: 'myTraceId' }, + service: { name: 'opbeans-node' }, + transaction: { + duration: { us: 49660 }, + name: 'GET /api', + id: 'myTransactionId1' + }, + timestamp: { us: 1549324795784006 } + } as Transaction, + { + parent: { id: 'mySpanIdD' }, + processor: { event: 'span' }, + trace: { id: 'myTraceId' }, + service: { name: 'opbeans-ruby' }, + transaction: { id: 'myTransactionId1' }, + timestamp: { us: 1549324795825633 }, + span: { + duration: { us: 481 }, + name: 'SELECT FROM products', + id: 'mySpanIdB' + }, + child_ids: ['incorrectId', 'mySpanIdC'] + } as Span, + { + parent: { id: 'mySpanIdD' }, + processor: { event: 'span' }, + trace: { id: 'myTraceId' }, + service: { name: 'opbeans-ruby' }, + transaction: { id: 'myTransactionId1' }, + span: { + duration: { us: 6161 }, + name: 'Api::ProductsController#index', + id: 'mySpanIdA' + }, + timestamp: { us: 1549324795824504 } + } as Span, + { + parent: { id: 'mySpanIdD' }, + processor: { event: 'span' }, + trace: { id: 'myTraceId' }, + service: { name: 'opbeans-ruby' }, + transaction: { id: 'myTransactionId1' }, + span: { + duration: { us: 532 }, + name: 'SELECT FROM product', + id: 'mySpanIdC' + }, + timestamp: { us: 1549324795827905 } + } as Span, + { + parent: { id: 'myTransactionId1' }, + processor: { event: 'span' }, + trace: { id: 'myTraceId' }, + service: { name: 'opbeans-node' }, + transaction: { id: 'myTransactionId1' }, + span: { + duration: { us: 47557 }, + name: 'GET opbeans-ruby:3000/api/products', + id: 'mySpanIdD' + }, + timestamp: { us: 1549324795785760 } + } as Span + ]; + const entryTransactionId = 'myTransactionId1'; + const waterfall = getWaterfall( + { + trace: { items: traceItems, errorDocs: [], exceedsMax: false }, + errorsPerTransaction: {} + }, + entryTransactionId + ); + const getIdAndParentId = (item: IWaterfallItem) => ({ + id: item.id, + parentId: item.parent?.id + }); + expect(waterfall.items.length).toBe(5); + expect(getIdAndParentId(waterfall.items[0])).toEqual({ + id: 'myTransactionId1', + parentId: undefined + }); + expect(getIdAndParentId(waterfall.items[1])).toEqual({ + id: 'mySpanIdD', + parentId: 'myTransactionId1' + }); + expect(getIdAndParentId(waterfall.items[2])).toEqual({ + id: 'mySpanIdA', + parentId: 'mySpanIdD' + }); + expect(getIdAndParentId(waterfall.items[3])).toEqual({ + id: 'mySpanIdB', + parentId: 'mySpanIdD' + }); + expect(getIdAndParentId(waterfall.items[4])).toEqual({ + id: 'mySpanIdC', + parentId: 'mySpanIdB' + }); + expect(waterfall.errorItems.length).toBe(0); + expect(waterfall.errorsCount).toEqual(0); + }); }); describe('getWaterfallItems', () => { diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.ts b/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.ts index 58d9134c4d787b..8a873b2ddf1c91 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.ts +++ b/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.ts @@ -236,6 +236,29 @@ const getWaterfallItems = (items: TraceAPIResponse['trace']['items']) => } }); +/** + * Changes the parent_id of items based on the child_ids property. + * Solves the problem of Inferred spans that are created as child of trace spans + * when it actually should be its parent. + * @param waterfallItems + */ +const reparentSpans = (waterfallItems: IWaterfallItem[]) => { + return waterfallItems.map(waterfallItem => { + if (waterfallItem.docType === 'span') { + const { child_ids: childIds } = waterfallItem.doc; + if (childIds) { + childIds.forEach(childId => { + const item = waterfallItems.find(_item => _item.id === childId); + if (item) { + item.parentId = waterfallItem.id; + } + }); + } + } + return waterfallItem; + }); +}; + const getChildrenGroupedByParentId = (waterfallItems: IWaterfallItem[]) => groupBy(waterfallItems, item => (item.parentId ? item.parentId : ROOT_ID)); @@ -306,7 +329,9 @@ export function getWaterfall( const waterfallItems: IWaterfallItem[] = getWaterfallItems(trace.items); - const childrenByParentId = getChildrenGroupedByParentId(waterfallItems); + const childrenByParentId = getChildrenGroupedByParentId( + reparentSpans(waterfallItems) + ); const entryWaterfallTransaction = getEntryWaterfallTransaction( entryTransactionId, diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/WaterfallContainer.stories.tsx b/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/WaterfallContainer.stories.tsx index 938962cc9dd189..f681f4dfc675ad 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/WaterfallContainer.stories.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/WaterfallContainer.stories.tsx @@ -14,7 +14,8 @@ import { urlParams, simpleTrace, traceWithErrors, - traceChildStartBeforeParent + traceChildStartBeforeParent, + inferredSpans } from './waterfallContainer.stories.data'; import { getWaterfall } from './Waterfall/waterfall_helpers/waterfall_helpers'; @@ -74,3 +75,22 @@ storiesOf('app/TransactionDetails/Waterfall', module).add( }, { info: { source: false } } ); + +storiesOf('app/TransactionDetails/Waterfall', module).add( + 'inferred spans', + () => { + const waterfall = getWaterfall( + inferredSpans as TraceAPIResponse, + 'f2387d37260d00bd' + ); + return ( + + ); + }, + { info: { source: false } } +); diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/waterfallContainer.stories.data.ts b/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/waterfallContainer.stories.data.ts index 835183e73b298b..306c8e4f3fedbc 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/waterfallContainer.stories.data.ts +++ b/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/waterfallContainer.stories.data.ts @@ -1645,3 +1645,667 @@ export const traceChildStartBeforeParent = { }, errorsPerTransaction: {} }; + +export const inferredSpans = { + trace: { + items: [ + { + container: { + id: 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad' + }, + agent: { + name: 'java', + ephemeral_id: '1cb5c830-c677-4b13-b340-ab1502f527c3', + version: '1.15.1-SNAPSHOT' + }, + process: { + pid: 6, + title: '/opt/java/openjdk/bin/java', + ppid: 1 + }, + source: { + ip: '172.18.0.8' + }, + processor: { + name: 'transaction', + event: 'transaction' + }, + url: { + path: '/api/products/2', + scheme: 'http', + port: 3000, + domain: '172.18.0.7', + full: 'http://172.18.0.7:3000/api/products/2' + }, + observer: { + hostname: '7189f754b5a3', + id: 'f32d8d9f-a9f9-4355-8370-548dfd8024dc', + ephemeral_id: 'bff20764-0195-4f78-aa84-d799fc47b954', + type: 'apm-server', + version: '8.0.0', + version_major: 8 + }, + trace: { + id: '3b0dc77f3754e5bcb9da0e4c15e0db97' + }, + '@timestamp': '2020-04-09T11:36:00.786Z', + ecs: { + version: '1.5.0' + }, + service: { + node: { + name: + 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad' + }, + environment: 'production', + name: 'opbeans-java', + runtime: { + name: 'Java', + version: '11.0.6' + }, + language: { + name: 'Java', + version: '11.0.6' + }, + version: 'None' + }, + host: { + hostname: 'fc2ae281f56f', + os: { + platform: 'Linux' + }, + ip: '172.18.0.7', + name: 'fc2ae281f56f', + architecture: 'amd64' + }, + client: { + ip: '172.18.0.8' + }, + http: { + request: { + headers: { + Accept: ['*/*'], + 'User-Agent': ['Python/3.7 aiohttp/3.3.2'], + Host: ['172.18.0.7:3000'], + 'Accept-Encoding': ['gzip, deflate'] + }, + method: 'get', + socket: { + encrypted: false, + remote_address: '172.18.0.8' + } + }, + response: { + headers: { + 'Transfer-Encoding': ['chunked'], + Date: ['Thu, 09 Apr 2020 11:36:01 GMT'], + 'Content-Type': ['application/json;charset=UTF-8'] + }, + status_code: 200, + finished: true, + headers_sent: true + }, + version: '1.1' + }, + user_agent: { + original: 'Python/3.7 aiohttp/3.3.2', + name: 'Other', + device: { + name: 'Other' + } + }, + transaction: { + duration: { + us: 237537 + }, + result: 'HTTP 2xx', + name: 'APIRestController#product', + span_count: { + dropped: 0, + started: 3 + }, + id: 'f2387d37260d00bd', + type: 'request', + sampled: true + }, + timestamp: { + us: 1586432160786001 + } + }, + { + container: { + id: 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad' + }, + parent: { + id: 'f2387d37260d00bd' + }, + agent: { + name: 'java', + ephemeral_id: '1cb5c830-c677-4b13-b340-ab1502f527c3', + version: '1.15.1-SNAPSHOT' + }, + process: { + pid: 6, + title: '/opt/java/openjdk/bin/java', + ppid: 1 + }, + processor: { + name: 'transaction', + event: 'span' + }, + observer: { + hostname: '7189f754b5a3', + id: 'f32d8d9f-a9f9-4355-8370-548dfd8024dc', + ephemeral_id: 'bff20764-0195-4f78-aa84-d799fc47b954', + type: 'apm-server', + version: '8.0.0', + version_major: 8 + }, + trace: { + id: '3b0dc77f3754e5bcb9da0e4c15e0db97' + }, + '@timestamp': '2020-04-09T11:36:00.810Z', + ecs: { + version: '1.5.0' + }, + service: { + node: { + name: + 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad' + }, + environment: 'production', + name: 'opbeans-java', + runtime: { + name: 'Java', + version: '11.0.6' + }, + language: { + name: 'Java', + version: '11.0.6' + }, + version: 'None' + }, + host: { + hostname: 'fc2ae281f56f', + os: { + platform: 'Linux' + }, + ip: '172.18.0.7', + name: 'fc2ae281f56f', + architecture: 'amd64' + }, + transaction: { + id: 'f2387d37260d00bd' + }, + span: { + duration: { + us: 204574 + }, + subtype: 'inferred', + name: 'ServletInvocableHandlerMethod#invokeAndHandle', + id: 'a5df600bd7bd5e38', + type: 'app' + }, + timestamp: { + us: 1586432160810441 + } + }, + { + container: { + id: 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad' + }, + parent: { + id: 'a5df600bd7bd5e38' + }, + agent: { + name: 'java', + ephemeral_id: '1cb5c830-c677-4b13-b340-ab1502f527c3', + version: '1.15.1-SNAPSHOT' + }, + process: { + pid: 6, + title: '/opt/java/openjdk/bin/java', + ppid: 1 + }, + processor: { + name: 'transaction', + event: 'span' + }, + observer: { + hostname: '7189f754b5a3', + id: 'f32d8d9f-a9f9-4355-8370-548dfd8024dc', + type: 'apm-server', + ephemeral_id: 'bff20764-0195-4f78-aa84-d799fc47b954', + version: '8.0.0', + version_major: 8 + }, + trace: { + id: '3b0dc77f3754e5bcb9da0e4c15e0db97' + }, + '@timestamp': '2020-04-09T11:36:00.810Z', + ecs: { + version: '1.5.0' + }, + service: { + node: { + name: + 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad' + }, + environment: 'production', + name: 'opbeans-java', + runtime: { + name: 'Java', + version: '11.0.6' + }, + language: { + name: 'Java', + version: '11.0.6' + }, + version: 'None' + }, + host: { + hostname: 'fc2ae281f56f', + os: { + platform: 'Linux' + }, + ip: '172.18.0.7', + name: 'fc2ae281f56f', + architecture: 'amd64' + }, + transaction: { + id: 'f2387d37260d00bd' + }, + timestamp: { + us: 1586432160810441 + }, + span: { + duration: { + us: 102993 + }, + stacktrace: [ + { + library_frame: true, + exclude_from_grouping: false, + filename: 'InvocableHandlerMethod.java', + line: { + number: -1 + }, + function: 'doInvoke' + }, + { + exclude_from_grouping: false, + library_frame: true, + filename: 'InvocableHandlerMethod.java', + line: { + number: -1 + }, + function: 'invokeForRequest' + } + ], + subtype: 'inferred', + name: 'APIRestController#product', + id: '808dc34fc41ce522', + type: 'app' + } + }, + { + container: { + id: 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad' + }, + parent: { + id: 'f2387d37260d00bd' + }, + agent: { + name: 'java', + ephemeral_id: '1cb5c830-c677-4b13-b340-ab1502f527c3', + version: '1.15.1-SNAPSHOT' + }, + process: { + pid: 6, + title: '/opt/java/openjdk/bin/java', + ppid: 1 + }, + processor: { + name: 'transaction', + event: 'span' + }, + labels: { + productId: '2' + }, + observer: { + hostname: '7189f754b5a3', + id: 'f32d8d9f-a9f9-4355-8370-548dfd8024dc', + ephemeral_id: 'bff20764-0195-4f78-aa84-d799fc47b954', + type: 'apm-server', + version: '8.0.0', + version_major: 8 + }, + trace: { + id: '3b0dc77f3754e5bcb9da0e4c15e0db97' + }, + '@timestamp': '2020-04-09T11:36:00.832Z', + ecs: { + version: '1.5.0' + }, + service: { + node: { + name: + 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad' + }, + environment: 'production', + name: 'opbeans-java', + runtime: { + name: 'Java', + version: '11.0.6' + }, + language: { + name: 'Java', + version: '11.0.6' + }, + version: 'None' + }, + host: { + hostname: 'fc2ae281f56f', + os: { + platform: 'Linux' + }, + ip: '172.18.0.7', + name: 'fc2ae281f56f', + architecture: 'amd64' + }, + transaction: { + id: 'f2387d37260d00bd' + }, + timestamp: { + us: 1586432160832300 + }, + span: { + duration: { + us: 99295 + }, + name: 'OpenTracing product span', + id: '41226ae63af4f235', + type: 'unknown' + }, + child_ids: ['8d80de06aa11a6fc'] + }, + { + container: { + id: 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad' + }, + parent: { + id: '808dc34fc41ce522' + }, + process: { + pid: 6, + title: '/opt/java/openjdk/bin/java', + ppid: 1 + }, + agent: { + name: 'java', + ephemeral_id: '1cb5c830-c677-4b13-b340-ab1502f527c3', + version: '1.15.1-SNAPSHOT' + }, + processor: { + name: 'transaction', + event: 'span' + }, + observer: { + hostname: '7189f754b5a3', + id: 'f32d8d9f-a9f9-4355-8370-548dfd8024dc', + ephemeral_id: 'bff20764-0195-4f78-aa84-d799fc47b954', + type: 'apm-server', + version: '8.0.0', + version_major: 8 + }, + trace: { + id: '3b0dc77f3754e5bcb9da0e4c15e0db97' + }, + '@timestamp': '2020-04-09T11:36:00.859Z', + ecs: { + version: '1.5.0' + }, + service: { + node: { + name: + 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad' + }, + environment: 'production', + name: 'opbeans-java', + runtime: { + name: 'Java', + version: '11.0.6' + }, + language: { + name: 'Java', + version: '11.0.6' + }, + version: 'None' + }, + host: { + hostname: 'fc2ae281f56f', + os: { + platform: 'Linux' + }, + ip: '172.18.0.7', + name: 'fc2ae281f56f', + architecture: 'amd64' + }, + transaction: { + id: 'f2387d37260d00bd' + }, + timestamp: { + us: 1586432160859600 + }, + span: { + duration: { + us: 53835 + }, + subtype: 'inferred', + name: 'Loader#executeQueryStatement', + id: '8d80de06aa11a6fc', + type: 'app' + } + }, + { + container: { + id: 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad' + }, + parent: { + id: '41226ae63af4f235' + }, + agent: { + name: 'java', + ephemeral_id: '1cb5c830-c677-4b13-b340-ab1502f527c3', + version: '1.15.1-SNAPSHOT' + }, + process: { + pid: 6, + title: '/opt/java/openjdk/bin/java', + ppid: 1 + }, + destination: { + address: 'postgres', + port: 5432 + }, + processor: { + name: 'transaction', + event: 'span' + }, + observer: { + hostname: '7189f754b5a3', + id: 'f32d8d9f-a9f9-4355-8370-548dfd8024dc', + ephemeral_id: 'bff20764-0195-4f78-aa84-d799fc47b954', + type: 'apm-server', + version: '8.0.0', + version_major: 8 + }, + trace: { + id: '3b0dc77f3754e5bcb9da0e4c15e0db97' + }, + '@timestamp': '2020-04-09T11:36:00.903Z', + ecs: { + version: '1.5.0' + }, + service: { + node: { + name: + 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad' + }, + environment: 'production', + name: 'opbeans-java', + runtime: { + name: 'Java', + version: '11.0.6' + }, + language: { + name: 'Java', + version: '11.0.6' + }, + version: 'None' + }, + host: { + hostname: 'fc2ae281f56f', + os: { + platform: 'Linux' + }, + ip: '172.18.0.7', + name: 'fc2ae281f56f', + architecture: 'amd64' + }, + transaction: { + id: 'f2387d37260d00bd' + }, + timestamp: { + us: 1586432160903236 + }, + span: { + duration: { + us: 10211 + }, + subtype: 'postgresql', + destination: { + service: { + resource: 'postgresql', + name: 'postgresql', + type: 'db' + } + }, + name: 'SELECT FROM products', + action: 'query', + id: '3708d5623658182f', + type: 'db', + db: { + statement: + 'select product0_.id as col_0_0_, product0_.sku as col_1_0_, product0_.name as col_2_0_, product0_.description as col_3_0_, product0_.cost as col_4_0_, product0_.selling_price as col_5_0_, product0_.stock as col_6_0_, producttyp1_.id as col_7_0_, producttyp1_.name as col_8_0_, (select sum(orderline2_.amount) from order_lines orderline2_ where orderline2_.product_id=product0_.id) as col_9_0_ from products product0_ left outer join product_types producttyp1_ on product0_.type_id=producttyp1_.id where product0_.id=?', + type: 'sql', + user: { + name: 'postgres' + } + } + } + }, + { + container: { + id: 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad' + }, + parent: { + id: '41226ae63af4f235' + }, + process: { + pid: 6, + title: '/opt/java/openjdk/bin/java', + ppid: 1 + }, + agent: { + name: 'java', + ephemeral_id: '1cb5c830-c677-4b13-b340-ab1502f527c3', + version: '1.15.1-SNAPSHOT' + }, + destination: { + address: 'postgres', + port: 5432 + }, + processor: { + name: 'transaction', + event: 'span' + }, + observer: { + hostname: '7189f754b5a3', + id: 'f32d8d9f-a9f9-4355-8370-548dfd8024dc', + ephemeral_id: 'bff20764-0195-4f78-aa84-d799fc47b954', + type: 'apm-server', + version: '8.0.0', + version_major: 8 + }, + trace: { + id: '3b0dc77f3754e5bcb9da0e4c15e0db97' + }, + '@timestamp': '2020-04-09T11:36:00.859Z', + ecs: { + version: '1.5.0' + }, + service: { + node: { + name: + 'fc2ae281f56fb84728bc9b5e6c17f3d13bbb7f4efd461158558e5c38e655abad' + }, + environment: 'production', + name: 'opbeans-java', + runtime: { + name: 'Java', + version: '11.0.6' + }, + language: { + name: 'Java', + version: '11.0.6' + }, + version: 'None' + }, + host: { + hostname: 'fc2ae281f56f', + os: { + platform: 'Linux' + }, + ip: '172.18.0.7', + name: 'fc2ae281f56f', + architecture: 'amd64' + }, + transaction: { + id: 'f2387d37260d00bd' + }, + timestamp: { + us: 1586432160859508 + }, + span: { + duration: { + us: 4503 + }, + subtype: 'postgresql', + destination: { + service: { + resource: 'postgresql', + name: 'postgresql', + type: 'db' + } + }, + name: 'empty query', + action: 'query', + id: '9871cfd612368932', + type: 'db', + db: { + rows_affected: 0, + statement: '(empty query)', + type: 'sql', + user: { + name: 'postgres' + } + } + } + } + ], + exceedsMax: false, + errorDocs: [] + }, + errorsPerTransaction: {} +}; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.scss b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.scss index 04f2f393d1e80e..ae26a1bee99a6f 100644 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.scss +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/embeddable/embeddable.scss @@ -26,8 +26,4 @@ .euiTable { background: none; } - - .lnsExpressionRenderer { - @include euiScrollBar; - } -} \ No newline at end of file +} diff --git a/x-pack/legacy/plugins/logstash/README.md b/x-pack/legacy/plugins/logstash/README.md deleted file mode 100755 index 7d181249300fa3..00000000000000 --- a/x-pack/legacy/plugins/logstash/README.md +++ /dev/null @@ -1,3 +0,0 @@ -## Logstash Plugin - -This plugin adds Logstash specific UI code to x-pack. Currently this plugin adds just the management features. diff --git a/x-pack/legacy/plugins/logstash/common/lib/__tests__/get_moment.js b/x-pack/legacy/plugins/logstash/common/lib/__tests__/get_moment.js deleted file mode 100755 index 2e63b231bec32d..00000000000000 --- a/x-pack/legacy/plugins/logstash/common/lib/__tests__/get_moment.js +++ /dev/null @@ -1,33 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import expect from '@kbn/expect'; -import { getMoment } from '../get_moment'; - -describe('get_moment', () => { - describe('getMoment', () => { - it(`returns a moment object when passed a date`, () => { - const moment = getMoment('2017-03-30T14:53:08.121Z'); - - expect(moment.constructor.name).to.be('Moment'); - }); - - it(`returns null when passed falsy`, () => { - const results = [ - getMoment(false), - getMoment(0), - getMoment(''), - getMoment(null), - getMoment(undefined), - getMoment(NaN), - ]; - - results.forEach(result => { - expect(result).to.be(null); - }); - }); - }); -}); diff --git a/x-pack/legacy/plugins/logstash/common/lib/get_moment.js b/x-pack/legacy/plugins/logstash/common/lib/get_moment.js deleted file mode 100755 index 7a808ec9a0336f..00000000000000 --- a/x-pack/legacy/plugins/logstash/common/lib/get_moment.js +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import moment from 'moment'; - -export function getMoment(date) { - if (!date) { - return null; - } - - return moment(date); -} diff --git a/x-pack/legacy/plugins/logstash/index.js b/x-pack/legacy/plugins/logstash/index.js deleted file mode 100755 index 29f01032f34131..00000000000000 --- a/x-pack/legacy/plugins/logstash/index.js +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { resolve } from 'path'; -import { registerLicenseChecker } from './server/lib/register_license_checker'; -import { PLUGIN } from '../../../plugins/logstash/common/constants'; - -export const logstash = kibana => - new kibana.Plugin({ - id: PLUGIN.ID, - publicDir: resolve(__dirname, 'public'), - require: ['kibana', 'elasticsearch', 'xpack_main'], - configPrefix: 'xpack.logstash', - config(Joi) { - return Joi.object({ - enabled: Joi.boolean().default(true), - }).default(); - }, - uiExports: { - managementSections: [ - 'plugins/logstash/sections/pipeline_list', - 'plugins/logstash/sections/pipeline_edit', - ], - home: ['plugins/logstash/lib/register_home_feature'], - }, - init: server => { - registerLicenseChecker(server); - }, - }); diff --git a/x-pack/legacy/plugins/logstash/public/lib/register_home_feature.ts b/x-pack/legacy/plugins/logstash/public/lib/register_home_feature.ts deleted file mode 100644 index 2e1ee2afb9ce61..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/lib/register_home_feature.ts +++ /dev/null @@ -1,35 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; -import { npSetup } from 'ui/new_platform'; -// @ts-ignore -import { xpackInfo } from 'plugins/xpack_main/services/xpack_info'; -import { FeatureCatalogueCategory } from '../../../../../../src/plugins/home/public'; -// @ts-ignore -import { PLUGIN } from '../../../../../plugins/logstash/common/constants'; - -const { - plugins: { home }, -} = npSetup; - -const enableLinks = Boolean(xpackInfo.get(`features.${PLUGIN.ID}.enableLinks`)); - -if (enableLinks) { - home.featureCatalogue.register({ - id: 'management_logstash', - title: i18n.translate('xpack.logstash.homeFeature.logstashPipelinesTitle', { - defaultMessage: 'Logstash Pipelines', - }), - description: i18n.translate('xpack.logstash.homeFeature.logstashPipelinesDescription', { - defaultMessage: 'Create, delete, update, and clone data ingestion pipelines.', - }), - icon: 'pipelineApp', - path: '/app/kibana#/management/logstash/pipelines', - showOnHomePage: true, - category: FeatureCatalogueCategory.ADMIN, - }); -} diff --git a/x-pack/legacy/plugins/logstash/public/lib/update_management_sections/update_logstash_sections.js b/x-pack/legacy/plugins/logstash/public/lib/update_management_sections/update_logstash_sections.js deleted file mode 100755 index 8da687529c8463..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/lib/update_management_sections/update_logstash_sections.js +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { management } from 'ui/management'; - -export function updateLogstashSections(pipelineId) { - const editSection = management.getSection('logstash/pipelines/pipeline/edit'); - const newSection = management.getSection('logstash/pipelines/pipeline/new'); - - newSection.hide(); - editSection.hide(); - - if (pipelineId) { - editSection.url = `#/management/logstash/pipelines/pipeline/${pipelineId}/edit`; - editSection.show(); - } else { - newSection.show(); - } -} diff --git a/x-pack/legacy/plugins/logstash/public/sections/pipeline_edit/components/pipeline_edit/pipeline_edit.js b/x-pack/legacy/plugins/logstash/public/sections/pipeline_edit/components/pipeline_edit/pipeline_edit.js deleted file mode 100755 index 83446278fdeca8..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/sections/pipeline_edit/components/pipeline_edit/pipeline_edit.js +++ /dev/null @@ -1,60 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; -import { render } from 'react-dom'; -import { isEmpty } from 'lodash'; -import { uiModules } from 'ui/modules'; -import { npSetup } from 'ui/new_platform'; -import { toastNotifications } from 'ui/notify'; -import { I18nContext } from 'ui/i18n'; -import { PipelineEditor } from '../../../../components/pipeline_editor'; -import 'plugins/logstash/services/license'; -import { logstashSecurity } from 'plugins/logstash/services/security'; -import 'ace'; - -const app = uiModules.get('xpack/logstash'); - -app.directive('pipelineEdit', function($injector) { - const pipelineService = $injector.get('pipelineService'); - const licenseService = $injector.get('logstashLicenseService'); - const kbnUrl = $injector.get('kbnUrl'); - const $route = $injector.get('$route'); - - return { - restrict: 'E', - link: async (scope, el) => { - const close = () => scope.$evalAsync(kbnUrl.change('/management/logstash/pipelines', {})); - const open = id => - scope.$evalAsync(kbnUrl.change(`/management/logstash/pipelines/${id}/edit`)); - - const userResource = logstashSecurity.isSecurityEnabled() - ? await npSetup.plugins.security.authc.getCurrentUser() - : null; - - render( - - - , - el[0] - ); - }, - scope: { - pipeline: '=', - }, - }; -}); diff --git a/x-pack/legacy/plugins/logstash/public/sections/pipeline_edit/components/upgrade_failure/upgrade_failure.js b/x-pack/legacy/plugins/logstash/public/sections/pipeline_edit/components/upgrade_failure/upgrade_failure.js deleted file mode 100755 index 2ef99d3b476723..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/sections/pipeline_edit/components/upgrade_failure/upgrade_failure.js +++ /dev/null @@ -1,49 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; -import { render } from 'react-dom'; -import { isEmpty } from 'lodash'; -import { uiModules } from 'ui/modules'; -import { I18nContext } from 'ui/i18n'; -import { UpgradeFailure } from '../../../../components/upgrade_failure'; - -const app = uiModules.get('xpack/logstash'); - -app.directive('upgradeFailure', $injector => { - const $route = $injector.get('$route'); - const kbnUrl = $injector.get('kbnUrl'); - - return { - link: (scope, el) => { - const onRetry = () => { - $route.updateParams({ retry: true }); - $route.reload(); - }; - const onClose = () => { - scope.$evalAsync(kbnUrl.change('management/logstash/pipelines', {})); - }; - const isNewPipeline = isEmpty(scope.pipeline.id); - const isManualUpgrade = !!$route.current.params.retry; - - render( - - - , - el[0] - ); - }, - restrict: 'E', - scope: { - pipeline: '=', - }, - }; -}); diff --git a/x-pack/legacy/plugins/logstash/public/sections/pipeline_edit/pipeline_edit_route.html b/x-pack/legacy/plugins/logstash/public/sections/pipeline_edit/pipeline_edit_route.html deleted file mode 100755 index e1c422d46dfdb6..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/sections/pipeline_edit/pipeline_edit_route.html +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/x-pack/legacy/plugins/logstash/public/sections/pipeline_edit/pipeline_edit_route.js b/x-pack/legacy/plugins/logstash/public/sections/pipeline_edit/pipeline_edit_route.js deleted file mode 100755 index 733f7dc3ae2e62..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/sections/pipeline_edit/pipeline_edit_route.js +++ /dev/null @@ -1,87 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import routes from 'ui/routes'; -import { toastNotifications } from 'ui/notify'; -import { i18n } from '@kbn/i18n'; -import template from './pipeline_edit_route.html'; -import 'plugins/logstash/services/pipeline'; -import 'plugins/logstash/services/license'; -import 'plugins/logstash/services/upgrade'; -import './components/pipeline_edit'; -import './components/upgrade_failure'; -import { updateLogstashSections } from 'plugins/logstash/lib/update_management_sections'; -import { Pipeline } from 'plugins/logstash/models/pipeline'; -import { getPipelineCreateBreadcrumbs, getPipelineEditBreadcrumbs } from '../breadcrumbs'; - -routes - .when('/management/logstash/pipelines/pipeline/:id/edit', { - k7Breadcrumbs: getPipelineEditBreadcrumbs, - }) - .when('/management/logstash/pipelines/new-pipeline', { - k7Breadcrumbs: getPipelineCreateBreadcrumbs, - }) - .defaults(/management\/logstash\/pipelines\/(new-pipeline|pipeline\/:id\/edit)/, { - template: template, - controller: class PipelineEditRouteController { - constructor($injector) { - const $route = $injector.get('$route'); - this.pipeline = $route.current.locals.pipeline; - this.isUpgraded = $route.current.locals.isUpgraded; - } - }, - controllerAs: 'pipelineEditRoute', - resolve: { - logstashTabs: $injector => { - const $route = $injector.get('$route'); - const pipelineId = $route.current.params.id; - updateLogstashSections(pipelineId); - }, - pipeline: function($injector) { - const $route = $injector.get('$route'); - const pipelineService = $injector.get('pipelineService'); - const licenseService = $injector.get('logstashLicenseService'); - const kbnUrl = $injector.get('kbnUrl'); - - const pipelineId = $route.current.params.id; - - if (!pipelineId) return new Pipeline(); - - return pipelineService - .loadPipeline(pipelineId) - .then(pipeline => (!!$route.current.params.clone ? pipeline.clone : pipeline)) - .catch(err => { - return licenseService.checkValidity().then(() => { - if (err.status !== 403) { - toastNotifications.addDanger( - i18n.translate('xpack.logstash.couldNotLoadPipelineErrorNotification', { - defaultMessage: `Couldn't load pipeline. Error: '{errStatusText}'.`, - values: { - errStatusText: err.statusText, - }, - }) - ); - } - - kbnUrl.redirect('/management/logstash/pipelines'); - return Promise.reject(); - }); - }); - }, - checkLicense: $injector => { - const licenseService = $injector.get('logstashLicenseService'); - return licenseService.checkValidity(); - }, - isUpgraded: $injector => { - const upgradeService = $injector.get('upgradeService'); - return upgradeService.executeUpgrade(); - }, - }, - }); - -routes.when('/management/logstash/pipelines/pipeline/:id', { - redirectTo: '/management/logstash/pipelines/pipeline/:id/edit', -}); diff --git a/x-pack/legacy/plugins/logstash/public/sections/pipeline_list/components/pipeline_list/index.js b/x-pack/legacy/plugins/logstash/public/sections/pipeline_list/components/pipeline_list/index.js deleted file mode 100755 index 7e8ca0e4c2c576..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/sections/pipeline_list/components/pipeline_list/index.js +++ /dev/null @@ -1,7 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import './pipeline_list'; diff --git a/x-pack/legacy/plugins/logstash/public/sections/pipeline_list/components/pipeline_list/pipeline_list.js b/x-pack/legacy/plugins/logstash/public/sections/pipeline_list/components/pipeline_list/pipeline_list.js deleted file mode 100755 index b856979aed8b6d..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/sections/pipeline_list/components/pipeline_list/pipeline_list.js +++ /dev/null @@ -1,58 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; -import { render } from 'react-dom'; -import { uiModules } from 'ui/modules'; -import { toastNotifications } from 'ui/notify'; -import { I18nContext } from 'ui/i18n'; -import { PipelineList } from '../../../../components/pipeline_list'; -import 'plugins/logstash/services/pipelines'; -import 'plugins/logstash/services/license'; -import 'plugins/logstash/services/cluster'; -import 'plugins/logstash/services/monitoring'; - -const app = uiModules.get('xpack/logstash'); - -app.directive('pipelineList', function($injector) { - const pipelinesService = $injector.get('pipelinesService'); - const licenseService = $injector.get('logstashLicenseService'); - const clusterService = $injector.get('xpackLogstashClusterService'); - const monitoringService = $injector.get('xpackLogstashMonitoringService'); - const kbnUrl = $injector.get('kbnUrl'); - - return { - restrict: 'E', - link: (scope, el) => { - const openPipeline = id => - scope.$evalAsync(kbnUrl.change(`management/logstash/pipelines/pipeline/${id}/edit`)); - const createPipeline = () => - scope.$evalAsync(kbnUrl.change('management/logstash/pipelines/new-pipeline')); - const clonePipeline = id => - scope.$evalAsync(kbnUrl.change(`management/logstash/pipelines/pipeline/${id}/edit?clone`)); - render( - - - , - el[0] - ); - }, - scope: {}, - controllerAs: 'pipelineList', - }; -}); diff --git a/x-pack/legacy/plugins/logstash/public/sections/pipeline_list/index.js b/x-pack/legacy/plugins/logstash/public/sections/pipeline_list/index.js deleted file mode 100755 index f60decd1378d5c..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/sections/pipeline_list/index.js +++ /dev/null @@ -1,8 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import './register_management_section'; -import './pipeline_list_route'; diff --git a/x-pack/legacy/plugins/logstash/public/sections/pipeline_list/pipeline_list_route.html b/x-pack/legacy/plugins/logstash/public/sections/pipeline_list/pipeline_list_route.html deleted file mode 100755 index 55b3fabd701614..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/sections/pipeline_list/pipeline_list_route.html +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/x-pack/legacy/plugins/logstash/public/sections/pipeline_list/pipeline_list_route.js b/x-pack/legacy/plugins/logstash/public/sections/pipeline_list/pipeline_list_route.js deleted file mode 100755 index eb593207572c20..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/sections/pipeline_list/pipeline_list_route.js +++ /dev/null @@ -1,33 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import routes from 'ui/routes'; -import { management } from 'ui/management'; -import template from './pipeline_list_route.html'; -import './components/pipeline_list'; -import 'plugins/logstash/services/license'; -import { getPipelineListBreadcrumbs } from '../breadcrumbs'; - -routes.when('/management/logstash/pipelines/', { - template, - k7Breadcrumbs: getPipelineListBreadcrumbs, -}); - -routes.defaults(/\/management/, { - resolve: { - logstashManagementSection: $injector => { - const licenseService = $injector.get('logstashLicenseService'); - const logstashSection = management.getSection('logstash/pipelines'); - - if (licenseService.enableLinks) { - logstashSection.show(); - logstashSection.enable(); - } else { - logstashSection.hide(); - } - }, - }, -}); diff --git a/x-pack/legacy/plugins/logstash/public/sections/pipeline_list/register_management_section.js b/x-pack/legacy/plugins/logstash/public/sections/pipeline_list/register_management_section.js deleted file mode 100755 index e285418f5f2ae5..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/sections/pipeline_list/register_management_section.js +++ /dev/null @@ -1,36 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { management } from 'ui/management'; -import { i18n } from '@kbn/i18n'; - -management.getSection('logstash').register('pipelines', { - display: i18n.translate('xpack.logstash.managementSection.pipelinesTitle', { - defaultMessage: 'Pipelines', - }), - order: 10, - url: '#/management/logstash/pipelines/', -}); - -management.getSection('logstash/pipelines').register('pipeline', { - visible: false, -}); - -management.getSection('logstash/pipelines/pipeline').register('edit', { - display: i18n.translate('xpack.logstash.managementSection.editPipelineTitle', { - defaultMessage: 'Edit pipeline', - }), - order: 1, - visible: false, -}); - -management.getSection('logstash/pipelines/pipeline').register('new', { - display: i18n.translate('xpack.logstash.managementSection.createPipelineTitle', { - defaultMessage: 'Create pipeline', - }), - order: 1, - visible: false, -}); diff --git a/x-pack/legacy/plugins/logstash/public/services/cluster/cluster_service.factory.js b/x-pack/legacy/plugins/logstash/public/services/cluster/cluster_service.factory.js deleted file mode 100755 index 0fee2804c704d4..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/services/cluster/cluster_service.factory.js +++ /dev/null @@ -1,13 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { uiModules } from 'ui/modules'; -import { ClusterService } from './cluster_service'; - -uiModules.get('xpack/logstash').factory('xpackLogstashClusterService', $injector => { - const $http = $injector.get('$http'); - return new ClusterService($http); -}); diff --git a/x-pack/legacy/plugins/logstash/public/services/cluster/index.js b/x-pack/legacy/plugins/logstash/public/services/cluster/index.js deleted file mode 100755 index ba52657a27ca8b..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/services/cluster/index.js +++ /dev/null @@ -1,7 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import './cluster_service.factory'; diff --git a/x-pack/legacy/plugins/logstash/public/services/license/index.js b/x-pack/legacy/plugins/logstash/public/services/license/index.js deleted file mode 100755 index 8be8fb5ccbc64f..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/services/license/index.js +++ /dev/null @@ -1,7 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import './license_service.factory'; diff --git a/x-pack/legacy/plugins/logstash/public/services/license/license_service.factory.js b/x-pack/legacy/plugins/logstash/public/services/license/license_service.factory.js deleted file mode 100755 index 0e131f9b94008d..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/services/license/license_service.factory.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { uiModules } from 'ui/modules'; -import { xpackInfo } from 'plugins/xpack_main/services/xpack_info'; -import 'ui/url'; -import { LogstashLicenseService } from './logstash_license_service'; - -uiModules.get('xpack/logstash').factory('logstashLicenseService', ($timeout, kbnUrl) => { - return new LogstashLicenseService(xpackInfo, kbnUrl, $timeout); -}); diff --git a/x-pack/legacy/plugins/logstash/public/services/license/logstash_license_service.js b/x-pack/legacy/plugins/logstash/public/services/license/logstash_license_service.js deleted file mode 100755 index 69cc8614a6ae26..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/services/license/logstash_license_service.js +++ /dev/null @@ -1,62 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; -import { toastNotifications } from 'ui/notify'; -import { MarkdownSimple } from '../../../../../../../src/plugins/kibana_react/public'; -import { PLUGIN } from '../../../../../../plugins/logstash/common/constants'; - -export class LogstashLicenseService { - constructor(xpackInfoService, kbnUrlService, $timeout) { - this.xpackInfoService = xpackInfoService; - this.kbnUrlService = kbnUrlService; - this.$timeout = $timeout; - } - - get enableLinks() { - return Boolean(this.xpackInfoService.get(`features.${PLUGIN.ID}.enableLinks`)); - } - - get isAvailable() { - return Boolean(this.xpackInfoService.get(`features.${PLUGIN.ID}.isAvailable`)); - } - - get isReadOnly() { - return Boolean(this.xpackInfoService.get(`features.${PLUGIN.ID}.isReadOnly`)); - } - - get message() { - return this.xpackInfoService.get(`features.${PLUGIN.ID}.message`); - } - - notifyAndRedirect() { - toastNotifications.addDanger({ - title: ( - - {this.xpackInfoService.get(`features.${PLUGIN.ID}.message`)} - - ), - }); - this.kbnUrlService.redirect('/management'); - } - - /** - * Checks if the license is valid or the license can perform downgraded UI tasks. - * Otherwise, notifies and redirects. - */ - checkValidity() { - return new Promise((resolve, reject) => { - this.$timeout(() => { - if (this.isAvailable) { - return resolve(); - } - - this.notifyAndRedirect(); - return reject(); - }, 10); // To allow latest XHR call to update license info - }); - } -} diff --git a/x-pack/legacy/plugins/logstash/public/services/monitoring/index.js b/x-pack/legacy/plugins/logstash/public/services/monitoring/index.js deleted file mode 100755 index 83b2105beb5ef8..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/services/monitoring/index.js +++ /dev/null @@ -1,7 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import './monitoring_service.factory'; diff --git a/x-pack/legacy/plugins/logstash/public/services/monitoring/monitoring_service.factory.js b/x-pack/legacy/plugins/logstash/public/services/monitoring/monitoring_service.factory.js deleted file mode 100755 index 271c776dd6f69c..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/services/monitoring/monitoring_service.factory.js +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { uiModules } from 'ui/modules'; -import { MonitoringService } from './monitoring_service'; -import '../cluster'; - -uiModules.get('xpack/logstash').factory('xpackLogstashMonitoringService', $injector => { - const $http = $injector.get('$http'); - const Promise = $injector.get('Promise'); - const monitoringUiEnabled = - $injector.has('monitoringUiEnabled') && $injector.get('monitoringUiEnabled'); - const clusterService = $injector.get('xpackLogstashClusterService'); - return new MonitoringService($http, Promise, monitoringUiEnabled, clusterService); -}); diff --git a/x-pack/legacy/plugins/logstash/public/services/pipeline/index.js b/x-pack/legacy/plugins/logstash/public/services/pipeline/index.js deleted file mode 100755 index 3b0e28bd555e6f..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/services/pipeline/index.js +++ /dev/null @@ -1,7 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import './pipeline_service.factory'; diff --git a/x-pack/legacy/plugins/logstash/public/services/pipeline/pipeline_service.factory.js b/x-pack/legacy/plugins/logstash/public/services/pipeline/pipeline_service.factory.js deleted file mode 100755 index cf93915425213b..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/services/pipeline/pipeline_service.factory.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { uiModules } from 'ui/modules'; -import { PipelineService } from './pipeline_service'; - -uiModules.get('xpack/logstash').factory('pipelineService', $injector => { - const $http = $injector.get('$http'); - const pipelinesService = $injector.get('pipelinesService'); - return new PipelineService($http, pipelinesService); -}); diff --git a/x-pack/legacy/plugins/logstash/public/services/pipeline/pipeline_service.js b/x-pack/legacy/plugins/logstash/public/services/pipeline/pipeline_service.js deleted file mode 100755 index b5d0dbeb852d52..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/services/pipeline/pipeline_service.js +++ /dev/null @@ -1,40 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import chrome from 'ui/chrome'; -import { ROUTES } from '../../../../../../plugins/logstash/common/constants'; -import { Pipeline } from 'plugins/logstash/models/pipeline'; - -export class PipelineService { - constructor($http, pipelinesService) { - this.$http = $http; - this.pipelinesService = pipelinesService; - this.basePath = chrome.addBasePath(ROUTES.API_ROOT); - } - - loadPipeline(id) { - return this.$http.get(`${this.basePath}/pipeline/${id}`).then(response => { - return Pipeline.fromUpstreamJSON(response.data); - }); - } - - savePipeline(pipelineModel) { - return this.$http - .put(`${this.basePath}/pipeline/${pipelineModel.id}`, pipelineModel.upstreamJSON) - .catch(e => { - throw e.data.message; - }); - } - - deletePipeline(id) { - return this.$http - .delete(`${this.basePath}/pipeline/${id}`) - .then(() => this.pipelinesService.addToRecentlyDeleted(id)) - .catch(e => { - throw e.data.message; - }); - } -} diff --git a/x-pack/legacy/plugins/logstash/public/services/pipelines/index.js b/x-pack/legacy/plugins/logstash/public/services/pipelines/index.js deleted file mode 100755 index e273e12d46c6d0..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/services/pipelines/index.js +++ /dev/null @@ -1,7 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import './pipelines_service.factory'; diff --git a/x-pack/legacy/plugins/logstash/public/services/pipelines/pipelines_service.factory.js b/x-pack/legacy/plugins/logstash/public/services/pipelines/pipelines_service.factory.js deleted file mode 100755 index 9295949e001eb3..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/services/pipelines/pipelines_service.factory.js +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { uiModules } from 'ui/modules'; -import { PipelinesService } from './pipelines_service'; -import '../monitoring'; - -uiModules.get('xpack/logstash').factory('pipelinesService', $injector => { - const $http = $injector.get('$http'); - const $window = $injector.get('$window'); - const Promise = $injector.get('Promise'); - const monitoringService = $injector.get('xpackLogstashMonitoringService'); - return new PipelinesService($http, $window, Promise, monitoringService); -}); diff --git a/x-pack/legacy/plugins/logstash/public/services/pipelines/pipelines_service.js b/x-pack/legacy/plugins/logstash/public/services/pipelines/pipelines_service.js deleted file mode 100755 index d70c8be06fde4d..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/services/pipelines/pipelines_service.js +++ /dev/null @@ -1,135 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import chrome from 'ui/chrome'; -import { ROUTES, MONITORING } from '../../../../../../plugins/logstash/common/constants'; -import { PipelineListItem } from 'plugins/logstash/models/pipeline_list_item'; - -const RECENTLY_DELETED_PIPELINE_IDS_STORAGE_KEY = 'xpack.logstash.recentlyDeletedPipelines'; - -export class PipelinesService { - constructor($http, $window, Promise, monitoringService) { - this.$http = $http; - this.$window = $window; - this.Promise = Promise; - this.monitoringService = monitoringService; - this.basePath = chrome.addBasePath(ROUTES.API_ROOT); - } - - getPipelineList() { - return this.Promise.all([ - this.getManagementPipelineList(), - this.getMonitoringPipelineList(), - ]).then(([managementPipelines, monitoringPipelines]) => { - const now = Date.now(); - - // Monitoring will report centrally-managed pipelines as well, including recently-deleted centrally-managed ones. - // If there's a recently-deleted pipeline we're keeping track of BUT monitoring doesn't report it, that means - // it's not running in Logstash any more. So we can stop tracking it as a recently-deleted pipeline. - const monitoringPipelineIds = monitoringPipelines.map(pipeline => pipeline.id); - this.getRecentlyDeleted().forEach(recentlyDeletedPipeline => { - // We don't want to stop tracking the recently-deleted pipeline until Monitoring has had some - // time to report on it. Otherwise, if we stop tracking first, *then* Monitoring reports it, we'll - // still end up showing it in the list until Monitoring stops reporting it. - if (now - recentlyDeletedPipeline.deletedOn < MONITORING.ACTIVE_PIPELINE_RANGE_S * 1000) { - return; - } - - // If Monitoring is still reporting the pipeline, don't stop tracking it yet - if (monitoringPipelineIds.includes(recentlyDeletedPipeline.id)) { - return; - } - - this.removeFromRecentlyDeleted(recentlyDeletedPipeline.id); - }); - - // Merge centrally-managed pipelines with pipelines reported by monitoring. Take care to dedupe - // while merging because monitoring will (rightly) report centrally-managed pipelines as well, - // including recently-deleted ones! - const managementPipelineIds = managementPipelines.map(pipeline => pipeline.id); - return managementPipelines.concat( - monitoringPipelines.filter( - monitoringPipeline => - !managementPipelineIds.includes(monitoringPipeline.id) && - !this.isRecentlyDeleted(monitoringPipeline.id) - ) - ); - }); - } - - getManagementPipelineList() { - return this.$http - .get(`${this.basePath}/pipelines`) - .then(response => - response.data.pipelines.map(pipeline => PipelineListItem.fromUpstreamJSON(pipeline)) - ); - } - - getMonitoringPipelineList() { - return this.monitoringService.getPipelineList(); - } - - /** - * Delete a collection of pipelines - * - * @param pipelineIds Array of pipeline IDs - * @return Promise { numSuccesses, numErrors } - */ - deletePipelines(pipelineIds) { - const body = { - pipelineIds, - }; - return this.$http.post(`${this.basePath}/pipelines/delete`, body).then(response => { - this.addToRecentlyDeleted(...pipelineIds); - return response.data.results; - }); - } - - addToRecentlyDeleted(...pipelineIds) { - const recentlyDeletedPipelines = this.getRecentlyDeleted(); - const recentlyDeletedPipelineIds = recentlyDeletedPipelines.map(pipeline => pipeline.id); - pipelineIds.forEach(pipelineId => { - if (!recentlyDeletedPipelineIds.includes(pipelineId)) { - recentlyDeletedPipelines.push({ - id: pipelineId, - deletedOn: Date.now(), - }); - } - }); - this.setRecentlyDeleted(recentlyDeletedPipelines); - } - - removeFromRecentlyDeleted(...pipelineIds) { - const recentlyDeletedPipelinesToKeep = this.getRecentlyDeleted().filter( - recentlyDeletedPipeline => !pipelineIds.includes(recentlyDeletedPipeline.id) - ); - this.setRecentlyDeleted(recentlyDeletedPipelinesToKeep); - } - - isRecentlyDeleted(pipelineId) { - return this.getRecentlyDeleted() - .map(pipeline => pipeline.id) - .includes(pipelineId); - } - - getRecentlyDeleted() { - const recentlyDeletedPipelines = this.$window.localStorage.getItem( - RECENTLY_DELETED_PIPELINE_IDS_STORAGE_KEY - ); - if (!recentlyDeletedPipelines) { - return []; - } - - return JSON.parse(recentlyDeletedPipelines); - } - - setRecentlyDeleted(recentlyDeletedPipelineIds) { - this.$window.localStorage.setItem( - RECENTLY_DELETED_PIPELINE_IDS_STORAGE_KEY, - JSON.stringify(recentlyDeletedPipelineIds) - ); - } -} diff --git a/x-pack/legacy/plugins/logstash/public/services/security/index.js b/x-pack/legacy/plugins/logstash/public/services/security/index.js deleted file mode 100755 index c9ff911723156f..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/services/security/index.js +++ /dev/null @@ -1,7 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -export { logstashSecurity } from './logstash_security'; diff --git a/x-pack/legacy/plugins/logstash/public/services/security/logstash_security.js b/x-pack/legacy/plugins/logstash/public/services/security/logstash_security.js deleted file mode 100755 index 0949038c9b6c73..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/services/security/logstash_security.js +++ /dev/null @@ -1,13 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { xpackInfo } from 'plugins/xpack_main/services/xpack_info'; - -export const logstashSecurity = { - isSecurityEnabled() { - return Boolean(xpackInfo.get(`features.security`)); - }, -}; diff --git a/x-pack/legacy/plugins/logstash/public/services/upgrade/index.js b/x-pack/legacy/plugins/logstash/public/services/upgrade/index.js deleted file mode 100755 index 345d0d0ff68c6d..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/services/upgrade/index.js +++ /dev/null @@ -1,7 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import './upgrade_service.factory'; diff --git a/x-pack/legacy/plugins/logstash/public/services/upgrade/upgrade_service.factory.js b/x-pack/legacy/plugins/logstash/public/services/upgrade/upgrade_service.factory.js deleted file mode 100755 index 925c6ae677bdf7..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/services/upgrade/upgrade_service.factory.js +++ /dev/null @@ -1,13 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { uiModules } from 'ui/modules'; -import { UpgradeService } from './upgrade_service'; - -uiModules.get('xpack/logstash').factory('upgradeService', $injector => { - const $http = $injector.get('$http'); - return new UpgradeService($http); -}); diff --git a/x-pack/legacy/plugins/logstash/public/services/upgrade/upgrade_service.js b/x-pack/legacy/plugins/logstash/public/services/upgrade/upgrade_service.js deleted file mode 100755 index 2019bdc1bf1aaa..00000000000000 --- a/x-pack/legacy/plugins/logstash/public/services/upgrade/upgrade_service.js +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import chrome from 'ui/chrome'; -import { ROUTES } from '../../../../../../plugins/logstash/common/constants'; - -export class UpgradeService { - constructor($http) { - this.$http = $http; - this.basePath = chrome.addBasePath(ROUTES.API_ROOT); - } - - executeUpgrade() { - return this.$http - .post(`${this.basePath}/upgrade`) - .then(response => response.data.is_upgraded) - .catch(e => { - throw e.data.message; - }); - } -} diff --git a/x-pack/legacy/plugins/logstash/server/lib/check_license/__tests__/check_license.js b/x-pack/legacy/plugins/logstash/server/lib/check_license/__tests__/check_license.js deleted file mode 100755 index 5fcce0aaa12190..00000000000000 --- a/x-pack/legacy/plugins/logstash/server/lib/check_license/__tests__/check_license.js +++ /dev/null @@ -1,179 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import expect from '@kbn/expect'; -import { set } from 'lodash'; -import { checkLicense } from '../check_license'; - -describe('check_license', function() { - let mockLicenseInfo; - beforeEach(() => (mockLicenseInfo = {})); - - describe('license information is undefined', () => { - beforeEach(() => (mockLicenseInfo = undefined)); - - it('should set isAvailable to false', () => { - expect(checkLicense(mockLicenseInfo).isAvailable).to.be(false); - }); - - it('should set enableLinks to false', () => { - expect(checkLicense(mockLicenseInfo).enableLinks).to.be(false); - }); - - it('should set isReadOnly to false', () => { - expect(checkLicense(mockLicenseInfo).isReadOnly).to.be(false); - }); - - it('should set a message', () => { - expect(checkLicense(mockLicenseInfo).message).to.not.be(undefined); - }); - }); - - describe('license information is not available', () => { - beforeEach(() => (mockLicenseInfo.isAvailable = () => false)); - - it('should set isAvailable to false', () => { - expect(checkLicense(mockLicenseInfo).isAvailable).to.be(false); - }); - - it('should set enableLinks to false', () => { - expect(checkLicense(mockLicenseInfo).enableLinks).to.be(false); - }); - - it('should set isReadOnly to false', () => { - expect(checkLicense(mockLicenseInfo).isReadOnly).to.be(false); - }); - - it('should set a message', () => { - expect(checkLicense(mockLicenseInfo).message).to.not.be(undefined); - }); - }); - - describe('license information is available', () => { - beforeEach(() => { - mockLicenseInfo.isAvailable = () => true; - set(mockLicenseInfo, 'license.getType', () => 'basic'); - }); - - describe('& license is > basic', () => { - beforeEach(() => { - set(mockLicenseInfo, 'license.isOneOf', () => true); - mockLicenseInfo.feature = () => ({ isEnabled: () => true }); // Security feature is enabled - }); - - describe('& license is active', () => { - beforeEach(() => set(mockLicenseInfo, 'license.isActive', () => true)); - - it('should set isAvailable to true', () => { - expect(checkLicense(mockLicenseInfo).isAvailable).to.be(true); - }); - - it('should set enableLinks to true', () => { - expect(checkLicense(mockLicenseInfo).enableLinks).to.be(true); - }); - - it('should set isReadOnly to false', () => { - expect(checkLicense(mockLicenseInfo).isReadOnly).to.be(false); - }); - - it('should not set a message', () => { - expect(checkLicense(mockLicenseInfo).message).to.be(undefined); - }); - }); - - describe('& license is expired', () => { - beforeEach(() => set(mockLicenseInfo, 'license.isActive', () => false)); - - it('should set isAvailable to true', () => { - expect(checkLicense(mockLicenseInfo).isAvailable).to.be(true); - }); - - it('should set enableLinks to true', () => { - expect(checkLicense(mockLicenseInfo).enableLinks).to.be(true); - }); - - it('should set isReadOnly to true', () => { - expect(checkLicense(mockLicenseInfo).isReadOnly).to.be(true); - }); - - it('should set a message', () => { - expect(checkLicense(mockLicenseInfo).message).to.not.be(undefined); - }); - }); - }); - - describe('& license is basic', () => { - beforeEach(() => { - set(mockLicenseInfo, 'license.isOneOf', () => false); - mockLicenseInfo.feature = () => ({ isEnabled: () => true }); // Security feature is enabled - }); - - describe('& license is active', () => { - beforeEach(() => set(mockLicenseInfo, 'license.isActive', () => true)); - - it('should set isAvailable to false', () => { - expect(checkLicense(mockLicenseInfo).isAvailable).to.be(false); - }); - - it('should set enableLinks to false', () => { - expect(checkLicense(mockLicenseInfo).enableLinks).to.be(false); - }); - - it('should set isReadOnly to false', () => { - expect(checkLicense(mockLicenseInfo).isReadOnly).to.be(false); - }); - - it('should set a message', () => { - expect(checkLicense(mockLicenseInfo).message).to.not.be(undefined); - }); - }); - - describe('& license is expired', () => { - beforeEach(() => set(mockLicenseInfo, 'license.isActive', () => false)); - - it('should set isAvailable to false', () => { - expect(checkLicense(mockLicenseInfo).isAvailable).to.be(false); - }); - - it('should set enableLinks to false', () => { - expect(checkLicense(mockLicenseInfo).enableLinks).to.be(false); - }); - - it('should set isReadOnly to false', () => { - expect(checkLicense(mockLicenseInfo).isReadOnly).to.be(false); - }); - - it('should set a message', () => { - expect(checkLicense(mockLicenseInfo).message).to.not.be(undefined); - }); - }); - }); - - describe('& security is disabled', () => { - beforeEach(() => { - mockLicenseInfo.feature = () => ({ isEnabled: () => false }); // Security feature is disabled - set(mockLicenseInfo, 'license.isOneOf', () => true); - set(mockLicenseInfo, 'license.isActive', () => true); - }); - - it('should set isAvailable to false', () => { - expect(checkLicense(mockLicenseInfo).isAvailable).to.be(false); - }); - - it('should set enableLinks to false', () => { - expect(checkLicense(mockLicenseInfo).enableLinks).to.be(false); - }); - - it('should set isReadOnly to false', () => { - expect(checkLicense(mockLicenseInfo).isReadOnly).to.be(false); - }); - - it('should set a message', () => { - expect(checkLicense(mockLicenseInfo).message).to.not.be(undefined); - }); - }); - }); -}); diff --git a/x-pack/legacy/plugins/logstash/server/lib/check_license/check_license.js b/x-pack/legacy/plugins/logstash/server/lib/check_license/check_license.js deleted file mode 100755 index 31136ae1c72a5c..00000000000000 --- a/x-pack/legacy/plugins/logstash/server/lib/check_license/check_license.js +++ /dev/null @@ -1,86 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; - -export function checkLicense(xpackLicenseInfo) { - // If, for some reason, we cannot get the license information - // from Elasticsearch, assume worst case and disable the Logstash pipeline UI - if (!xpackLicenseInfo || !xpackLicenseInfo.isAvailable()) { - return { - isAvailable: false, - enableLinks: false, - isReadOnly: false, - message: i18n.translate( - 'xpack.logstash.managementSection.notPossibleToManagePipelinesMessage', - { - defaultMessage: - 'You cannot manage Logstash pipelines because license information is not available at this time.', - } - ), - }; - } - - const VALID_LICENSE_MODES = ['trial', 'standard', 'gold', 'platinum', 'enterprise']; - - const isLicenseModeValid = xpackLicenseInfo.license.isOneOf(VALID_LICENSE_MODES); - const isLicenseActive = xpackLicenseInfo.license.isActive(); - const licenseType = xpackLicenseInfo.license.getType(); - const isSecurityEnabled = xpackLicenseInfo.feature('security').isEnabled(); - - // Security is not enabled in ES - if (!isSecurityEnabled) { - const message = i18n.translate('xpack.logstash.managementSection.enableSecurityDescription', { - defaultMessage: - 'Security must be enabled in order to use Logstash pipeline management features.' + - ' Please set xpack.security.enabled: true in your elasticsearch.yml.', - }); - return { - isAvailable: false, - enableLinks: false, - isReadOnly: false, - message, - }; - } - - // License is not valid - if (!isLicenseModeValid) { - return { - isAvailable: false, - enableLinks: false, - isReadOnly: false, - message: i18n.translate('xpack.logstash.managementSection.licenseDoesNotSupportDescription', { - defaultMessage: - 'Your {licenseType} license does not support Logstash pipeline management features. Please upgrade your license.', - values: { licenseType }, - }), - }; - } - - // License is valid but not active, we go into a read-only mode. - if (!isLicenseActive) { - return { - isAvailable: true, - enableLinks: true, - isReadOnly: true, - message: i18n.translate( - 'xpack.logstash.managementSection.pipelineCrudOperationsNotAllowedDescription', - { - defaultMessage: - 'You cannot edit, create, or delete your Logstash pipelines because your {licenseType} license has expired.', - values: { licenseType }, - } - ), - }; - } - - // License is valid and active - return { - isAvailable: true, - enableLinks: true, - isReadOnly: false, - }; -} diff --git a/x-pack/legacy/plugins/logstash/server/lib/check_license/index.js b/x-pack/legacy/plugins/logstash/server/lib/check_license/index.js deleted file mode 100755 index f2c070fd44b6e6..00000000000000 --- a/x-pack/legacy/plugins/logstash/server/lib/check_license/index.js +++ /dev/null @@ -1,7 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -export { checkLicense } from './check_license'; diff --git a/x-pack/legacy/plugins/logstash/server/lib/register_license_checker/index.js b/x-pack/legacy/plugins/logstash/server/lib/register_license_checker/index.js deleted file mode 100755 index 7b0f97c38d1292..00000000000000 --- a/x-pack/legacy/plugins/logstash/server/lib/register_license_checker/index.js +++ /dev/null @@ -1,7 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -export { registerLicenseChecker } from './register_license_checker'; diff --git a/x-pack/legacy/plugins/logstash/server/lib/register_license_checker/register_license_checker.js b/x-pack/legacy/plugins/logstash/server/lib/register_license_checker/register_license_checker.js deleted file mode 100755 index a0d06e77b410d2..00000000000000 --- a/x-pack/legacy/plugins/logstash/server/lib/register_license_checker/register_license_checker.js +++ /dev/null @@ -1,21 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { mirrorPluginStatus } from '../../../../../server/lib/mirror_plugin_status'; -import { checkLicense } from '../check_license'; -import { PLUGIN } from '../../../../../../plugins/logstash/common/constants'; - -export function registerLicenseChecker(server) { - const xpackMainPlugin = server.plugins.xpack_main; - const logstashPlugin = server.plugins.logstash; - - mirrorPluginStatus(xpackMainPlugin, logstashPlugin); - xpackMainPlugin.status.once('green', () => { - // Register a function that is called whenever the xpack info changes, - // to re-compute the license check results for this plugin - xpackMainPlugin.info.feature(PLUGIN.ID).registerLicenseCheckResultsGenerator(checkLicense); - }); -} diff --git a/x-pack/legacy/plugins/maps/common/constants.ts b/x-pack/legacy/plugins/maps/common/constants.ts deleted file mode 100644 index 98945653c25dc8..00000000000000 --- a/x-pack/legacy/plugins/maps/common/constants.ts +++ /dev/null @@ -1,8 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -export * from '../../../../plugins/maps/common/constants'; diff --git a/x-pack/legacy/plugins/maps/common/get_join_key.ts b/x-pack/legacy/plugins/maps/common/get_join_key.ts deleted file mode 100644 index 004f12ca08d2ea..00000000000000 --- a/x-pack/legacy/plugins/maps/common/get_join_key.ts +++ /dev/null @@ -1,8 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -export * from '../../../../plugins/maps/common/get_join_key'; diff --git a/x-pack/legacy/plugins/maps/common/i18n_getters.ts b/x-pack/legacy/plugins/maps/common/i18n_getters.ts deleted file mode 100644 index f9d186dea2e2b9..00000000000000 --- a/x-pack/legacy/plugins/maps/common/i18n_getters.ts +++ /dev/null @@ -1,8 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -export * from '../../../../plugins/maps/common/i18n_getters'; diff --git a/x-pack/legacy/plugins/maps/common/parse_xml_string.js b/x-pack/legacy/plugins/maps/common/parse_xml_string.js deleted file mode 100644 index 34ec1444728281..00000000000000 --- a/x-pack/legacy/plugins/maps/common/parse_xml_string.js +++ /dev/null @@ -1,8 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -export * from '../../../../plugins/maps/common/parse_xml_string'; diff --git a/x-pack/legacy/plugins/maps/index.js b/x-pack/legacy/plugins/maps/index.js index 1a7f478d3bbad4..8546e3712c7630 100644 --- a/x-pack/legacy/plugins/maps/index.js +++ b/x-pack/legacy/plugins/maps/index.js @@ -9,9 +9,14 @@ import mappings from './mappings.json'; import { i18n } from '@kbn/i18n'; import { resolve } from 'path'; import { migrations } from './migrations'; -import { getAppTitle } from './common/i18n_getters'; +import { getAppTitle } from '../../../plugins/maps/common/i18n_getters'; import { MapPlugin } from './server/plugin'; -import { APP_ID, APP_ICON, createMapPath, MAP_SAVED_OBJECT_TYPE } from './common/constants'; +import { + APP_ID, + APP_ICON, + createMapPath, + MAP_SAVED_OBJECT_TYPE, +} from '../../../plugins/maps/common/constants'; import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/utils'; export function maps(kibana) { @@ -38,6 +43,7 @@ export function maps(kibana) { return { showMapVisualizationTypes: serverConfig.get('xpack.maps.showMapVisualizationTypes'), showMapsInspectorAdapter: serverConfig.get('xpack.maps.showMapsInspectorAdapter'), + enableVectorTiles: serverConfig.get('xpack.maps.enableVectorTiles'), preserveDrawingBuffer: serverConfig.get('xpack.maps.preserveDrawingBuffer'), isEmsEnabled: mapConfig.includeElasticMapsService, emsFontLibraryUrl: mapConfig.emsFontLibraryUrl, @@ -52,7 +58,6 @@ export function maps(kibana) { }; }, embeddableFactories: ['plugins/maps/embeddable/map_embeddable_factory'], - home: ['plugins/maps/legacy_register_feature'], styleSheetPaths: `${__dirname}/public/index.scss`, savedObjectSchemas: { 'maps-telemetry': { @@ -77,7 +82,6 @@ export function maps(kibana) { }, mappings, migrations, - hacks: ['plugins/maps/register_vis_type_alias'], }, config(Joi) { return Joi.object({ @@ -85,6 +89,7 @@ export function maps(kibana) { showMapVisualizationTypes: Joi.boolean().default(false), showMapsInspectorAdapter: Joi.boolean().default(false), // flag used in functional testing preserveDrawingBuffer: Joi.boolean().default(false), // flag used in functional testing + enableVectorTiles: Joi.boolean().default(false), // flag used to enable/disable vector-tiles }).default(); }, diff --git a/x-pack/legacy/plugins/maps/migrations.js b/x-pack/legacy/plugins/maps/migrations.js index a8e69eef7a02fd..d3666025082b78 100644 --- a/x-pack/legacy/plugins/maps/migrations.js +++ b/x-pack/legacy/plugins/maps/migrations.js @@ -4,14 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { extractReferences } from './common/migrations/references'; -import { emsRasterTileToEmsVectorTile } from './common/migrations/ems_raster_tile_to_ems_vector_tile'; -import { topHitsTimeToSort } from './common/migrations/top_hits_time_to_sort'; -import { moveApplyGlobalQueryToSources } from './common/migrations/move_apply_global_query'; -import { addFieldMetaOptions } from './common/migrations/add_field_meta_options'; -import { migrateSymbolStyleDescriptor } from './common/migrations/migrate_symbol_style_descriptor'; -import { migrateUseTopHitsToScalingType } from './common/migrations/scaling_type'; -import { migrateJoinAggKey } from './common/migrations/join_agg_key'; +import { extractReferences } from '../../../plugins/maps/common/migrations/references'; +import { emsRasterTileToEmsVectorTile } from '../../../plugins/maps/common/migrations/ems_raster_tile_to_ems_vector_tile'; +import { topHitsTimeToSort } from '../../../plugins/maps/common/migrations/top_hits_time_to_sort'; +import { moveApplyGlobalQueryToSources } from '../../../plugins/maps/common/migrations/move_apply_global_query'; +import { addFieldMetaOptions } from '../../../plugins/maps/common/migrations/add_field_meta_options'; +import { migrateSymbolStyleDescriptor } from '../../../plugins/maps/common/migrations/migrate_symbol_style_descriptor'; +import { migrateUseTopHitsToScalingType } from '../../../plugins/maps/common/migrations/scaling_type'; +import { migrateJoinAggKey } from '../../../plugins/maps/common/migrations/join_agg_key'; export const migrations = { map: { diff --git a/x-pack/legacy/plugins/maps/public/actions/map_actions.d.ts b/x-pack/legacy/plugins/maps/public/actions/map_actions.d.ts deleted file mode 100644 index 34f8c30b51874b..00000000000000 --- a/x-pack/legacy/plugins/maps/public/actions/map_actions.d.ts +++ /dev/null @@ -1,8 +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; - * you may not use this file except in compliance with the Elastic License. - */ -/* eslint-disable @typescript-eslint/consistent-type-definitions */ - -export * from '../../../../../plugins/maps/public/actions/map_actions'; diff --git a/x-pack/legacy/plugins/maps/public/actions/map_actions.js b/x-pack/legacy/plugins/maps/public/actions/map_actions.js deleted file mode 100644 index 7bfbf5761c5b8c..00000000000000 --- a/x-pack/legacy/plugins/maps/public/actions/map_actions.js +++ /dev/null @@ -1,978 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import _ from 'lodash'; -import turf from 'turf'; -import turfBooleanContains from '@turf/boolean-contains'; -import uuid from 'uuid/v4'; -import { - getLayerList, - getLayerListRaw, - getDataFilters, - getSelectedLayerId, - getMapReady, - getWaitingForMapReadyLayerListRaw, - getTransientLayerId, - getOpenTooltips, - getQuery, - getDataRequestDescriptor, -} from '../selectors/map_selectors'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { FLYOUT_STATE } from '../../../../../plugins/maps/public/reducers/ui'; -import { - cancelRequest, - registerCancelCallback, - unregisterCancelCallback, - getEventHandlers, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../../plugins/maps/public/reducers/non_serializable_instances'; -import { updateFlyout } from '../actions/ui_actions'; -import { - FEATURE_ID_PROPERTY_NAME, - LAYER_TYPE, - SOURCE_DATA_ID_ORIGIN, -} from '../../common/constants'; - -import { - SET_SELECTED_LAYER, - SET_TRANSIENT_LAYER, - UPDATE_LAYER_ORDER, - ADD_LAYER, - SET_LAYER_ERROR_STATUS, - ADD_WAITING_FOR_MAP_READY_LAYER, - CLEAR_WAITING_FOR_MAP_READY_LAYER_LIST, - REMOVE_LAYER, - SET_LAYER_VISIBILITY, - MAP_EXTENT_CHANGED, - MAP_READY, - MAP_DESTROYED, - LAYER_DATA_LOAD_STARTED, - LAYER_DATA_LOAD_ENDED, - LAYER_DATA_LOAD_ERROR, - UPDATE_SOURCE_DATA_REQUEST, - SET_JOINS, - SET_QUERY, - TRIGGER_REFRESH_TIMER, - UPDATE_LAYER_PROP, - UPDATE_LAYER_STYLE, - SET_LAYER_STYLE_META, - UPDATE_SOURCE_PROP, - SET_REFRESH_CONFIG, - SET_MOUSE_COORDINATES, - CLEAR_MOUSE_COORDINATES, - SET_GOTO, - CLEAR_GOTO, - TRACK_CURRENT_LAYER_STATE, - ROLLBACK_TO_TRACKED_LAYER_STATE, - REMOVE_TRACKED_LAYER_STATE, - SET_OPEN_TOOLTIPS, - UPDATE_DRAW_STATE, - SET_SCROLL_ZOOM, - SET_MAP_INIT_ERROR, - SET_INTERACTIVE, - DISABLE_TOOLTIP_CONTROL, - HIDE_TOOLBAR_OVERLAY, - HIDE_LAYER_CONTROL, - HIDE_VIEW_CONTROL, - SET_WAITING_FOR_READY_HIDDEN_LAYERS, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../../plugins/maps/public/actions/map_actions'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -export * from '../../../../../plugins/maps/public/actions/map_actions'; - -function getLayerLoadingCallbacks(dispatch, getState, layerId) { - return { - startLoading: (dataId, requestToken, meta) => - dispatch(startDataLoad(layerId, dataId, requestToken, meta)), - stopLoading: (dataId, requestToken, data, meta) => - dispatch(endDataLoad(layerId, dataId, requestToken, data, meta)), - onLoadError: (dataId, requestToken, errorMessage) => - dispatch(onDataLoadError(layerId, dataId, requestToken, errorMessage)), - updateSourceData: newData => { - dispatch(updateSourceDataRequest(layerId, newData)); - }, - isRequestStillActive: (dataId, requestToken) => { - const dataRequest = getDataRequestDescriptor(getState(), layerId, dataId); - if (!dataRequest) { - return false; - } - return dataRequest.dataRequestToken === requestToken; - }, - registerCancelCallback: (requestToken, callback) => - dispatch(registerCancelCallback(requestToken, callback)), - }; -} - -function getLayerById(layerId, state) { - return getLayerList(state).find(layer => { - return layerId === layer.getId(); - }); -} - -async function syncDataForAllLayers(dispatch, getState, dataFilters) { - const state = getState(); - const layerList = getLayerList(state); - const syncs = layerList.map(layer => { - const loadingFunctions = getLayerLoadingCallbacks(dispatch, getState, layer.getId()); - return layer.syncData({ ...loadingFunctions, dataFilters }); - }); - await Promise.all(syncs); -} - -export function cancelAllInFlightRequests() { - return (dispatch, getState) => { - getLayerList(getState()).forEach(layer => { - dispatch(clearDataRequests(layer)); - }); - }; -} - -function clearDataRequests(layer) { - return dispatch => { - layer.getInFlightRequestTokens().forEach(requestToken => { - dispatch(cancelRequest(requestToken)); - }); - dispatch({ - type: UPDATE_LAYER_PROP, - id: layer.getId(), - propName: '__dataRequests', - newValue: [], - }); - }; -} - -export function setMapInitError(errorMessage) { - return { - type: SET_MAP_INIT_ERROR, - errorMessage, - }; -} - -export function trackCurrentLayerState(layerId) { - return { - type: TRACK_CURRENT_LAYER_STATE, - layerId: layerId, - }; -} - -export function rollbackToTrackedLayerStateForSelectedLayer() { - return async (dispatch, getState) => { - const layerId = getSelectedLayerId(getState()); - await dispatch({ - type: ROLLBACK_TO_TRACKED_LAYER_STATE, - layerId: layerId, - }); - - // Ensure updateStyleMeta is triggered - // syncDataForLayer may not trigger endDataLoad if no re-fetch is required - dispatch(updateStyleMeta(layerId)); - - dispatch(syncDataForLayer(layerId)); - }; -} - -export function removeTrackedLayerStateForSelectedLayer() { - return (dispatch, getState) => { - const layerId = getSelectedLayerId(getState()); - dispatch({ - type: REMOVE_TRACKED_LAYER_STATE, - layerId: layerId, - }); - }; -} - -export function replaceLayerList(newLayerList) { - return (dispatch, getState) => { - const isMapReady = getMapReady(getState()); - if (!isMapReady) { - dispatch({ - type: CLEAR_WAITING_FOR_MAP_READY_LAYER_LIST, - }); - } else { - getLayerListRaw(getState()).forEach(({ id }) => { - dispatch(removeLayerFromLayerList(id)); - }); - } - - newLayerList.forEach(layerDescriptor => { - dispatch(addLayer(layerDescriptor)); - }); - }; -} - -export function cloneLayer(layerId) { - return async (dispatch, getState) => { - const layer = getLayerById(layerId, getState()); - if (!layer) { - return; - } - - const clonedDescriptor = await layer.cloneDescriptor(); - dispatch(addLayer(clonedDescriptor)); - }; -} - -export function addLayer(layerDescriptor) { - return (dispatch, getState) => { - const isMapReady = getMapReady(getState()); - if (!isMapReady) { - dispatch({ - type: ADD_WAITING_FOR_MAP_READY_LAYER, - layer: layerDescriptor, - }); - return; - } - - dispatch({ - type: ADD_LAYER, - layer: layerDescriptor, - }); - dispatch(syncDataForLayer(layerDescriptor.id)); - }; -} - -// Do not use when rendering a map. Method exists to enable selectors for getLayerList when -// rendering is not needed. -export function addLayerWithoutDataSync(layerDescriptor) { - return { - type: ADD_LAYER, - layer: layerDescriptor, - }; -} - -function setLayerDataLoadErrorStatus(layerId, errorMessage) { - return dispatch => { - dispatch({ - type: SET_LAYER_ERROR_STATUS, - isInErrorState: errorMessage !== null, - layerId, - errorMessage, - }); - }; -} - -export function cleanTooltipStateForLayer(layerId, layerFeatures = []) { - return (dispatch, getState) => { - let featuresRemoved = false; - const openTooltips = getOpenTooltips(getState()) - .map(tooltipState => { - const nextFeatures = tooltipState.features.filter(tooltipFeature => { - if (tooltipFeature.layerId !== layerId) { - // feature from another layer, keep it - return true; - } - - // Keep feature if it is still in layer - return layerFeatures.some(layerFeature => { - return layerFeature.properties[FEATURE_ID_PROPERTY_NAME] === tooltipFeature.id; - }); - }); - - if (tooltipState.features.length !== nextFeatures.length) { - featuresRemoved = true; - } - - return { ...tooltipState, features: nextFeatures }; - }) - .filter(tooltipState => { - return tooltipState.features.length > 0; - }); - - if (featuresRemoved) { - dispatch({ - type: SET_OPEN_TOOLTIPS, - openTooltips, - }); - } - }; -} - -export function setLayerVisibility(layerId, makeVisible) { - return async (dispatch, getState) => { - //if the current-state is invisible, we also want to sync data - //e.g. if a layer was invisible at start-up, it won't have any data loaded - const layer = getLayerById(layerId, getState()); - - // If the layer visibility is already what we want it to be, do nothing - if (!layer || layer.isVisible() === makeVisible) { - return; - } - - if (!makeVisible) { - dispatch(cleanTooltipStateForLayer(layerId)); - } - - await dispatch({ - type: SET_LAYER_VISIBILITY, - layerId, - visibility: makeVisible, - }); - if (makeVisible) { - dispatch(syncDataForLayer(layerId)); - } - }; -} - -export function toggleLayerVisible(layerId) { - return async (dispatch, getState) => { - const layer = getLayerById(layerId, getState()); - if (!layer) { - return; - } - const makeVisible = !layer.isVisible(); - - dispatch(setLayerVisibility(layerId, makeVisible)); - }; -} - -export function setSelectedLayer(layerId) { - return async (dispatch, getState) => { - const oldSelectedLayer = getSelectedLayerId(getState()); - if (oldSelectedLayer) { - await dispatch(rollbackToTrackedLayerStateForSelectedLayer()); - } - if (layerId) { - dispatch(trackCurrentLayerState(layerId)); - } - dispatch({ - type: SET_SELECTED_LAYER, - selectedLayerId: layerId, - }); - }; -} - -export function removeTransientLayer() { - return async (dispatch, getState) => { - const transientLayerId = getTransientLayerId(getState()); - if (transientLayerId) { - await dispatch(removeLayerFromLayerList(transientLayerId)); - await dispatch(setTransientLayer(null)); - } - }; -} - -export function setTransientLayer(layerId) { - return { - type: SET_TRANSIENT_LAYER, - transientLayerId: layerId, - }; -} - -export function clearTransientLayerStateAndCloseFlyout() { - return async dispatch => { - await dispatch(updateFlyout(FLYOUT_STATE.NONE)); - await dispatch(setSelectedLayer(null)); - await dispatch(removeTransientLayer()); - }; -} - -export function updateLayerOrder(newLayerOrder) { - return { - type: UPDATE_LAYER_ORDER, - newLayerOrder, - }; -} - -export function mapReady() { - return (dispatch, getState) => { - dispatch({ - type: MAP_READY, - }); - - getWaitingForMapReadyLayerListRaw(getState()).forEach(layerDescriptor => { - dispatch(addLayer(layerDescriptor)); - }); - - dispatch({ - type: CLEAR_WAITING_FOR_MAP_READY_LAYER_LIST, - }); - }; -} - -export function mapDestroyed() { - return { - type: MAP_DESTROYED, - }; -} - -export function mapExtentChanged(newMapConstants) { - return async (dispatch, getState) => { - const state = getState(); - const dataFilters = getDataFilters(state); - const { extent, zoom: newZoom } = newMapConstants; - const { buffer, zoom: currentZoom } = dataFilters; - - if (extent) { - let doesBufferContainExtent = false; - if (buffer) { - const bufferGeometry = turf.bboxPolygon([ - buffer.minLon, - buffer.minLat, - buffer.maxLon, - buffer.maxLat, - ]); - const extentGeometry = turf.bboxPolygon([ - extent.minLon, - extent.minLat, - extent.maxLon, - extent.maxLat, - ]); - - doesBufferContainExtent = turfBooleanContains(bufferGeometry, extentGeometry); - } - - if (!doesBufferContainExtent || currentZoom !== newZoom) { - const scaleFactor = 0.5; // TODO put scale factor in store and fetch with selector - const width = extent.maxLon - extent.minLon; - const height = extent.maxLat - extent.minLat; - dataFilters.buffer = { - minLon: extent.minLon - width * scaleFactor, - minLat: extent.minLat - height * scaleFactor, - maxLon: extent.maxLon + width * scaleFactor, - maxLat: extent.maxLat + height * scaleFactor, - }; - } - } - - dispatch({ - type: MAP_EXTENT_CHANGED, - mapState: { - ...dataFilters, - ...newMapConstants, - }, - }); - const newDataFilters = { ...dataFilters, ...newMapConstants }; - await syncDataForAllLayers(dispatch, getState, newDataFilters); - }; -} - -export function closeOnClickTooltip(tooltipId) { - return (dispatch, getState) => { - dispatch({ - type: SET_OPEN_TOOLTIPS, - openTooltips: getOpenTooltips(getState()).filter(({ id }) => { - return tooltipId !== id; - }), - }); - }; -} - -export function openOnClickTooltip(tooltipState) { - return (dispatch, getState) => { - const openTooltips = getOpenTooltips(getState()).filter(({ features, location, isLocked }) => { - return ( - isLocked && - !_.isEqual(location, tooltipState.location) && - !_.isEqual(features, tooltipState.features) - ); - }); - - openTooltips.push({ - ...tooltipState, - isLocked: true, - id: uuid(), - }); - - dispatch({ - type: SET_OPEN_TOOLTIPS, - openTooltips, - }); - }; -} - -export function closeOnHoverTooltip() { - return (dispatch, getState) => { - if (getOpenTooltips(getState()).length) { - dispatch({ - type: SET_OPEN_TOOLTIPS, - openTooltips: [], - }); - } - }; -} - -export function openOnHoverTooltip(tooltipState) { - return { - type: SET_OPEN_TOOLTIPS, - openTooltips: [ - { - ...tooltipState, - isLocked: false, - id: uuid(), - }, - ], - }; -} - -export function setMouseCoordinates({ lat, lon }) { - let safeLon = lon; - if (lon > 180) { - const overlapWestOfDateLine = lon - 180; - safeLon = -180 + overlapWestOfDateLine; - } else if (lon < -180) { - const overlapEastOfDateLine = Math.abs(lon) - 180; - safeLon = 180 - overlapEastOfDateLine; - } - - return { - type: SET_MOUSE_COORDINATES, - lat, - lon: safeLon, - }; -} - -export function clearMouseCoordinates() { - return { type: CLEAR_MOUSE_COORDINATES }; -} - -export function disableScrollZoom() { - return { type: SET_SCROLL_ZOOM, scrollZoom: false }; -} - -export function fitToLayerExtent(layerId) { - return async function(dispatch, getState) { - const targetLayer = getLayerById(layerId, getState()); - - if (targetLayer) { - const dataFilters = getDataFilters(getState()); - const bounds = await targetLayer.getBounds(dataFilters); - if (bounds) { - await dispatch(setGotoWithBounds(bounds)); - } - } - }; -} - -export function setGotoWithBounds(bounds) { - return { - type: SET_GOTO, - bounds: bounds, - }; -} - -export function setGotoWithCenter({ lat, lon, zoom }) { - return { - type: SET_GOTO, - center: { lat, lon, zoom }, - }; -} - -export function clearGoto() { - return { type: CLEAR_GOTO }; -} - -export function startDataLoad(layerId, dataId, requestToken, meta = {}) { - return (dispatch, getState) => { - const layer = getLayerById(layerId, getState()); - if (layer) { - dispatch(cancelRequest(layer.getPrevRequestToken(dataId))); - } - - const eventHandlers = getEventHandlers(getState()); - if (eventHandlers && eventHandlers.onDataLoad) { - eventHandlers.onDataLoad({ - layerId, - dataId, - }); - } - - dispatch({ - meta, - type: LAYER_DATA_LOAD_STARTED, - layerId, - dataId, - requestToken, - }); - }; -} - -export function updateSourceDataRequest(layerId, newData) { - return dispatch => { - dispatch({ - type: UPDATE_SOURCE_DATA_REQUEST, - dataId: SOURCE_DATA_ID_ORIGIN, - layerId, - newData, - }); - - dispatch(updateStyleMeta(layerId)); - }; -} - -export function endDataLoad(layerId, dataId, requestToken, data, meta) { - return async (dispatch, getState) => { - dispatch(unregisterCancelCallback(requestToken)); - - const features = data && data.features ? data.features : []; - - const eventHandlers = getEventHandlers(getState()); - if (eventHandlers && eventHandlers.onDataLoadEnd) { - const layer = getLayerById(layerId, getState()); - const resultMeta = {}; - if (layer && layer.getType() === LAYER_TYPE.VECTOR) { - resultMeta.featuresCount = features.length; - } - - eventHandlers.onDataLoadEnd({ - layerId, - dataId, - resultMeta, - }); - } - - dispatch(cleanTooltipStateForLayer(layerId, features)); - dispatch({ - type: LAYER_DATA_LOAD_ENDED, - layerId, - dataId, - data, - meta, - requestToken, - }); - - //Clear any data-load errors when there is a succesful data return. - //Co this on end-data-load iso at start-data-load to avoid blipping the error status between true/false. - //This avoids jitter in the warning icon of the TOC when the requests continues to return errors. - dispatch(setLayerDataLoadErrorStatus(layerId, null)); - - dispatch(updateStyleMeta(layerId)); - }; -} - -export function onDataLoadError(layerId, dataId, requestToken, errorMessage) { - return async (dispatch, getState) => { - dispatch(unregisterCancelCallback(requestToken)); - - const eventHandlers = getEventHandlers(getState()); - if (eventHandlers && eventHandlers.onDataLoadError) { - eventHandlers.onDataLoadError({ - layerId, - dataId, - errorMessage, - }); - } - - dispatch(cleanTooltipStateForLayer(layerId)); - dispatch({ - type: LAYER_DATA_LOAD_ERROR, - data: null, - layerId, - dataId, - requestToken, - }); - - dispatch(setLayerDataLoadErrorStatus(layerId, errorMessage)); - }; -} - -export function updateSourceProp(layerId, propName, value, newLayerType) { - return async dispatch => { - dispatch({ - type: UPDATE_SOURCE_PROP, - layerId, - propName, - value, - }); - if (newLayerType) { - dispatch(updateLayerType(layerId, newLayerType)); - } - await dispatch(clearMissingStyleProperties(layerId)); - dispatch(syncDataForLayer(layerId)); - }; -} - -function updateLayerType(layerId, newLayerType) { - return (dispatch, getState) => { - const layer = getLayerById(layerId, getState()); - if (!layer || layer.getType() === newLayerType) { - return; - } - dispatch(clearDataRequests(layer)); - dispatch({ - type: UPDATE_LAYER_PROP, - id: layerId, - propName: 'type', - newValue: newLayerType, - }); - }; -} - -export function syncDataForLayer(layerId) { - return async (dispatch, getState) => { - const targetLayer = getLayerById(layerId, getState()); - if (targetLayer) { - const dataFilters = getDataFilters(getState()); - const loadingFunctions = getLayerLoadingCallbacks(dispatch, getState, layerId); - await targetLayer.syncData({ - ...loadingFunctions, - dataFilters, - }); - } - }; -} - -export function updateLayerLabel(id, newLabel) { - return { - type: UPDATE_LAYER_PROP, - id, - propName: 'label', - newValue: newLabel, - }; -} - -export function updateLayerMinZoom(id, minZoom) { - return { - type: UPDATE_LAYER_PROP, - id, - propName: 'minZoom', - newValue: minZoom, - }; -} - -export function updateLayerMaxZoom(id, maxZoom) { - return { - type: UPDATE_LAYER_PROP, - id, - propName: 'maxZoom', - newValue: maxZoom, - }; -} - -export function updateLayerAlpha(id, alpha) { - return { - type: UPDATE_LAYER_PROP, - id, - propName: 'alpha', - newValue: alpha, - }; -} - -export function setLayerQuery(id, query) { - return dispatch => { - dispatch({ - type: UPDATE_LAYER_PROP, - id, - propName: 'query', - newValue: query, - }); - - dispatch(syncDataForLayer(id)); - }; -} - -export function removeSelectedLayer() { - return (dispatch, getState) => { - const state = getState(); - const layerId = getSelectedLayerId(state); - dispatch(removeLayer(layerId)); - }; -} - -export function removeLayer(layerId) { - return async (dispatch, getState) => { - const state = getState(); - const selectedLayerId = getSelectedLayerId(state); - if (layerId === selectedLayerId) { - dispatch(updateFlyout(FLYOUT_STATE.NONE)); - await dispatch(setSelectedLayer(null)); - } - dispatch(removeLayerFromLayerList(layerId)); - }; -} - -function removeLayerFromLayerList(layerId) { - return (dispatch, getState) => { - const layerGettingRemoved = getLayerById(layerId, getState()); - if (!layerGettingRemoved) { - return; - } - - layerGettingRemoved.getInFlightRequestTokens().forEach(requestToken => { - dispatch(cancelRequest(requestToken)); - }); - dispatch(cleanTooltipStateForLayer(layerId)); - layerGettingRemoved.destroy(); - dispatch({ - type: REMOVE_LAYER, - id: layerId, - }); - }; -} - -export function setQuery({ query, timeFilters, filters = [], refresh = false }) { - function generateQueryTimestamp() { - return new Date().toISOString(); - } - return async (dispatch, getState) => { - const prevQuery = getQuery(getState()); - const prevTriggeredAt = - prevQuery && prevQuery.queryLastTriggeredAt - ? prevQuery.queryLastTriggeredAt - : generateQueryTimestamp(); - - dispatch({ - type: SET_QUERY, - timeFilters, - query: { - ...query, - // ensure query changes to trigger re-fetch when "Refresh" clicked - queryLastTriggeredAt: refresh ? generateQueryTimestamp() : prevTriggeredAt, - }, - filters, - }); - - const dataFilters = getDataFilters(getState()); - await syncDataForAllLayers(dispatch, getState, dataFilters); - }; -} - -export function setRefreshConfig({ isPaused, interval }) { - return { - type: SET_REFRESH_CONFIG, - isPaused, - interval, - }; -} - -export function triggerRefreshTimer() { - return async (dispatch, getState) => { - dispatch({ - type: TRIGGER_REFRESH_TIMER, - }); - - const dataFilters = getDataFilters(getState()); - await syncDataForAllLayers(dispatch, getState, dataFilters); - }; -} - -export function clearMissingStyleProperties(layerId) { - return async (dispatch, getState) => { - const targetLayer = getLayerById(layerId, getState()); - if (!targetLayer) { - return; - } - - const style = targetLayer.getCurrentStyle(); - if (!style) { - return; - } - - const nextFields = await targetLayer.getFields(); //take into account all fields, since labels can be driven by any field (source or join) - const { hasChanges, nextStyleDescriptor } = style.getDescriptorWithMissingStylePropsRemoved( - nextFields - ); - if (hasChanges) { - dispatch(updateLayerStyle(layerId, nextStyleDescriptor)); - } - }; -} - -export function updateLayerStyle(layerId, styleDescriptor) { - return dispatch => { - dispatch({ - type: UPDATE_LAYER_STYLE, - layerId, - style: { - ...styleDescriptor, - }, - }); - - // Ensure updateStyleMeta is triggered - // syncDataForLayer may not trigger endDataLoad if no re-fetch is required - dispatch(updateStyleMeta(layerId)); - - // Style update may require re-fetch, for example ES search may need to retrieve field used for dynamic styling - dispatch(syncDataForLayer(layerId)); - }; -} - -export function updateStyleMeta(layerId) { - return async (dispatch, getState) => { - const layer = getLayerById(layerId, getState()); - if (!layer) { - return; - } - const sourceDataRequest = layer.getSourceDataRequest(); - const style = layer.getCurrentStyle(); - if (!style || !sourceDataRequest) { - return; - } - const styleMeta = await style.pluckStyleMetaFromSourceDataRequest(sourceDataRequest); - dispatch({ - type: SET_LAYER_STYLE_META, - layerId, - styleMeta, - }); - }; -} - -export function updateLayerStyleForSelectedLayer(styleDescriptor) { - return (dispatch, getState) => { - const selectedLayerId = getSelectedLayerId(getState()); - if (!selectedLayerId) { - return; - } - dispatch(updateLayerStyle(selectedLayerId, styleDescriptor)); - }; -} - -export function setJoinsForLayer(layer, joins) { - return async dispatch => { - await dispatch({ - type: SET_JOINS, - layer: layer, - joins: joins, - }); - - await dispatch(clearMissingStyleProperties(layer.getId())); - dispatch(syncDataForLayer(layer.getId())); - }; -} - -export function updateDrawState(drawState) { - return dispatch => { - if (drawState !== null) { - dispatch({ type: SET_OPEN_TOOLTIPS, openTooltips: [] }); // tooltips just get in the way - } - dispatch({ - type: UPDATE_DRAW_STATE, - drawState: drawState, - }); - }; -} - -export function disableInteractive() { - return { type: SET_INTERACTIVE, disableInteractive: true }; -} - -export function disableTooltipControl() { - return { type: DISABLE_TOOLTIP_CONTROL, disableTooltipControl: true }; -} - -export function hideToolbarOverlay() { - return { type: HIDE_TOOLBAR_OVERLAY, hideToolbarOverlay: true }; -} - -export function hideLayerControl() { - return { type: HIDE_LAYER_CONTROL, hideLayerControl: true }; -} -export function hideViewControl() { - return { type: HIDE_VIEW_CONTROL, hideViewControl: true }; -} - -export function setHiddenLayers(hiddenLayerIds) { - return (dispatch, getState) => { - const isMapReady = getMapReady(getState()); - - if (!isMapReady) { - dispatch({ type: SET_WAITING_FOR_READY_HIDDEN_LAYERS, hiddenLayerIds }); - } else { - getLayerListRaw(getState()).forEach(layer => - dispatch(setLayerVisibility(layer.id, !hiddenLayerIds.includes(layer.id))) - ); - } - }; -} diff --git a/x-pack/legacy/plugins/maps/public/actions/ui_actions.js b/x-pack/legacy/plugins/maps/public/actions/ui_actions.js deleted file mode 100644 index 33ab2fd74122a6..00000000000000 --- a/x-pack/legacy/plugins/maps/public/actions/ui_actions.js +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { - UPDATE_FLYOUT, - CLOSE_SET_VIEW, - OPEN_SET_VIEW, - SET_IS_LAYER_TOC_OPEN, - SET_FULL_SCREEN, - SET_READ_ONLY, - SET_OPEN_TOC_DETAILS, - SHOW_TOC_DETAILS, - HIDE_TOC_DETAILS, - UPDATE_INDEXING_STAGE, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../../plugins/maps/public/actions/ui_actions'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -export * from '../../../../../plugins/maps/public/actions/ui_actions'; - -export function exitFullScreen() { - return { - type: SET_FULL_SCREEN, - isFullScreen: false, - }; -} - -export function updateFlyout(display) { - return { - type: UPDATE_FLYOUT, - display, - }; -} -export function closeSetView() { - return { - type: CLOSE_SET_VIEW, - }; -} -export function openSetView() { - return { - type: OPEN_SET_VIEW, - }; -} -export function setIsLayerTOCOpen(isLayerTOCOpen) { - return { - type: SET_IS_LAYER_TOC_OPEN, - isLayerTOCOpen, - }; -} -export function enableFullScreen() { - return { - type: SET_FULL_SCREEN, - isFullScreen: true, - }; -} -export function setReadOnly(isReadOnly) { - return { - type: SET_READ_ONLY, - isReadOnly, - }; -} - -export function setOpenTOCDetails(layerIds) { - return { - type: SET_OPEN_TOC_DETAILS, - layerIds, - }; -} - -export function showTOCDetails(layerId) { - return { - type: SHOW_TOC_DETAILS, - layerId, - }; -} - -export function hideTOCDetails(layerId) { - return { - type: HIDE_TOC_DETAILS, - layerId, - }; -} - -export function updateIndexingStage(stage) { - return { - type: UPDATE_INDEXING_STAGE, - stage, - }; -} diff --git a/x-pack/legacy/plugins/maps/public/angular/get_initial_layers.js b/x-pack/legacy/plugins/maps/public/angular/get_initial_layers.js deleted file mode 100644 index 686259aeaaba44..00000000000000 --- a/x-pack/legacy/plugins/maps/public/angular/get_initial_layers.js +++ /dev/null @@ -1,54 +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; - * you may not use this file except in compliance with the Elastic License. - */ -import _ from 'lodash'; -// Import each layer type, even those not used, to init in registry -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import '../../../../../plugins/maps/public/layers/sources/wms_source'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import '../../../../../plugins/maps/public/layers/sources/ems_file_source'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import '../../../../../plugins/maps/public/layers/sources/es_search_source'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import '../../../../../plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import '../../../../../plugins/maps/public/layers/sources/kibana_regionmap_source'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import '../../../../../plugins/maps/public/layers/sources/es_geo_grid_source'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import '../../../../../plugins/maps/public/layers/sources/xyz_tms_source'; - -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { KibanaTilemapSource } from '../../../../../plugins/maps/public/layers/sources/kibana_tilemap_source'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { EMSTMSSource } from '../../../../../plugins/maps/public/layers/sources/ems_tms_source'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getInjectedVarFunc } from '../../../../../plugins/maps/public/kibana_services'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getKibanaTileMap } from '../../../../../plugins/maps/public/meta'; - -export function getInitialLayers(layerListJSON, initialLayers = []) { - if (layerListJSON) { - return JSON.parse(layerListJSON); - } - - const tilemapSourceFromKibana = getKibanaTileMap(); - if (_.get(tilemapSourceFromKibana, 'url')) { - const sourceDescriptor = KibanaTilemapSource.createDescriptor(); - const source = new KibanaTilemapSource(sourceDescriptor); - const layer = source.createDefaultLayer(); - return [layer.toLayerDescriptor(), ...initialLayers]; - } - - const isEmsEnabled = getInjectedVarFunc()('isEmsEnabled', true); - if (isEmsEnabled) { - const descriptor = EMSTMSSource.createDescriptor({ isAutoSelect: true }); - const source = new EMSTMSSource(descriptor); - const layer = source.createDefaultLayer(); - return [layer.toLayerDescriptor(), ...initialLayers]; - } - - return initialLayers; -} diff --git a/x-pack/legacy/plugins/maps/public/angular/map_controller.js b/x-pack/legacy/plugins/maps/public/angular/map_controller.js index 6bc8a4d0be5aca..9522fd12ad37d1 100644 --- a/x-pack/legacy/plugins/maps/public/angular/map_controller.js +++ b/x-pack/legacy/plugins/maps/public/angular/map_controller.js @@ -28,8 +28,10 @@ import { // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { createMapStore } from '../../../../../plugins/maps/public/reducers/store'; import { Provider } from 'react-redux'; -import { GisMap } from '../connected_components/gis_map'; -import { addHelpMenuToAppChrome } from '../help_menu_util'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { GisMap } from '../../../../../plugins/maps/public/connected_components/gis_map'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { addHelpMenuToAppChrome } from '../../../../../plugins/maps/public/help_menu_util'; import { setSelectedLayer, setRefreshConfig, @@ -37,7 +39,8 @@ import { replaceLayerList, setQuery, clearTransientLayerStateAndCloseFlyout, -} from '../actions/map_actions'; + // eslint-disable-next-line @kbn/eslint/no-restricted-paths +} from '../../../../../plugins/maps/public/actions/map_actions'; import { DEFAULT_IS_LAYER_TOC_OPEN, FLYOUT_STATE, @@ -49,22 +52,29 @@ import { setReadOnly, setIsLayerTOCOpen, setOpenTOCDetails, -} from '../actions/ui_actions'; -import { getIsFullScreen } from '../selectors/ui_selectors'; + // eslint-disable-next-line @kbn/eslint/no-restricted-paths +} from '../../../../../plugins/maps/public/actions/ui_actions'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { getIsFullScreen } from '../../../../../plugins/maps/public/selectors/ui_selectors'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { copyPersistentState } from '../../../../../plugins/maps/public/reducers/util'; import { getQueryableUniqueIndexPatternIds, hasDirtyState, getLayerListRaw, -} from '../selectors/map_selectors'; + // eslint-disable-next-line @kbn/eslint/no-restricted-paths +} from '../../../../../plugins/maps/public/selectors/map_selectors'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { getInspectorAdapters } from '../../../../../plugins/maps/public/reducers/non_serializable_instances'; -import { getInitialLayers } from './get_initial_layers'; -import { getInitialQuery } from './get_initial_query'; -import { getInitialTimeFilters } from './get_initial_time_filters'; -import { getInitialRefreshConfig } from './get_initial_refresh_config'; -import { MAP_SAVED_OBJECT_TYPE, MAP_APP_PATH } from '../../common/constants'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { getInitialLayers } from '../../../../../plugins/maps/public/angular/get_initial_layers'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { getInitialQuery } from '../../../../../plugins/maps/public/angular/get_initial_query'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { getInitialTimeFilters } from '../../../../../plugins/maps/public/angular/get_initial_time_filters'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { getInitialRefreshConfig } from '../../../../../plugins/maps/public/angular/get_initial_refresh_config'; +import { MAP_SAVED_OBJECT_TYPE, MAP_APP_PATH } from '../../../../../plugins/maps/common/constants'; import { npSetup, npStart } from 'ui/new_platform'; import { esFilters } from '../../../../../../src/plugins/data/public'; import { diff --git a/x-pack/legacy/plugins/maps/public/components/_index.scss b/x-pack/legacy/plugins/maps/public/components/_index.scss deleted file mode 100644 index 0b327194424244..00000000000000 --- a/x-pack/legacy/plugins/maps/public/components/_index.scss +++ /dev/null @@ -1,3 +0,0 @@ -@import './metric_editors'; -@import './geometry_filter'; -@import './tooltip_selector'; diff --git a/x-pack/legacy/plugins/maps/public/connected_components/_index.scss b/x-pack/legacy/plugins/maps/public/connected_components/_index.scss deleted file mode 100644 index 99a2e222ea6c14..00000000000000 --- a/x-pack/legacy/plugins/maps/public/connected_components/_index.scss +++ /dev/null @@ -1,6 +0,0 @@ -@import './gis_map/gis_map'; -@import './layer_addpanel/source_select/index'; -@import './layer_panel/index'; -@import './widget_overlay/index'; -@import './toolbar_overlay/index'; -@import './map/features_tooltip/index'; diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/source_select/_index.scss b/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/source_select/_index.scss deleted file mode 100644 index 7fe1396fcca16e..00000000000000 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/source_select/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import './source_select'; diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/_index.scss b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/_index.scss deleted file mode 100644 index fd074edf032fa0..00000000000000 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/_index.scss +++ /dev/null @@ -1,4 +0,0 @@ -@import './layer_panel'; -@import './filter_editor/filter_editor'; -@import './join_editor/resources/join'; -@import './style_settings/style_settings'; \ No newline at end of file diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.d.ts b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.d.ts deleted file mode 100644 index cf4fdc7be70c68..00000000000000 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.d.ts +++ /dev/null @@ -1,8 +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; - * you may not use this file except in compliance with the Elastic License. - */ -/* eslint-disable @typescript-eslint/consistent-type-definitions */ - -export * from '../../../../../../plugins/maps/public/connected_components/layer_panel/view'; diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/utils.js b/x-pack/legacy/plugins/maps/public/connected_components/map/mb/utils.js deleted file mode 100644 index a1d1341b7c4f7e..00000000000000 --- a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/utils.js +++ /dev/null @@ -1,107 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import _ from 'lodash'; -import { - loadSpriteSheetImageData, - addSpriteSheetToMapFromImageData, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../../../../plugins/maps/public/connected_components/map/mb/utils'; - -export { loadSpriteSheetImageData, addSpriteSheetToMapFromImageData }; - -export function removeOrphanedSourcesAndLayers(mbMap, layerList) { - const mbStyle = mbMap.getStyle(); - - const mbLayerIdsToRemove = []; - mbStyle.layers.forEach(mbLayer => { - const layer = layerList.find(layer => { - return layer.ownsMbLayerId(mbLayer.id); - }); - if (!layer) { - mbLayerIdsToRemove.push(mbLayer.id); - } - }); - mbLayerIdsToRemove.forEach(mbLayerId => mbMap.removeLayer(mbLayerId)); - - const mbSourcesToRemove = []; - for (const mbSourceId in mbStyle.sources) { - if (mbStyle.sources.hasOwnProperty(mbSourceId)) { - const layer = layerList.find(layer => { - return layer.ownsMbSourceId(mbSourceId); - }); - if (!layer) { - mbSourcesToRemove.push(mbSourceId); - } - } - } - mbSourcesToRemove.forEach(mbSourceId => mbMap.removeSource(mbSourceId)); -} - -/** - * This is function assumes only a single layer moved in the layerList, compared to mbMap - * It is optimized to minimize the amount of mbMap.moveLayer calls. - * @param mbMap - * @param layerList - */ -export function syncLayerOrderForSingleLayer(mbMap, layerList) { - if (!layerList || layerList.length === 0) { - return; - } - - const mbLayers = mbMap.getStyle().layers.slice(); - const layerIds = mbLayers.map(mbLayer => { - const layer = layerList.find(layer => layer.ownsMbLayerId(mbLayer.id)); - return layer.getId(); - }); - - const currentLayerOrderLayerIds = _.uniq(layerIds); - - const newLayerOrderLayerIdsUnfiltered = layerList.map(l => l.getId()); - const newLayerOrderLayerIds = newLayerOrderLayerIdsUnfiltered.filter(layerId => - currentLayerOrderLayerIds.includes(layerId) - ); - - let netPos = 0; - let netNeg = 0; - const movementArr = currentLayerOrderLayerIds.reduce((accu, id, idx) => { - const movement = newLayerOrderLayerIds.findIndex(newOId => newOId === id) - idx; - movement > 0 ? netPos++ : movement < 0 && netNeg++; - accu.push({ id, movement }); - return accu; - }, []); - if (netPos === 0 && netNeg === 0) { - return; - } - const movedLayerId = - (netPos >= netNeg && movementArr.find(l => l.movement < 0).id) || - (netPos < netNeg && movementArr.find(l => l.movement > 0).id); - const nextLayerIdx = newLayerOrderLayerIds.findIndex(layerId => layerId === movedLayerId) + 1; - - let nextMbLayerId; - if (nextLayerIdx === newLayerOrderLayerIds.length) { - nextMbLayerId = null; - } else { - const foundLayer = mbLayers.find(({ id: mbLayerId }) => { - const layerId = newLayerOrderLayerIds[nextLayerIdx]; - const layer = layerList.find(layer => layer.getId() === layerId); - return layer.ownsMbLayerId(mbLayerId); - }); - nextMbLayerId = foundLayer.id; - } - - const movedLayer = layerList.find(layer => layer.getId() === movedLayerId); - mbLayers.forEach(({ id: mbLayerId }) => { - if (movedLayer.ownsMbLayerId(mbLayerId)) { - mbMap.moveLayer(mbLayerId, nextMbLayerId); - } - }); -} - -export async function addSpritesheetToMap(json, imgUrl, mbMap) { - const imgData = await loadSpriteSheetImageData(imgUrl); - addSpriteSheetToMapFromImageData(json, imgData, mbMap); -} diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/_index.scss b/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/_index.scss deleted file mode 100644 index cc1ab35039dac2..00000000000000 --- a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/_index.scss +++ /dev/null @@ -1,6 +0,0 @@ -@import './mixins'; - -@import './widget_overlay'; -@import './attribution_control/attribution_control'; -@import './layer_control/index'; -@import './view_control/view_control'; diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/_index.scss b/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/_index.scss deleted file mode 100644 index 761ef9d17b4c2d..00000000000000 --- a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/_index.scss +++ /dev/null @@ -1,2 +0,0 @@ -@import './layer_control'; -@import './layer_toc/toc_entry/toc_entry'; diff --git a/x-pack/legacy/plugins/maps/public/embeddable/map_embeddable_factory.ts b/x-pack/legacy/plugins/maps/public/embeddable/map_embeddable_factory.ts index 96c3baf634a834..90b17412377f52 100644 --- a/x-pack/legacy/plugins/maps/public/embeddable/map_embeddable_factory.ts +++ b/x-pack/legacy/plugins/maps/public/embeddable/map_embeddable_factory.ts @@ -4,153 +4,25 @@ * you may not use this file except in compliance with the Elastic License. */ -import _ from 'lodash'; -import { i18n } from '@kbn/i18n'; +/* + Maintain legacy embeddable legacy present while apps switch over + */ + import { npSetup, npStart } from 'ui/new_platform'; -import { IIndexPattern } from 'src/plugins/data/public'; -// @ts-ignore -import { getMapsSavedObjectLoader } from '../angular/services/gis_map_saved_object_loader'; -import { MapEmbeddable, MapEmbeddableInput } from './map_embeddable'; import { - getIndexPatternService, - getHttp, - getMapsCapabilities, + bindSetupCoreAndPlugins, + bindStartCoreAndPlugins, // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../../plugins/maps/public/kibana_services'; -import { - EmbeddableFactoryDefinition, - IContainer, -} from '../../../../../../src/plugins/embeddable/public'; - -import { createMapPath, MAP_SAVED_OBJECT_TYPE, APP_ICON } from '../../common/constants'; +} from '../../../../../plugins/maps/public/plugin'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { createMapStore } from '../../../../../plugins/maps/public/reducers/store'; -import { addLayerWithoutDataSync } from '../actions/map_actions'; -import { getQueryableUniqueIndexPatternIds } from '../selectors/map_selectors'; -import { getInitialLayers } from '../angular/get_initial_layers'; -import { mergeInputWithSavedMap } from './merge_input_with_saved_map'; -import '../angular/services/gis_map_saved_object_loader'; -// @ts-ignore -import { - bindSetupCoreAndPlugins as bindNpSetupCoreAndPlugins, - bindStartCoreAndPlugins as bindNpStartCoreAndPlugins, -} from '../../../../../plugins/maps/public/plugin'; // eslint-disable-line @kbn/eslint/no-restricted-paths - -export class MapEmbeddableFactory implements EmbeddableFactoryDefinition { - type = MAP_SAVED_OBJECT_TYPE; - savedObjectMetaData = { - name: i18n.translate('xpack.maps.mapSavedObjectLabel', { - defaultMessage: 'Map', - }), - type: MAP_SAVED_OBJECT_TYPE, - getIconForSavedObject: () => APP_ICON, - }; - constructor() { - // Init required services. Necessary while in legacy - bindNpSetupCoreAndPlugins(npSetup.core, npSetup.plugins); - bindNpStartCoreAndPlugins(npStart.core, npStart.plugins); - } - - async isEditable() { - return getMapsCapabilities().save as boolean; - } - - // Not supported yet for maps types. - canCreateNew() { - return false; - } - - getDisplayName() { - return i18n.translate('xpack.maps.embeddableDisplayName', { - defaultMessage: 'map', - }); - } - - async _getIndexPatterns(layerList: unknown[]): Promise { - // Need to extract layerList from store to get queryable index pattern ids - const store = createMapStore(); - let queryableIndexPatternIds; - try { - layerList.forEach((layerDescriptor: unknown) => { - store.dispatch(addLayerWithoutDataSync(layerDescriptor)); - }); - queryableIndexPatternIds = getQueryableUniqueIndexPatternIds(store.getState()); - } catch (error) { - throw new Error( - i18n.translate('xpack.maps.mapEmbeddableFactory.invalidLayerList', { - defaultMessage: 'Unable to load map, malformed layer list', - }) - ); - } - - const promises = queryableIndexPatternIds.map(async indexPatternId => { - try { - return await getIndexPatternService().get(indexPatternId); - } catch (error) { - // Unable to load index pattern, better to not throw error so map embeddable can render - // Error will be surfaced by map embeddable since it too will be unable to locate the index pattern - return null; - } - }); - const indexPatterns = await Promise.all(promises); - return _.compact(indexPatterns) as IIndexPattern[]; - } - - async _fetchSavedMap(savedObjectId: string) { - const savedObjectLoader = getMapsSavedObjectLoader(); - return await savedObjectLoader.get(savedObjectId); - } - - createFromSavedObject = async ( - savedObjectId: string, - input: MapEmbeddableInput, - parent?: IContainer - ) => { - const savedMap = await this._fetchSavedMap(savedObjectId); - const layerList = getInitialLayers(savedMap.layerListJSON); - const indexPatterns = await this._getIndexPatterns(layerList); - - const embeddable = new MapEmbeddable( - { - layerList, - title: savedMap.title, - editUrl: getHttp().basePath.prepend(createMapPath(savedObjectId)), - indexPatterns, - editable: await this.isEditable(), - }, - input, - parent - ); - - try { - embeddable.updateInput(mergeInputWithSavedMap(input, savedMap)); - } catch (error) { - throw new Error( - i18n.translate('xpack.maps.mapEmbeddableFactory.invalidSavedObject', { - defaultMessage: 'Unable to load map, malformed saved object', - }) - ); - } - - return embeddable; - }; +import { MAP_SAVED_OBJECT_TYPE } from '../../../../../plugins/maps/common/constants'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { MapEmbeddableFactory } from '../../../../../plugins/maps/public/embeddable'; - create = async (input: MapEmbeddableInput, parent?: IContainer) => { - const layerList = getInitialLayers(); - const indexPatterns = await this._getIndexPatterns(layerList); +bindSetupCoreAndPlugins(npSetup.core, npSetup.plugins); +bindStartCoreAndPlugins(npStart.core, npStart.plugins); - return new MapEmbeddable( - { - layerList, - title: input.title ?? '', - indexPatterns, - editable: false, - }, - input, - parent - ); - }; -} +export * from '../../../../../plugins/maps/public/embeddable/map_embeddable_factory'; npSetup.plugins.embeddable.registerEmbeddableFactory( MAP_SAVED_OBJECT_TYPE, diff --git a/x-pack/legacy/plugins/maps/public/index.scss b/x-pack/legacy/plugins/maps/public/index.scss index b2ac514299d80c..b2a228f01b9210 100644 --- a/x-pack/legacy/plugins/maps/public/index.scss +++ b/x-pack/legacy/plugins/maps/public/index.scss @@ -1,17 +1,3 @@ -// Import the EUI global scope so we can use EUI constants -@import 'src/legacy/ui/public/styles/_styling_constants'; - /* GIS plugin styles */ -// Prefix all styles with "map" to avoid conflicts. -// Examples -// mapChart -// mapChart__legend -// mapChart__legend--small -// mapChart__legend-isLoading - -@import './main'; -@import './mapbox_hacks'; -@import './connected_components/index'; -@import './components/index'; -@import '../../../../plugins/maps/public/layers/index'; +@import '../../../../plugins/maps/public/index'; diff --git a/x-pack/legacy/plugins/maps/public/index.ts b/x-pack/legacy/plugins/maps/public/index.ts index 8555594e909d38..98db26859297b9 100644 --- a/x-pack/legacy/plugins/maps/public/index.ts +++ b/x-pack/legacy/plugins/maps/public/index.ts @@ -15,15 +15,14 @@ import 'uiExports/embeddableActions'; import 'ui/autoload/all'; import 'react-vis/dist/style.css'; - -import './angular/services/gis_map_saved_object_loader'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import '../../../../plugins/maps/public/angular/services/gis_map_saved_object_loader'; import './angular/map_controller'; import './routes'; // @ts-ignore -import { PluginInitializerContext } from 'kibana/public'; import { MapsPlugin } from './plugin'; -export const plugin = (initializerContext: PluginInitializerContext) => { +export const plugin = () => { return new MapsPlugin(); }; @@ -32,4 +31,4 @@ export { RenderTooltipContentParams, ITooltipProperty, } from '../../../../plugins/maps/public/layers/tooltips/tooltip_property'; -export { MapEmbeddable, MapEmbeddableInput } from './embeddable'; +export { MapEmbeddable, MapEmbeddableInput } from '../../../../plugins/maps/public/embeddable'; diff --git a/x-pack/legacy/plugins/maps/public/legacy.ts b/x-pack/legacy/plugins/maps/public/legacy.ts index 96d9e09c1d09a1..bcbfca17755fb4 100644 --- a/x-pack/legacy/plugins/maps/public/legacy.ts +++ b/x-pack/legacy/plugins/maps/public/legacy.ts @@ -7,10 +7,9 @@ import { npSetup, npStart } from 'ui/new_platform'; // @ts-ignore Untyped Module import { uiModules } from 'ui/modules'; -import { PluginInitializerContext } from 'kibana/public'; // eslint-disable-line import/order import { plugin } from '.'; -const pluginInstance = plugin({} as PluginInitializerContext); +const pluginInstance = plugin(); const setupPlugins = { __LEGACY: { diff --git a/x-pack/legacy/plugins/maps/public/legacy_register_feature.ts b/x-pack/legacy/plugins/maps/public/legacy_register_feature.ts deleted file mode 100644 index 00f788f267d4b1..00000000000000 --- a/x-pack/legacy/plugins/maps/public/legacy_register_feature.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { npSetup } from 'ui/new_platform'; -import { featureCatalogueEntry } from './feature_catalogue_entry'; - -const { - plugins: { home }, -} = npSetup; - -home.featureCatalogue.register(featureCatalogueEntry); diff --git a/x-pack/legacy/plugins/maps/public/plugin.ts b/x-pack/legacy/plugins/maps/public/plugin.ts index 4ec068ff440294..0123e32b6d3b93 100644 --- a/x-pack/legacy/plugins/maps/public/plugin.ts +++ b/x-pack/legacy/plugins/maps/public/plugin.ts @@ -4,20 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import '../../../../plugins/maps/public/layers/layer_wizard_registry'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import '../../../../plugins/maps/public/layers/sources/source_registry'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import '../../../../plugins/maps/public/layers/load_layer_wizards'; - import { Plugin, CoreStart, CoreSetup } from 'src/core/public'; // @ts-ignore import { Start as InspectorStartContract } from 'src/plugins/inspector/public'; // @ts-ignore import { wrapInI18nContext } from 'ui/i18n'; // @ts-ignore -import { MapListing } from './components/map_listing'; +import { MapListing } from '../../../../plugins/maps/public/components/map_listing'; // eslint-disable-line @kbn/eslint/no-restricted-paths // @ts-ignore import { bindSetupCoreAndPlugins as bindNpSetupCoreAndPlugins, @@ -25,7 +18,6 @@ import { } from '../../../../plugins/maps/public/plugin'; // eslint-disable-line @kbn/eslint/no-restricted-paths import { HomePublicPluginSetup } from '../../../../../src/plugins/home/public'; import { LicensingPluginSetup } from '../../../../plugins/licensing/public'; -import { featureCatalogueEntry } from './feature_catalogue_entry'; import { DataPublicPluginSetup, DataPublicPluginStart, @@ -64,8 +56,6 @@ export class MapsPlugin implements Plugin { }); bindNpSetupCoreAndPlugins(core, np); - - np.home.featureCatalogue.register(featureCatalogueEntry); } public start(core: CoreStart, plugins: MapsPluginStartDependencies) { diff --git a/x-pack/legacy/plugins/maps/public/register_vis_type_alias.js b/x-pack/legacy/plugins/maps/public/register_vis_type_alias.js deleted file mode 100644 index 9dc07bcb5dc0e9..00000000000000 --- a/x-pack/legacy/plugins/maps/public/register_vis_type_alias.js +++ /dev/null @@ -1,49 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; -import { APP_ID, APP_ICON, MAP_BASE_URL } from '../common/constants'; -import { - getInjectedVarFunc, - getVisualizations, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../plugins/maps/public/kibana_services'; -import { npSetup } from 'ui/new_platform'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { bindSetupCoreAndPlugins } from '../../../../plugins/maps/public/plugin'; - -bindSetupCoreAndPlugins(npSetup.core, npSetup.plugins); - -const showMapVisualizationTypes = getInjectedVarFunc()('showMapVisualizationTypes', false); - -const description = i18n.translate('xpack.maps.visTypeAlias.description', { - defaultMessage: 'Create and style maps with multiple layers and indices.', -}); - -const legacyMapVisualizationWarning = i18n.translate( - 'xpack.maps.visTypeAlias.legacyMapVizWarning', - { - defaultMessage: `Use the Maps app instead of Coordinate Map and Region Map. -The Maps app offers more functionality and is easier to use.`, - } -); - -getVisualizations().registerAlias({ - aliasUrl: MAP_BASE_URL, - name: APP_ID, - title: i18n.translate('xpack.maps.visTypeAlias.title', { - defaultMessage: 'Maps', - }), - description: showMapVisualizationTypes - ? `${description} ${legacyMapVisualizationWarning}` - : description, - icon: APP_ICON, - stage: 'production', -}); - -if (!showMapVisualizationTypes) { - getVisualizations().hideTypes(['region_map', 'tile_map']); -} diff --git a/x-pack/legacy/plugins/maps/public/routes.js b/x-pack/legacy/plugins/maps/public/routes.js index c082e0e1352c0e..70c1c4a50efd45 100644 --- a/x-pack/legacy/plugins/maps/public/routes.js +++ b/x-pack/legacy/plugins/maps/public/routes.js @@ -6,15 +6,18 @@ import { i18n } from '@kbn/i18n'; import routes from 'ui/routes'; -import listingTemplate from './angular/listing_ng_wrapper.html'; -import mapTemplate from './angular/map.html'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import listingTemplate from '../../../../plugins/maps/public/angular/listing_ng_wrapper.html'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import mapTemplate from '../../../../plugins/maps/public/angular/map.html'; import { getSavedObjectsClient, getCoreChrome, getMapsCapabilities, // eslint-disable-next-line @kbn/eslint/no-restricted-paths } from '../../../../plugins/maps/public/kibana_services'; -import { getMapsSavedObjectLoader } from './angular/services/gis_map_saved_object_loader'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { getMapsSavedObjectLoader } from '../../../../plugins/maps/public/angular/services/gis_map_saved_object_loader'; routes.enable(); diff --git a/x-pack/legacy/plugins/maps/server/lib/get_index_pattern_settings.js b/x-pack/legacy/plugins/maps/server/lib/get_index_pattern_settings.js index c5522b7ba21c58..e2a758075155a5 100644 --- a/x-pack/legacy/plugins/maps/server/lib/get_index_pattern_settings.js +++ b/x-pack/legacy/plugins/maps/server/lib/get_index_pattern_settings.js @@ -5,7 +5,10 @@ */ import _ from 'lodash'; -import { DEFAULT_MAX_RESULT_WINDOW, DEFAULT_MAX_INNER_RESULT_WINDOW } from '../../common/constants'; +import { + DEFAULT_MAX_RESULT_WINDOW, + DEFAULT_MAX_INNER_RESULT_WINDOW, +} from '../../../../../plugins/maps/common/constants'; export function getIndexPatternSettings(indicesSettingsResp) { let maxResultWindow = Infinity; diff --git a/x-pack/legacy/plugins/maps/server/lib/get_index_pattern_settings.test.js b/x-pack/legacy/plugins/maps/server/lib/get_index_pattern_settings.test.js index 01a1ba2703cba3..c152f5bfffc31c 100644 --- a/x-pack/legacy/plugins/maps/server/lib/get_index_pattern_settings.test.js +++ b/x-pack/legacy/plugins/maps/server/lib/get_index_pattern_settings.test.js @@ -5,7 +5,10 @@ */ import { getIndexPatternSettings } from './get_index_pattern_settings'; -import { DEFAULT_MAX_RESULT_WINDOW, DEFAULT_MAX_INNER_RESULT_WINDOW } from '../../common/constants'; +import { + DEFAULT_MAX_RESULT_WINDOW, + DEFAULT_MAX_INNER_RESULT_WINDOW, +} from '../../../../../plugins/maps/common/constants'; describe('max_result_window and max_inner_result_window are not set', () => { test('Should provide default values when values not set', () => { diff --git a/x-pack/legacy/plugins/maps/server/maps_telemetry/collectors/register.ts b/x-pack/legacy/plugins/maps/server/maps_telemetry/collectors/register.ts index 652bb83a0d781c..d34e306d1fff90 100644 --- a/x-pack/legacy/plugins/maps/server/maps_telemetry/collectors/register.ts +++ b/x-pack/legacy/plugins/maps/server/maps_telemetry/collectors/register.ts @@ -9,7 +9,7 @@ import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { SavedObjectsClientContract } from 'src/core/server'; import { getMapsTelemetry } from '../maps_telemetry'; // @ts-ignore -import { TELEMETRY_TYPE } from '../../../common/constants'; +import { TELEMETRY_TYPE } from '../../../../../../plugins/maps/common/constants'; export function registerMapsUsageCollector( usageCollection: UsageCollectionSetup, diff --git a/x-pack/legacy/plugins/maps/server/maps_telemetry/maps_telemetry.ts b/x-pack/legacy/plugins/maps/server/maps_telemetry/maps_telemetry.ts index 27c0211446e852..4610baabad3fe5 100644 --- a/x-pack/legacy/plugins/maps/server/maps_telemetry/maps_telemetry.ts +++ b/x-pack/legacy/plugins/maps/server/maps_telemetry/maps_telemetry.ts @@ -16,8 +16,8 @@ import { ES_GEO_FIELD_TYPE, MAP_SAVED_OBJECT_TYPE, TELEMETRY_TYPE, -} from '../../common/constants'; -import { LayerDescriptor } from '../../common/descriptor_types'; +} from '../../../../../plugins/maps/common/constants'; +import { LayerDescriptor } from '../../../../../plugins/maps/common/descriptor_types'; import { MapSavedObject } from '../../../../../plugins/maps/common/map_saved_object_type'; interface IStats { diff --git a/x-pack/legacy/plugins/maps/server/plugin.js b/x-pack/legacy/plugins/maps/server/plugin.js index 25c552433e9f82..79f3dcf76b82eb 100644 --- a/x-pack/legacy/plugins/maps/server/plugin.js +++ b/x-pack/legacy/plugins/maps/server/plugin.js @@ -4,7 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ import { i18n } from '@kbn/i18n'; -import { APP_ID, APP_ICON, createMapPath, MAP_SAVED_OBJECT_TYPE } from '../common/constants'; +import { + APP_ID, + APP_ICON, + createMapPath, + MAP_SAVED_OBJECT_TYPE, +} from '../../../../plugins/maps/common/constants'; import { getEcommerceSavedObjects } from './sample_data/ecommerce_saved_objects'; import { getFlightsSavedObjects } from './sample_data/flights_saved_objects.js'; import { getWebLogsSavedObjects } from './sample_data/web_logs_saved_objects.js'; diff --git a/x-pack/legacy/plugins/maps/server/routes.js b/x-pack/legacy/plugins/maps/server/routes.js index 20e022001577a8..d49f9827e3ea04 100644 --- a/x-pack/legacy/plugins/maps/server/routes.js +++ b/x-pack/legacy/plugins/maps/server/routes.js @@ -21,7 +21,7 @@ import { GIS_API_PATH, EMS_SPRITES_PATH, INDEX_SETTINGS_API_PATH, -} from '../common/constants'; +} from '../../../../plugins/maps/common/constants'; import { EMSClient } from '@elastic/ems-client'; import fetch from 'node-fetch'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/legacy/plugins/reporting/common/constants.ts b/x-pack/legacy/plugins/reporting/common/constants.ts index e3d6a4274e7df7..f30a7cc87f3187 100644 --- a/x-pack/legacy/plugins/reporting/common/constants.ts +++ b/x-pack/legacy/plugins/reporting/common/constants.ts @@ -20,6 +20,7 @@ export const API_GENERATE_IMMEDIATE = `${API_BASE_URL_V1}/generate/immediate/csv export const CONTENT_TYPE_CSV = 'text/csv'; export const CSV_REPORTING_ACTION = 'downloadCsvReport'; export const CSV_BOM_CHARS = '\ufeff'; +export const CSV_FORMULA_CHARS = ['=', '+', '-', '@']; export const WHITELISTED_JOB_CONTENT_TYPES = [ 'application/json', diff --git a/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.test.ts b/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.test.ts index 0f7f01fa171215..ba527152a554a6 100644 --- a/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.test.ts +++ b/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.test.ts @@ -300,7 +300,7 @@ describe('CSV Execute Job', function() { }); }); - describe('Cells with formula values', () => { + describe('Warning when cells have formulas', () => { it('returns `csv_contains_formulas` when cells contain formulas', async function() { configGetStub.withArgs('csv', 'checkForFormulas').returns(true); callAsCurrentUserStub.onFirstCall().returns({ @@ -353,6 +353,7 @@ describe('CSV Execute Job', function() { it('returns no warnings when cells have no formulas', async function() { configGetStub.withArgs('csv', 'checkForFormulas').returns(true); + configGetStub.withArgs('csv', 'escapeFormulaValues').returns(false); callAsCurrentUserStub.onFirstCall().returns({ hits: { hits: [{ _source: { one: 'foo', two: 'bar' } }], @@ -376,6 +377,33 @@ describe('CSV Execute Job', function() { expect(csvContainsFormulas).toEqual(false); }); + it('returns no warnings when cells have formulas but are escaped', async function() { + configGetStub.withArgs('csv', 'checkForFormulas').returns(true); + configGetStub.withArgs('csv', 'escapeFormulaValues').returns(true); + callAsCurrentUserStub.onFirstCall().returns({ + hits: { + hits: [{ _source: { '=SUM(A1:A2)': 'foo', two: 'bar' } }], + }, + _scroll_id: 'scrollId', + }); + + const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger); + const jobParams = getJobDocPayload({ + headers: encryptedHeaders, + fields: ['=SUM(A1:A2)', 'two'], + conflictedTypesFields: [], + searchRequest: { index: null, body: null }, + }); + + const { csv_contains_formulas: csvContainsFormulas } = await executeJob( + 'job123', + jobParams, + cancellationToken + ); + + expect(csvContainsFormulas).toEqual(false); + }); + it('returns no warnings when configured not to', async () => { configGetStub.withArgs('csv', 'checkForFormulas').returns(false); callAsCurrentUserStub.onFirstCall().returns({ @@ -446,6 +474,50 @@ describe('CSV Execute Job', function() { }); }); + describe('Escaping cells with formulas', () => { + it('escapes values with formulas', async () => { + configGetStub.withArgs('csv', 'escapeFormulaValues').returns(true); + callAsCurrentUserStub.onFirstCall().returns({ + hits: { + hits: [{ _source: { one: `=cmd|' /C calc'!A0`, two: 'bar' } }], + }, + _scroll_id: 'scrollId', + }); + + const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger); + const jobParams = getJobDocPayload({ + headers: encryptedHeaders, + fields: ['one', 'two'], + conflictedTypesFields: [], + searchRequest: { index: null, body: null }, + }); + const { content } = await executeJob('job123', jobParams, cancellationToken); + + expect(content).toEqual("one,two\n\"'=cmd|' /C calc'!A0\",bar\n"); + }); + + it('does not escapes values with formulas', async () => { + configGetStub.withArgs('csv', 'escapeFormulaValues').returns(false); + callAsCurrentUserStub.onFirstCall().returns({ + hits: { + hits: [{ _source: { one: `=cmd|' /C calc'!A0`, two: 'bar' } }], + }, + _scroll_id: 'scrollId', + }); + + const executeJob = await executeJobFactory(mockReportingPlugin, mockLogger); + const jobParams = getJobDocPayload({ + headers: encryptedHeaders, + fields: ['one', 'two'], + conflictedTypesFields: [], + searchRequest: { index: null, body: null }, + }); + const { content } = await executeJob('job123', jobParams, cancellationToken); + + expect(content).toEqual('one,two\n"=cmd|\' /C calc\'!A0",bar\n'); + }); + }); + describe('Elasticsearch call errors', function() { it('should reject Promise if search call errors out', async function() { callAsCurrentUserStub.rejects(new Error()); diff --git a/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.ts b/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.ts index 376a398da274f9..dbe305bc452dbf 100644 --- a/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.ts +++ b/x-pack/legacy/plugins/reporting/export_types/csv/server/execute_job.ts @@ -123,7 +123,7 @@ export const executeJobFactory: ExecuteJobFactory + CSV_FORMULA_CHARS.some(formulaChar => startsWith(val, formulaChar)); diff --git a/x-pack/legacy/plugins/reporting/export_types/csv/server/lib/check_cells_for_formulas.ts b/x-pack/legacy/plugins/reporting/export_types/csv/server/lib/check_cells_for_formulas.ts index 09f7cd2061ffbb..0ec39c527d6567 100644 --- a/x-pack/legacy/plugins/reporting/export_types/csv/server/lib/check_cells_for_formulas.ts +++ b/x-pack/legacy/plugins/reporting/export_types/csv/server/lib/check_cells_for_formulas.ts @@ -5,8 +5,7 @@ */ import * as _ from 'lodash'; - -const formulaValues = ['=', '+', '-', '@']; +import { cellHasFormulas } from './cell_has_formula'; interface IFlattened { [header: string]: string; @@ -14,7 +13,7 @@ interface IFlattened { export const checkIfRowsHaveFormulas = (flattened: IFlattened, fields: string[]) => { const pruned = _.pick(flattened, fields); - const csvValues = [..._.keys(pruned), ...(_.values(pruned) as string[])]; + const cells = [..._.keys(pruned), ...(_.values(pruned) as string[])]; - return _.some(csvValues, cell => _.some(formulaValues, char => _.startsWith(cell, char))); + return _.some(cells, cell => cellHasFormulas(cell)); }; diff --git a/x-pack/legacy/plugins/reporting/export_types/csv/server/lib/escape_value.test.ts b/x-pack/legacy/plugins/reporting/export_types/csv/server/lib/escape_value.test.ts index 64b021a2aeea84..dd0f9d08b864b9 100644 --- a/x-pack/legacy/plugins/reporting/export_types/csv/server/lib/escape_value.test.ts +++ b/x-pack/legacy/plugins/reporting/export_types/csv/server/lib/escape_value.test.ts @@ -11,7 +11,7 @@ describe('escapeValue', function() { describe('quoteValues is true', function() { let escapeValue: (val: string) => string; beforeEach(function() { - escapeValue = createEscapeValue(true); + escapeValue = createEscapeValue(true, false); }); it('should escape value with spaces', function() { @@ -46,7 +46,7 @@ describe('escapeValue', function() { describe('quoteValues is false', function() { let escapeValue: (val: string) => string; beforeEach(function() { - escapeValue = createEscapeValue(false); + escapeValue = createEscapeValue(false, false); }); it('should return the value unescaped', function() { @@ -54,4 +54,34 @@ describe('escapeValue', function() { expect(escapeValue(value)).to.be(value); }); }); + + describe('escapeValues', () => { + describe('when true', () => { + let escapeValue: (val: string) => string; + beforeEach(function() { + escapeValue = createEscapeValue(true, true); + }); + + ['@', '+', '-', '='].forEach(badChar => { + it(`should escape ${badChar} injection values`, function() { + expect(escapeValue(`${badChar}cmd|' /C calc'!A0`)).to.be( + `"'${badChar}cmd|' /C calc'!A0"` + ); + }); + }); + }); + + describe('when false', () => { + let escapeValue: (val: string) => string; + beforeEach(function() { + escapeValue = createEscapeValue(true, false); + }); + + ['@', '+', '-', '='].forEach(badChar => { + it(`should not escape ${badChar} injection values`, function() { + expect(escapeValue(`${badChar}cmd|' /C calc'!A0`)).to.be(`"${badChar}cmd|' /C calc'!A0"`); + }); + }); + }); + }); }); diff --git a/x-pack/legacy/plugins/reporting/export_types/csv/server/lib/escape_value.ts b/x-pack/legacy/plugins/reporting/export_types/csv/server/lib/escape_value.ts index 563de563350e9e..60e75d74b2f98e 100644 --- a/x-pack/legacy/plugins/reporting/export_types/csv/server/lib/escape_value.ts +++ b/x-pack/legacy/plugins/reporting/export_types/csv/server/lib/escape_value.ts @@ -5,15 +5,20 @@ */ import { RawValue } from './types'; +import { cellHasFormulas } from './cell_has_formula'; const nonAlphaNumRE = /[^a-zA-Z0-9]/; const allDoubleQuoteRE = /"/g; -export function createEscapeValue(quoteValues: boolean): (val: RawValue) => string { +export function createEscapeValue( + quoteValues: boolean, + escapeFormulas: boolean +): (val: RawValue) => string { return function escapeValue(val: RawValue) { if (val && typeof val === 'string') { - if (quoteValues && nonAlphaNumRE.test(val)) { - return `"${val.replace(allDoubleQuoteRE, '""')}"`; + const formulasEscaped = escapeFormulas && cellHasFormulas(val) ? "'" + val : val; + if (quoteValues && nonAlphaNumRE.test(formulasEscaped)) { + return `"${formulasEscaped.replace(allDoubleQuoteRE, '""')}"`; } } diff --git a/x-pack/legacy/plugins/reporting/export_types/csv/server/lib/generate_csv.ts b/x-pack/legacy/plugins/reporting/export_types/csv/server/lib/generate_csv.ts index 1986e68917ba86..c7996ebf832a19 100644 --- a/x-pack/legacy/plugins/reporting/export_types/csv/server/lib/generate_csv.ts +++ b/x-pack/legacy/plugins/reporting/export_types/csv/server/lib/generate_csv.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { i18n } from '@kbn/i18n'; import { Logger } from '../../../../types'; import { GenerateCsvParams, SavedSearchGeneratorResult } from '../../types'; import { createFlattenHit } from './flatten_hit'; @@ -26,14 +27,17 @@ export function createGenerateCsv(logger: Logger) { cancellationToken, settings, }: GenerateCsvParams): Promise { - const escapeValue = createEscapeValue(settings.quoteValues); + const escapeValue = createEscapeValue(settings.quoteValues, settings.escapeFormulaValues); const builder = new MaxSizeStringBuilder(settings.maxSizeBytes); const header = `${fields.map(escapeValue).join(settings.separator)}\n`; + const warnings: string[] = []; + if (!builder.tryAppend(header)) { return { size: 0, content: '', maxSizeReached: true, + warnings: [], }; } @@ -82,11 +86,20 @@ export function createGenerateCsv(logger: Logger) { const size = builder.getSizeInBytes(); logger.debug(`finished generating, total size in bytes: ${size}`); + if (csvContainsFormulas && settings.escapeFormulaValues) { + warnings.push( + i18n.translate('xpack.reporting.exportTypes.csv.generateCsv.escapedFormulaValues', { + defaultMessage: 'CSV may contain formulas whose values have been escaped', + }) + ); + } + return { content: builder.getString(), - csvContainsFormulas, + csvContainsFormulas: csvContainsFormulas && !settings.escapeFormulaValues, maxSizeReached, size, + warnings, }; }; } diff --git a/x-pack/legacy/plugins/reporting/export_types/csv/types.d.ts b/x-pack/legacy/plugins/reporting/export_types/csv/types.d.ts index 529c195486bc6d..40a42db3526352 100644 --- a/x-pack/legacy/plugins/reporting/export_types/csv/types.d.ts +++ b/x-pack/legacy/plugins/reporting/export_types/csv/types.d.ts @@ -87,6 +87,7 @@ export interface SavedSearchGeneratorResult { size: number; maxSizeReached: boolean; csvContainsFormulas?: boolean; + warnings: string[]; } export interface CsvResultFromSearch { @@ -109,5 +110,6 @@ export interface GenerateCsvParams { maxSizeBytes: number; scroll: ScrollConfig; checkForFormulas?: boolean; + escapeFormulaValues: boolean; }; } diff --git a/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/lib/generate_csv_search.ts b/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/lib/generate_csv_search.ts index 9757c71c19cf41..2611b74c83de92 100644 --- a/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/lib/generate_csv_search.ts +++ b/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/lib/generate_csv_search.ts @@ -173,6 +173,7 @@ export async function generateCsvSearch( ...uiSettings, maxSizeBytes: config.get('csv', 'maxSizeBytes'), scroll: config.get('csv', 'scroll'), + escapeFormulaValues: config.get('csv', 'escapeFormulaValues'), timezone, }, }; diff --git a/x-pack/legacy/plugins/rollup/README.md b/x-pack/legacy/plugins/rollup/README.md index 6d04973de591e1..3647be38b6a09e 100644 --- a/x-pack/legacy/plugins/rollup/README.md +++ b/x-pack/legacy/plugins/rollup/README.md @@ -14,7 +14,7 @@ The rest of this doc dives into the implementation details of each of the above ## Create and manage rollup jobs -The most straight forward part of this plugin! A new app called Rollup Jobs is registered in the Management section and follows a typical CRUD UI pattern. This app allows users to create, start, stop, clone, and delete rollup jobs. There is no way to edit an existing rollup job; instead, the UI offers a cloning ability. The client-side portion of this app lives [here](public/crud_app) and uses endpoints registered [here](server/routes/api/jobs.js). +The most straight forward part of this plugin! A new app called Rollup Jobs is registered in the Management section and follows a typical CRUD UI pattern. This app allows users to create, start, stop, clone, and delete rollup jobs. There is no way to edit an existing rollup job; instead, the UI offers a cloning ability. The client-side portion of this app lives [here](../../../plugins/rollup/public/crud_app) and uses endpoints registered [here](server/routes/api/jobs.js). Refer to the [Elasticsearch documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/rollup-getting-started.html) to understand rollup indices and how to create rollup jobs. @@ -22,22 +22,22 @@ Refer to the [Elasticsearch documentation](https://www.elastic.co/guide/en/elast Kibana uses index patterns to consume and visualize rollup indices. Typically, Kibana can inspect the indices captured by an index pattern, identify its aggregations and fields, and determine how to consume the data. Rollup indices don't contain this type of information, so we predefine how to consume a rollup index pattern with the type and typeMeta fields on the index pattern saved object. All rollup index patterns have `type` defined as "rollup" and `typeMeta` defined as an object of the index pattern's capabilities. -In the Index Pattern app, the "Create index pattern" button includes a context menu when a rollup index is detected. This menu offers items for creating a standard index pattern and a rollup index pattern. A [rollup config is registered to index pattern creation extension point](public/index_pattern_creation/rollup_index_pattern_creation_config.js). The context menu behavior in particular uses the `getIndexPatternCreationOption()` method. When the user chooses to create a rollup index pattern, this config changes the behavior of the index pattern creation wizard: +In the Index Pattern app, the "Create index pattern" button includes a context menu when a rollup index is detected. This menu offers items for creating a standard index pattern and a rollup index pattern. A [rollup config is registered to index pattern creation extension point](../../../plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js). The context menu behavior in particular uses the `getIndexPatternCreationOption()` method. When the user chooses to create a rollup index pattern, this config changes the behavior of the index pattern creation wizard: 1. Adds a `Rollup` badge to rollup indices using `getIndexTags()`. 2. Enforces index pattern rules using `checkIndicesForErrors()`. Rollup index patterns must match **one** rollup index, and optionally, any number of regular indices. A rollup index pattern configured with one or more regular indices is known as a "hybrid" index pattern. This allows the user to visualize historical (rollup) data and live (regular) data in the same visualization. 3. Routes to this plugin's [rollup `_fields_for_wildcard` endpoint](server/routes/api/index_patterns.js), instead of the standard one, using `getFetchForWildcardOptions()`, so that the internal rollup data field names are mapped to the original field names. 4. Writes additional information about aggregations, fields, histogram interval, and date histogram interval and timezone to the rollup index pattern saved object using `getIndexPatternMappings()`. This collection of information is referred to as its "capabilities". -Once a rollup index pattern is created, it is tagged with `Rollup` in the list of index patterns, and its details page displays capabilities information. This is done by registering [yet another config for the index pattern list](public/index_pattern_list/rollup_index_pattern_list_config.js) extension points. +Once a rollup index pattern is created, it is tagged with `Rollup` in the list of index patterns, and its details page displays capabilities information. This is done by registering [yet another config for the index pattern list](../../../plugins/rollup/public/index_pattern_list/rollup_index_pattern_list_config.js) extension points. ## Create visualizations from rollup index patterns This plugin enables the user to create visualizations from rollup data using the Visualize app, excluding TSVB, Vega, and Timelion. When Visualize sends search requests, this plugin routes the requests to the [Elasticsearch rollup search endpoint](https://www.elastic.co/guide/en/elasticsearch/reference/current/rollup-search.html), which searches the special document structure within rollup indices. The visualization options available to users are based on the capabilities of the rollup index pattern they're visualizing. -Routing to the Elasticsearch rollup search endpoint is done by creating an extension point in Courier, effectively allowing multiple "search strategies" to be registered. A [rollup search strategy](public/search/register.js) is registered by this plugin that queries [this plugin's rollup search endpoint](server/routes/api/search.js). +Routing to the Elasticsearch rollup search endpoint is done by creating an extension point in Courier, effectively allowing multiple "search strategies" to be registered. A [rollup search strategy](../../../plugins/rollup/public/search/register.js) is registered by this plugin that queries [this plugin's rollup search endpoint](server/routes/api/search.js). -Limiting visualization editor options is done by [registering configs](public/visualize/index.js) to various vis extension points. These configs use information stored on the rollup index pattern to limit: +Limiting visualization editor options is done by [registering configs](../../../plugins/rollup/public/visualize/index.js) to various vis extension points. These configs use information stored on the rollup index pattern to limit: * Available aggregation types * Available fields for a particular aggregation * Default and base interval for histogram aggregation @@ -47,6 +47,6 @@ Limiting visualization editor options is done by [registering configs](public/vi In Index Management, similar to system indices, rollup indices are hidden by default. A toggle is provided to show rollup indices and add a badge to the table rows. This is done by using Index Management's extension points. -The toggle and badge are registered on client-side [here](public/extend_index_management/index.js). +The toggle and badge are registered on client-side [here](../../../plugins/rollup/public/extend_index_management/index.js). Additional data needed to filter rollup indices in Index Management is provided with a [data enricher](rollup_data_enricher.js). diff --git a/x-pack/legacy/plugins/rollup/common/index.ts b/x-pack/legacy/plugins/rollup/common/index.ts index 42298034622034..526af055a3ef65 100644 --- a/x-pack/legacy/plugins/rollup/common/index.ts +++ b/x-pack/legacy/plugins/rollup/common/index.ts @@ -16,24 +16,4 @@ export const PLUGIN = { }, }; -export const CONFIG_ROLLUPS = 'rollups:enableIndexPatterns'; - -export const API_BASE_PATH = '/api/rollup'; - -export { - UIM_APP_NAME, - UIM_APP_LOAD, - UIM_JOB_CREATE, - UIM_JOB_DELETE, - UIM_JOB_DELETE_MANY, - UIM_JOB_START, - UIM_JOB_START_MANY, - UIM_JOB_STOP, - UIM_JOB_STOP_MANY, - UIM_SHOW_DETAILS_CLICK, - UIM_DETAIL_PANEL_SUMMARY_TAB_CLICK, - UIM_DETAIL_PANEL_TERMS_TAB_CLICK, - UIM_DETAIL_PANEL_HISTOGRAM_TAB_CLICK, - UIM_DETAIL_PANEL_METRICS_TAB_CLICK, - UIM_DETAIL_PANEL_JSON_TAB_CLICK, -} from './ui_metric'; +export * from '../../../../plugins/rollup/common'; diff --git a/x-pack/legacy/plugins/rollup/index.ts b/x-pack/legacy/plugins/rollup/index.ts index 621667f3618b2c..f33ae7cfee0a22 100644 --- a/x-pack/legacy/plugins/rollup/index.ts +++ b/x-pack/legacy/plugins/rollup/index.ts @@ -4,40 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ -import { resolve } from 'path'; -import { i18n } from '@kbn/i18n'; import { PluginInitializerContext } from 'src/core/server'; import { RollupSetup } from '../../../plugins/rollup/server'; -import { PLUGIN, CONFIG_ROLLUPS } from './common'; +import { PLUGIN } from './common'; import { plugin } from './server'; export function rollup(kibana: any) { return new kibana.Plugin({ id: PLUGIN.ID, configPrefix: 'xpack.rollup', - publicDir: resolve(__dirname, 'public'), require: ['kibana', 'elasticsearch', 'xpack_main'], - uiExports: { - styleSheetPaths: resolve(__dirname, 'public/index.scss'), - managementSections: ['plugins/rollup/legacy'], - uiSettingDefaults: { - [CONFIG_ROLLUPS]: { - name: i18n.translate('xpack.rollupJobs.rollupIndexPatternsTitle', { - defaultMessage: 'Enable rollup index patterns', - }), - value: true, - description: i18n.translate('xpack.rollupJobs.rollupIndexPatternsDescription', { - defaultMessage: `Enable the creation of index patterns which capture rollup indices, - which in turn enable visualizations based on rollup data. Refresh - the page to apply the changes.`, - }), - category: ['rollups'], - }, - }, - indexManagement: ['plugins/rollup/legacy'], - visualize: ['plugins/rollup/legacy'], - search: ['plugins/rollup/legacy'], - }, init(server: any) { const { core: coreSetup, plugins } = server.newPlatform.setup; const { usageCollection, visTypeTimeseries, indexManagement } = plugins; diff --git a/x-pack/legacy/plugins/rollup/public/legacy.ts b/x-pack/legacy/plugins/rollup/public/legacy.ts deleted file mode 100644 index 83945110c2c760..00000000000000 --- a/x-pack/legacy/plugins/rollup/public/legacy.ts +++ /dev/null @@ -1,13 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { npSetup, npStart } from 'ui/new_platform'; -import { RollupPlugin } from './plugin'; - -const plugin = new RollupPlugin(); - -export const setup = plugin.setup(npSetup.core, npSetup.plugins); -export const start = plugin.start(npStart.core, npStart.plugins); diff --git a/x-pack/legacy/plugins/rollup/public/legacy_imports.ts b/x-pack/legacy/plugins/rollup/public/legacy_imports.ts deleted file mode 100644 index e82a41f60b1cae..00000000000000 --- a/x-pack/legacy/plugins/rollup/public/legacy_imports.ts +++ /dev/null @@ -1,7 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -export { PluginsStart } from 'ui/new_platform/new_platform'; diff --git a/x-pack/legacy/plugins/rollup/public/search/rollup_search_strategy.ts b/x-pack/legacy/plugins/rollup/public/search/rollup_search_strategy.ts deleted file mode 100644 index 4709c0aa498f81..00000000000000 --- a/x-pack/legacy/plugins/rollup/public/search/rollup_search_strategy.ts +++ /dev/null @@ -1,104 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { HttpSetup } from 'src/core/public'; -import { - SearchError, - getSearchErrorType, - IIndexPattern, - SearchStrategyProvider, - SearchResponse, - SearchRequest, -} from '../../../../../../src/plugins/data/public'; - -function serializeFetchParams(searchRequests: SearchRequest[]) { - return JSON.stringify( - searchRequests.map(searchRequestWithFetchParams => { - const indexPattern = - searchRequestWithFetchParams.index.title || searchRequestWithFetchParams.index; - const { - body: { size, aggs, query: _query }, - } = searchRequestWithFetchParams; - - const query = { - size, - aggregations: aggs, - query: _query, - }; - - return { index: indexPattern, query }; - }) - ); -} - -// Rollup search always returns 0 hits, but visualizations expect search responses -// to return hits > 0, otherwise they do not render. We fake the number of hits here -// by counting the number of aggregation buckets/values returned by rollup search. -function shimHitsInFetchResponse(response: SearchResponse[]) { - return response.map(result => { - const buckets = result.aggregations - ? Object.keys(result.aggregations).reduce((allBuckets, agg) => { - return allBuckets.concat( - result.aggregations[agg].buckets || [result.aggregations[agg].value] || [] - ); - }, []) - : []; - return buckets && buckets.length - ? { - ...result, - hits: { - ...result.hits, - total: buckets.length, - }, - } - : result; - }); -} - -export const getRollupSearchStrategy = (fetch: HttpSetup['fetch']): SearchStrategyProvider => ({ - id: 'rollup', - - search: ({ searchRequests }) => { - // Serialize the fetch params into a format suitable for the body of an ES query. - const serializedFetchParams = serializeFetchParams(searchRequests); - - const controller = new AbortController(); - const promise = fetch('../api/rollup/search', { - signal: controller.signal, - method: 'POST', - body: serializedFetchParams, - }); - - return { - searching: promise.then(shimHitsInFetchResponse).catch(error => { - const { - body: { statusCode, error: title, message }, - res: { url }, - } = error; - - // Format fetch error as a SearchError. - const searchError = new SearchError({ - status: statusCode, - title, - message: `Rollup search error: ${message}`, - path: url, - type: getSearchErrorType({ message }) || '', - }); - - return Promise.reject(searchError); - }), - abort: () => controller.abort(), - }; - }, - - isViable: (indexPattern: IIndexPattern) => { - if (!indexPattern) { - return false; - } - - return indexPattern.type === 'rollup'; - }, -}); diff --git a/x-pack/legacy/plugins/siem/index.ts b/x-pack/legacy/plugins/siem/index.ts index 6e03583dda69fa..5ffaea1ee73dfb 100644 --- a/x-pack/legacy/plugins/siem/index.ts +++ b/x-pack/legacy/plugins/siem/index.ts @@ -11,24 +11,7 @@ import { Root } from 'joi'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { savedObjectMappings } from '../../../plugins/siem/server/saved_objects'; -import { - APP_ID, - APP_NAME, - DEFAULT_INDEX_KEY, - DEFAULT_ANOMALY_SCORE, - DEFAULT_SIEM_TIME_RANGE, - DEFAULT_SIEM_REFRESH_INTERVAL, - DEFAULT_INTERVAL_PAUSE, - DEFAULT_INTERVAL_VALUE, - DEFAULT_FROM, - DEFAULT_TO, - ENABLE_NEWS_FEED_SETTING, - NEWS_FEED_URL_SETTING, - NEWS_FEED_URL_SETTING_DEFAULT, - IP_REPUTATION_LINKS_SETTING, - IP_REPUTATION_LINKS_SETTING_DEFAULT, - DEFAULT_INDEX_PATTERN, -} from '../../../plugins/siem/common/constants'; +import { APP_ID, APP_NAME } from '../../../plugins/siem/common/constants'; import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/utils'; // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -63,100 +46,6 @@ export const siem = (kibana: any) => { category: DEFAULT_APP_CATEGORIES.security, }, ], - uiSettingDefaults: { - [DEFAULT_SIEM_REFRESH_INTERVAL]: { - type: 'json', - name: i18n.translate('xpack.siem.uiSettings.defaultRefreshIntervalLabel', { - defaultMessage: 'Time filter refresh interval', - }), - value: `{ - "pause": ${DEFAULT_INTERVAL_PAUSE}, - "value": ${DEFAULT_INTERVAL_VALUE} -}`, - description: i18n.translate('xpack.siem.uiSettings.defaultRefreshIntervalDescription', { - defaultMessage: - '

Default refresh interval for the SIEM time filter, in milliseconds.

', - }), - category: ['siem'], - requiresPageReload: true, - }, - [DEFAULT_SIEM_TIME_RANGE]: { - type: 'json', - name: i18n.translate('xpack.siem.uiSettings.defaultTimeRangeLabel', { - defaultMessage: 'Time filter period', - }), - value: `{ - "from": "${DEFAULT_FROM}", - "to": "${DEFAULT_TO}" -}`, - description: i18n.translate('xpack.siem.uiSettings.defaultTimeRangeDescription', { - defaultMessage: '

Default period of time in the SIEM time filter.

', - }), - category: ['siem'], - requiresPageReload: true, - }, - [DEFAULT_INDEX_KEY]: { - name: i18n.translate('xpack.siem.uiSettings.defaultIndexLabel', { - defaultMessage: 'Elasticsearch indices', - }), - value: DEFAULT_INDEX_PATTERN, - description: i18n.translate('xpack.siem.uiSettings.defaultIndexDescription', { - defaultMessage: - '

Comma-delimited list of Elasticsearch indices from which the SIEM app collects events.

', - }), - category: ['siem'], - requiresPageReload: true, - }, - [DEFAULT_ANOMALY_SCORE]: { - name: i18n.translate('xpack.siem.uiSettings.defaultAnomalyScoreLabel', { - defaultMessage: 'Anomaly threshold', - }), - value: 50, - type: 'number', - description: i18n.translate('xpack.siem.uiSettings.defaultAnomalyScoreDescription', { - defaultMessage: - '

Value above which Machine Learning job anomalies are displayed in the SIEM app.

Valid values: 0 to 100.

', - }), - category: ['siem'], - requiresPageReload: true, - }, - [ENABLE_NEWS_FEED_SETTING]: { - name: i18n.translate('xpack.siem.uiSettings.enableNewsFeedLabel', { - defaultMessage: 'News feed', - }), - value: true, - description: i18n.translate('xpack.siem.uiSettings.enableNewsFeedDescription', { - defaultMessage: '

Enables the News feed

', - }), - type: 'boolean', - category: ['siem'], - requiresPageReload: true, - }, - [NEWS_FEED_URL_SETTING]: { - name: i18n.translate('xpack.siem.uiSettings.newsFeedUrl', { - defaultMessage: 'News feed URL', - }), - value: NEWS_FEED_URL_SETTING_DEFAULT, - description: i18n.translate('xpack.siem.uiSettings.newsFeedUrlDescription', { - defaultMessage: '

News feed content will be retrieved from this URL

', - }), - category: ['siem'], - requiresPageReload: true, - }, - [IP_REPUTATION_LINKS_SETTING]: { - name: i18n.translate('xpack.siem.uiSettings.ipReputationLinks', { - defaultMessage: 'IP Reputation Links', - }), - value: IP_REPUTATION_LINKS_SETTING_DEFAULT, - type: 'json', - description: i18n.translate('xpack.siem.uiSettings.ipReputationLinksDescription', { - defaultMessage: - 'Array of URL templates to build the list of reputation URLs to be displayed on the IP Details page.', - }), - category: ['siem'], - requiresPageReload: true, - }, - }, mappings: savedObjectMappings, }, config(Joi: Root) { diff --git a/x-pack/legacy/plugins/siem/public/containers/case/api.test.tsx b/x-pack/legacy/plugins/siem/public/containers/case/api.test.tsx index 4f5655cc9f2219..693a7175ebc3eb 100644 --- a/x-pack/legacy/plugins/siem/public/containers/case/api.test.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/case/api.test.tsx @@ -5,6 +5,9 @@ */ import { KibanaServices } from '../../lib/kibana'; + +import { CASES_URL } from '../../../../../../plugins/case/common/constants'; + import { deleteCases, getActionLicense, @@ -22,6 +25,7 @@ import { pushCase, pushToService, } from './api'; + import { actionLicenses, allCases, @@ -44,7 +48,7 @@ import { caseUserActionsSnake, casesStatusSnake, } from './mock'; -import { CASES_URL } from './constants'; + import { DEFAULT_FILTER_OPTIONS, DEFAULT_QUERY_PARAMS } from './use_get_cases'; import * as i18n from './translations'; diff --git a/x-pack/legacy/plugins/siem/public/containers/case/api.ts b/x-pack/legacy/plugins/siem/public/containers/case/api.ts index 12b4c80a2dd899..b7453616324199 100644 --- a/x-pack/legacy/plugins/siem/public/containers/case/api.ts +++ b/x-pack/legacy/plugins/siem/public/containers/case/api.ts @@ -20,6 +20,21 @@ import { ActionTypeExecutorResult, } from '../../../../../../plugins/case/common/api'; +import { + CASE_STATUS_URL, + CASES_URL, + CASE_TAGS_URL, + CASE_REPORTERS_URL, + ACTION_TYPES_URL, + ACTION_URL, +} from '../../../../../../plugins/case/common/constants'; + +import { + getCaseDetailsUrl, + getCaseUserActionUrl, + getCaseCommentsUrl, +} from '../../../../../../plugins/case/common/api/helpers'; + import { KibanaServices } from '../../lib/kibana'; import { @@ -33,8 +48,6 @@ import { CaseUserActions, } from './types'; -import { CASES_URL } from './constants'; - import { convertToCamelCase, convertAllCasesToCamel, @@ -54,7 +67,7 @@ export const getCase = async ( includeComments: boolean = true, signal: AbortSignal ): Promise => { - const response = await KibanaServices.get().http.fetch(`${CASES_URL}/${caseId}`, { + const response = await KibanaServices.get().http.fetch(getCaseDetailsUrl(caseId), { method: 'GET', query: { includeComments, @@ -65,18 +78,15 @@ export const getCase = async ( }; export const getCasesStatus = async (signal: AbortSignal): Promise => { - const response = await KibanaServices.get().http.fetch( - `${CASES_URL}/status`, - { - method: 'GET', - signal, - } - ); + const response = await KibanaServices.get().http.fetch(CASE_STATUS_URL, { + method: 'GET', + signal, + }); return convertToCamelCase(decodeCasesStatusResponse(response)); }; export const getTags = async (signal: AbortSignal): Promise => { - const response = await KibanaServices.get().http.fetch(`${CASES_URL}/tags`, { + const response = await KibanaServices.get().http.fetch(CASE_TAGS_URL, { method: 'GET', signal, }); @@ -84,7 +94,7 @@ export const getTags = async (signal: AbortSignal): Promise => { }; export const getReporters = async (signal: AbortSignal): Promise => { - const response = await KibanaServices.get().http.fetch(`${CASES_URL}/reporters`, { + const response = await KibanaServices.get().http.fetch(CASE_REPORTERS_URL, { method: 'GET', signal, }); @@ -96,7 +106,7 @@ export const getCaseUserActions = async ( signal: AbortSignal ): Promise => { const response = await KibanaServices.get().http.fetch( - `${CASES_URL}/${caseId}/user_actions`, + getCaseUserActionUrl(caseId), { method: 'GET', signal, @@ -193,14 +203,11 @@ export const patchComment = async ( version: string, signal: AbortSignal ): Promise => { - const response = await KibanaServices.get().http.fetch( - `${CASES_URL}/${caseId}/comments`, - { - method: 'PATCH', - body: JSON.stringify({ comment: commentUpdate, id: commentId, version }), - signal, - } - ); + const response = await KibanaServices.get().http.fetch(getCaseCommentsUrl(caseId), { + method: 'PATCH', + body: JSON.stringify({ comment: commentUpdate, id: commentId, version }), + signal, + }); return convertToCamelCase(decodeCaseResponse(response)); }; @@ -219,7 +226,7 @@ export const pushCase = async ( signal: AbortSignal ): Promise => { const response = await KibanaServices.get().http.fetch( - `${CASES_URL}/${caseId}/_push`, + `${getCaseDetailsUrl(caseId)}/_push`, { method: 'POST', body: JSON.stringify(push), @@ -235,7 +242,7 @@ export const pushToService = async ( signal: AbortSignal ): Promise => { const response = await KibanaServices.get().http.fetch( - `/api/action/${connectorId}/_execute`, + `${ACTION_URL}/${connectorId}/_execute`, { method: 'POST', body: JSON.stringify({ params: casePushParams }), @@ -251,7 +258,7 @@ export const pushToService = async ( }; export const getActionLicense = async (signal: AbortSignal): Promise => { - const response = await KibanaServices.get().http.fetch(`/api/action/types`, { + const response = await KibanaServices.get().http.fetch(ACTION_TYPES_URL, { method: 'GET', signal, }); diff --git a/x-pack/legacy/plugins/siem/public/containers/case/configure/api.ts b/x-pack/legacy/plugins/siem/public/containers/case/configure/api.ts index c24081c777a968..85e472811c93bf 100644 --- a/x-pack/legacy/plugins/siem/public/containers/case/configure/api.ts +++ b/x-pack/legacy/plugins/siem/public/containers/case/configure/api.ts @@ -13,26 +13,27 @@ import { } from '../../../../../../../plugins/case/common/api'; import { KibanaServices } from '../../../lib/kibana'; -import { CASES_CONFIGURE_URL } from '../constants'; +import { + CASE_CONFIGURE_CONNECTORS_URL, + CASE_CONFIGURE_URL, +} from '../../../../../../../plugins/case/common/constants'; + import { ApiProps } from '../types'; import { convertToCamelCase, decodeCaseConfigureResponse } from '../utils'; import { CaseConfigure } from './types'; export const fetchConnectors = async ({ signal }: ApiProps): Promise => { - const response = await KibanaServices.get().http.fetch( - `${CASES_CONFIGURE_URL}/connectors/_find`, - { - method: 'GET', - signal, - } - ); + const response = await KibanaServices.get().http.fetch(`${CASE_CONFIGURE_CONNECTORS_URL}/_find`, { + method: 'GET', + signal, + }); return response; }; export const getCaseConfigure = async ({ signal }: ApiProps): Promise => { const response = await KibanaServices.get().http.fetch( - CASES_CONFIGURE_URL, + CASE_CONFIGURE_URL, { method: 'GET', signal, @@ -51,7 +52,7 @@ export const postCaseConfigure = async ( signal: AbortSignal ): Promise => { const response = await KibanaServices.get().http.fetch( - CASES_CONFIGURE_URL, + CASE_CONFIGURE_URL, { method: 'POST', body: JSON.stringify(caseConfiguration), @@ -68,7 +69,7 @@ export const patchCaseConfigure = async ( signal: AbortSignal ): Promise => { const response = await KibanaServices.get().http.fetch( - CASES_CONFIGURE_URL, + CASE_CONFIGURE_URL, { method: 'PATCH', body: JSON.stringify(caseConfiguration), diff --git a/x-pack/legacy/plugins/siem/public/containers/case/constants.ts b/x-pack/legacy/plugins/siem/public/containers/case/constants.ts index ab8dc98db4f64b..d8bb499ed7922a 100644 --- a/x-pack/legacy/plugins/siem/public/containers/case/constants.ts +++ b/x-pack/legacy/plugins/siem/public/containers/case/constants.ts @@ -4,7 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -export const CASES_URL = `/api/cases`; -export const CASES_CONFIGURE_URL = `/api/cases/configure`; export const DEFAULT_TABLE_ACTIVE_PAGE = 1; export const DEFAULT_TABLE_LIMIT = 5; diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/index.test.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/index.test.tsx index f4955c2a93b8dd..59b3b02ff3587a 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/index.test.tsx @@ -5,10 +5,138 @@ */ import React from 'react'; -import { shallow } from 'enzyme'; +import { shallow, mount } from 'enzyme'; +import { act } from 'react-dom/test-utils'; +import { createKibanaContextProviderMock } from '../../../../mock/kibana_react'; +import { TestProviders } from '../../../../mock'; +import { wait } from '../../../../lib/helpers'; import { AllRules } from './index'; +jest.mock('./reducer', () => { + return { + allRulesReducer: jest.fn().mockReturnValue(() => ({ + exportRuleIds: [], + filterOptions: { + filter: 'some filter', + sortField: 'some sort field', + sortOrder: 'desc', + }, + loadingRuleIds: [], + loadingRulesAction: null, + pagination: { + page: 1, + perPage: 20, + total: 1, + }, + rules: [ + { + actions: [], + created_at: '2020-02-14T19:49:28.178Z', + created_by: 'elastic', + description: 'jibber jabber', + enabled: false, + false_positives: [], + filters: [], + from: 'now-660s', + id: 'rule-id-1', + immutable: true, + index: ['endgame-*'], + interval: '10m', + language: 'kuery', + max_signals: 100, + name: 'Credential Dumping - Detected - Elastic Endpoint', + output_index: '.siem-signals-default', + query: 'host.name:*', + references: [], + risk_score: 73, + rule_id: '571afc56-5ed9-465d-a2a9-045f099f6e7e', + severity: 'high', + tags: ['Elastic', 'Endpoint'], + threat: [], + throttle: null, + to: 'now', + type: 'query', + updated_at: '2020-02-14T19:49:28.320Z', + updated_by: 'elastic', + version: 1, + }, + ], + selectedRuleIds: [], + })), + }; +}); + +jest.mock('../../../../containers/detection_engine/rules', () => { + return { + useRules: jest.fn().mockReturnValue([ + false, + { + page: 1, + perPage: 20, + total: 1, + data: [ + { + actions: [], + created_at: '2020-02-14T19:49:28.178Z', + created_by: 'elastic', + description: 'jibber jabber', + enabled: false, + false_positives: [], + filters: [], + from: 'now-660s', + id: 'rule-id-1', + immutable: true, + index: ['endgame-*'], + interval: '10m', + language: 'kuery', + max_signals: 100, + name: 'Credential Dumping - Detected - Elastic Endpoint', + output_index: '.siem-signals-default', + query: 'host.name:*', + references: [], + risk_score: 73, + rule_id: '571afc56-5ed9-465d-a2a9-045f099f6e7e', + severity: 'high', + tags: ['Elastic', 'Endpoint'], + threat: [], + throttle: null, + to: 'now', + type: 'query', + updated_at: '2020-02-14T19:49:28.320Z', + updated_by: 'elastic', + version: 1, + }, + ], + }, + ]), + useRulesStatuses: jest.fn().mockReturnValue({ + loading: false, + rulesStatuses: [ + { + current_status: { + alert_id: 'alertId', + bulk_create_time_durations: ['2235.01'], + gap: null, + last_failure_at: null, + last_failure_message: null, + last_look_back_date: new Date().toISOString(), + last_success_at: new Date().toISOString(), + last_success_message: 'it is a success', + search_after_time_durations: ['616.97'], + status: 'succeeded', + status_date: new Date().toISOString(), + }, + failures: [], + id: '12345678987654321', + activate: true, + name: 'Test rule', + }, + ], + }), + }; +}); + jest.mock('react-router-dom', () => { const originalModule = jest.requireActual('react-router-dom'); @@ -37,4 +165,66 @@ describe('AllRules', () => { expect(wrapper.find('[title="All rules"]')).toHaveLength(1); }); + + it('renders rules tab', async () => { + const KibanaContext = createKibanaContextProviderMock(); + const wrapper = mount( + + + + + + ); + + await act(async () => { + await wait(); + + expect(wrapper.exists('[data-test-subj="monitoring-table"]')).toBeFalsy(); + expect(wrapper.exists('[data-test-subj="rules-table"]')).toBeTruthy(); + }); + }); + + it('renders monitoring tab when monitoring tab clicked', async () => { + const KibanaContext = createKibanaContextProviderMock(); + + const wrapper = mount( + + + + + + ); + const monitoringTab = wrapper.find('[data-test-subj="allRulesTableTab-monitoring"] button'); + monitoringTab.simulate('click'); + + await act(async () => { + wrapper.update(); + await wait(); + + expect(wrapper.exists('[data-test-subj="monitoring-table"]')).toBeTruthy(); + expect(wrapper.exists('[data-test-subj="rules-table"]')).toBeFalsy(); + }); + }); }); diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/index.tsx index e96ed856208bde..18ca4d42bd018d 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/all/index.tsx @@ -4,7 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiBasicTable, EuiContextMenuPanel, EuiLoadingContent, EuiSpacer } from '@elastic/eui'; +import { + EuiBasicTable, + EuiContextMenuPanel, + EuiLoadingContent, + EuiSpacer, + EuiTab, + EuiTabs, +} from '@elastic/eui'; import React, { useCallback, useEffect, useMemo, useReducer, useRef, useState } from 'react'; import { useHistory } from 'react-router-dom'; import uuid from 'uuid'; @@ -75,6 +82,24 @@ interface AllRulesProps { setRefreshRulesData: (refreshRule: (refreshPrePackagedRule?: boolean) => void) => void; } +export enum AllRulesTabs { + rules = 'rules', + monitoring = 'monitoring', +} + +const allRulesTabs = [ + { + id: AllRulesTabs.rules, + name: i18n.RULES_TAB, + disabled: false, + }, + { + id: AllRulesTabs.monitoring, + name: i18n.MONITORING_TAB, + disabled: false, + }, +]; + /** * Table Component for displaying all Rules for a given cluster. Provides the ability to filter * by name, sort by enabled, and perform the following actions: @@ -114,6 +139,7 @@ export const AllRules = React.memo( const history = useHistory(); const [, dispatchToaster] = useStateToaster(); const mlCapabilities = useMlCapabilities(); + const [allRulesTab, setAllRulesTab] = useState(AllRulesTabs.rules); // TODO: Refactor license check + hasMlAdminPermissions to common check const hasMlPermissions = @@ -271,6 +297,25 @@ export const AllRules = React.memo( return false; }, [loadingRuleIds, loadingRulesAction]); + const tabs = useMemo( + () => ( + + {allRulesTabs.map(tab => ( + setAllRulesTab(tab.id)} + isSelected={tab.id === allRulesTab} + disabled={tab.disabled} + key={tab.id} + > + {tab.name} + + ))} + + ), + [allRulesTabs, allRulesTab, setAllRulesTab] + ); + return ( <> ( exportSelectedData={exportRules} /> + {tabs} + <> @@ -321,7 +368,7 @@ export const AllRules = React.memo( )} {showRulesTable({ rulesCustomInstalled, rulesInstalled }) && !initLoading && ( <> - + @@ -352,6 +399,7 @@ export const AllRules = React.memo( { it('renders correctly', () => { @@ -16,6 +17,7 @@ describe('AllRulesTables', () => { return ( { expect(wrapper.dive().find('[data-test-subj="rules-table"]')).toHaveLength(1); }); + + it('renders rules tab when "selectedTab" is "rules"', () => { + const Component = () => { + const ref = useRef(); + + return ( + + ); + }; + const wrapper = shallow(); + + expect(wrapper.dive().find('[data-test-subj="rules-table"]')).toHaveLength(1); + expect(wrapper.dive().find('[data-test-subj="monitoring-table"]')).toHaveLength(0); + }); + + it('renders monitoring tab when "selectedTab" is "monitoring"', () => { + const Component = () => { + const ref = useRef(); + + return ( + + ); + }; + const wrapper = shallow(); + + expect(wrapper.dive().find('[data-test-subj="rules-table"]')).toHaveLength(0); + expect(wrapper.dive().find('[data-test-subj="monitoring-table"]')).toHaveLength(1); + }); }); diff --git a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/all_rules_tables/index.tsx b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/all_rules_tables/index.tsx index 31aaa426e4f3b8..8ea5606d0082c0 100644 --- a/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/all_rules_tables/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/detection_engine/rules/components/all_rules_tables/index.tsx @@ -7,13 +7,11 @@ import { EuiBasicTable, EuiBasicTableColumn, - EuiTab, - EuiTabs, EuiEmptyPrompt, Direction, EuiTableSelectionType, } from '@elastic/eui'; -import React, { useMemo, memo, useState } from 'react'; +import React, { useMemo, memo } from 'react'; import styled from 'styled-components'; import { EuiBasicTableOnChange } from '../../types'; @@ -23,6 +21,7 @@ import { RuleStatusRowItemType, } from '../../../../../pages/detection_engine/rules/all/columns'; import { Rule, Rules } from '../../../../../containers/detection_engine/rules'; +import { AllRulesTabs } from '../../all'; // EuiBasicTable give me a hardtime with adding the ref attributes so I went the easy way // after few hours of fight with typescript !!!! I lost :( @@ -57,27 +56,10 @@ interface AllRulesTablesProps { }; tableOnChangeCallback: ({ page, sort }: EuiBasicTableOnChange) => void; tableRef?: React.MutableRefObject; + selectedTab: AllRulesTabs; } -enum AllRulesTabs { - rules = 'rules', - monitoring = 'monitoring', -} - -const allRulesTabs = [ - { - id: AllRulesTabs.rules, - name: i18n.RULES_TAB, - disabled: false, - }, - { - id: AllRulesTabs.monitoring, - name: i18n.MONITORING_TAB, - disabled: false, - }, -]; - -const AllRulesTablesComponent: React.FC = ({ +export const AllRulesTablesComponent: React.FC = ({ euiBasicTableSelectionProps, hasNoPermissions, monitoringColumns, @@ -88,34 +70,17 @@ const AllRulesTablesComponent: React.FC = ({ sorting, tableOnChangeCallback, tableRef, + selectedTab, }) => { - const [allRulesTab, setAllRulesTab] = useState(AllRulesTabs.rules); const emptyPrompt = useMemo(() => { return ( {i18n.NO_RULES}} titleSize="xs" body={i18n.NO_RULES_BODY} /> ); }, []); - const tabs = useMemo( - () => ( - - {allRulesTabs.map(tab => ( - setAllRulesTab(tab.id)} - isSelected={tab.id === allRulesTab} - disabled={tab.disabled} - key={tab.id} - > - {tab.name} - - ))} - - ), - [allRulesTabs, allRulesTab, setAllRulesTab] - ); + return ( <> - {tabs} - {allRulesTab === AllRulesTabs.rules && ( + {selectedTab === AllRulesTabs.rules && ( = ({ selection={hasNoPermissions ? undefined : euiBasicTableSelectionProps} /> )} - {allRulesTab === AllRulesTabs.monitoring && ( + {selectedTab === AllRulesTabs.monitoring && ( { + return CASE_DETAILS_URL.replace('{case_id}', id); +}; + +export const getCaseCommentsUrl = (id: string): string => { + return CASE_COMMENTS_URL.replace('{case_id}', id); +}; + +export const getCaseCommentDetailsUrl = (caseId: string, commentId: string): string => { + return CASE_COMMENT_DETAILS_URL.replace('{case_id}', caseId).replace('{comment_id}', commentId); +}; + +export const getCaseUserActionUrl = (id: string): string => { + return CASE_USER_ACTIONS_URL.replace('{case_id}', id); +}; diff --git a/x-pack/plugins/case/common/constants.ts b/x-pack/plugins/case/common/constants.ts new file mode 100644 index 00000000000000..dcfa46bfa60191 --- /dev/null +++ b/x-pack/plugins/case/common/constants.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export const APP_ID = 'case'; + +/** + * Case routes + */ + +export const CASES_URL = '/api/cases'; +export const CASE_DETAILS_URL = `${CASES_URL}/{case_id}`; +export const CASE_CONFIGURE_URL = `${CASES_URL}/configure`; +export const CASE_CONFIGURE_CONNECTORS_URL = `${CASE_CONFIGURE_URL}/connectors`; +export const CASE_COMMENTS_URL = `${CASE_DETAILS_URL}/comments`; +export const CASE_COMMENT_DETAILS_URL = `${CASE_DETAILS_URL}/comments/{comment_id}`; +export const CASE_REPORTERS_URL = `${CASES_URL}/reporters`; +export const CASE_STATUS_URL = `${CASES_URL}/status`; +export const CASE_TAGS_URL = `${CASES_URL}/tags`; +export const CASE_USER_ACTIONS_URL = `${CASE_DETAILS_URL}/user_actions`; + +/** + * Action routes + */ + +export const ACTION_URL = '/api/action'; +export const ACTION_TYPES_URL = '/api/action/types'; diff --git a/x-pack/plugins/case/server/routes/api/cases/comments/delete_all_comments.ts b/x-pack/plugins/case/server/routes/api/cases/comments/delete_all_comments.ts index 1dfab165eccd72..e9bcb9690ebd86 100644 --- a/x-pack/plugins/case/server/routes/api/cases/comments/delete_all_comments.ts +++ b/x-pack/plugins/case/server/routes/api/cases/comments/delete_all_comments.ts @@ -9,11 +9,12 @@ import { schema } from '@kbn/config-schema'; import { buildCommentUserActionItem } from '../../../../services/user_actions/helpers'; import { RouteDeps } from '../../types'; import { wrapError } from '../../utils'; +import { CASE_COMMENTS_URL } from '../../../../../common/constants'; export function initDeleteAllCommentsApi({ caseService, router, userActionService }: RouteDeps) { router.delete( { - path: '/api/cases/{case_id}/comments', + path: CASE_COMMENTS_URL, validate: { params: schema.object({ case_id: schema.string(), diff --git a/x-pack/plugins/case/server/routes/api/cases/comments/delete_comment.test.ts b/x-pack/plugins/case/server/routes/api/cases/comments/delete_comment.test.ts index b2022e6dec26d6..67cb9984095709 100644 --- a/x-pack/plugins/case/server/routes/api/cases/comments/delete_comment.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/comments/delete_comment.test.ts @@ -15,6 +15,7 @@ import { mockCaseComments, } from '../../__fixtures__'; import { initDeleteCommentApi } from './delete_comment'; +import { CASE_COMMENT_DETAILS_URL } from '../../../../../common/constants'; describe('DELETE comment', () => { let routeHandler: RequestHandler; @@ -23,7 +24,7 @@ describe('DELETE comment', () => { }); it(`deletes the comment. responds with 204`, async () => { const request = httpServerMock.createKibanaRequest({ - path: '/api/cases/{case_id}/comments/{comment_id}', + path: CASE_COMMENT_DETAILS_URL, method: 'delete', params: { case_id: 'mock-id-1', @@ -43,7 +44,7 @@ describe('DELETE comment', () => { }); it(`returns an error when thrown from deleteComment service`, async () => { const request = httpServerMock.createKibanaRequest({ - path: '/api/cases/{case_id}/comments/{comment_id}', + path: CASE_COMMENT_DETAILS_URL, method: 'delete', params: { case_id: 'mock-id-1', diff --git a/x-pack/plugins/case/server/routes/api/cases/comments/delete_comment.ts b/x-pack/plugins/case/server/routes/api/cases/comments/delete_comment.ts index ff0729afed96a2..72ef400415d0fb 100644 --- a/x-pack/plugins/case/server/routes/api/cases/comments/delete_comment.ts +++ b/x-pack/plugins/case/server/routes/api/cases/comments/delete_comment.ts @@ -11,11 +11,12 @@ import { CASE_SAVED_OBJECT } from '../../../../saved_object_types'; import { buildCommentUserActionItem } from '../../../../services/user_actions/helpers'; import { RouteDeps } from '../../types'; import { wrapError } from '../../utils'; +import { CASE_COMMENT_DETAILS_URL } from '../../../../../common/constants'; export function initDeleteCommentApi({ caseService, router, userActionService }: RouteDeps) { router.delete( { - path: '/api/cases/{case_id}/comments/{comment_id}', + path: CASE_COMMENT_DETAILS_URL, validate: { params: schema.object({ case_id: schema.string(), diff --git a/x-pack/plugins/case/server/routes/api/cases/comments/find_comments.ts b/x-pack/plugins/case/server/routes/api/cases/comments/find_comments.ts index 92da64cebee741..3df9fdb80ba8a1 100644 --- a/x-pack/plugins/case/server/routes/api/cases/comments/find_comments.ts +++ b/x-pack/plugins/case/server/routes/api/cases/comments/find_comments.ts @@ -18,11 +18,12 @@ import { } from '../../../../../common/api'; import { RouteDeps } from '../../types'; import { escapeHatch, transformComments, wrapError } from '../../utils'; +import { CASE_COMMENTS_URL } from '../../../../../common/constants'; export function initFindCaseCommentsApi({ caseService, router }: RouteDeps) { router.get( { - path: '/api/cases/{case_id}/comments/_find', + path: `${CASE_COMMENTS_URL}/_find`, validate: { params: schema.object({ case_id: schema.string(), diff --git a/x-pack/plugins/case/server/routes/api/cases/comments/get_all_comment.ts b/x-pack/plugins/case/server/routes/api/cases/comments/get_all_comment.ts index 1500039eb2cc28..8d7820d4e8fece 100644 --- a/x-pack/plugins/case/server/routes/api/cases/comments/get_all_comment.ts +++ b/x-pack/plugins/case/server/routes/api/cases/comments/get_all_comment.ts @@ -9,11 +9,12 @@ import { schema } from '@kbn/config-schema'; import { AllCommentsResponseRt } from '../../../../../common/api'; import { RouteDeps } from '../../types'; import { flattenCommentSavedObjects, wrapError } from '../../utils'; +import { CASE_COMMENTS_URL } from '../../../../../common/constants'; export function initGetAllCommentsApi({ caseService, router }: RouteDeps) { router.get( { - path: '/api/cases/{case_id}/comments', + path: CASE_COMMENTS_URL, validate: { params: schema.object({ case_id: schema.string(), diff --git a/x-pack/plugins/case/server/routes/api/cases/comments/get_comment.test.ts b/x-pack/plugins/case/server/routes/api/cases/comments/get_comment.test.ts index 9c8d0e5254df0a..b5a7d6367ea4bc 100644 --- a/x-pack/plugins/case/server/routes/api/cases/comments/get_comment.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/comments/get_comment.test.ts @@ -15,6 +15,7 @@ import { } from '../../__fixtures__'; import { flattenCommentSavedObject } from '../../utils'; import { initGetCommentApi } from './get_comment'; +import { CASE_COMMENT_DETAILS_URL } from '../../../../../common/constants'; describe('GET comment', () => { let routeHandler: RequestHandler; @@ -23,7 +24,7 @@ describe('GET comment', () => { }); it(`returns the comment`, async () => { const request = httpServerMock.createKibanaRequest({ - path: '/api/cases/{case_id}/comments/{comment_id}', + path: CASE_COMMENT_DETAILS_URL, method: 'get', params: { case_id: 'mock-id-1', @@ -48,7 +49,7 @@ describe('GET comment', () => { }); it(`returns an error when getComment throws`, async () => { const request = httpServerMock.createKibanaRequest({ - path: '/api/cases/{case_id}/comments/{comment_id}', + path: CASE_COMMENT_DETAILS_URL, method: 'get', params: { case_id: 'mock-id-1', diff --git a/x-pack/plugins/case/server/routes/api/cases/comments/get_comment.ts b/x-pack/plugins/case/server/routes/api/cases/comments/get_comment.ts index 24f44a5f5129b7..5fa668f6ae5deb 100644 --- a/x-pack/plugins/case/server/routes/api/cases/comments/get_comment.ts +++ b/x-pack/plugins/case/server/routes/api/cases/comments/get_comment.ts @@ -9,11 +9,12 @@ import { schema } from '@kbn/config-schema'; import { CommentResponseRt } from '../../../../../common/api'; import { RouteDeps } from '../../types'; import { flattenCommentSavedObject, wrapError } from '../../utils'; +import { CASE_COMMENT_DETAILS_URL } from '../../../../../common/constants'; export function initGetCommentApi({ caseService, router }: RouteDeps) { router.get( { - path: '/api/cases/{case_id}/comments/{comment_id}', + path: CASE_COMMENT_DETAILS_URL, validate: { params: schema.object({ case_id: schema.string(), diff --git a/x-pack/plugins/case/server/routes/api/cases/comments/patch_comment.test.ts b/x-pack/plugins/case/server/routes/api/cases/comments/patch_comment.test.ts index 8d9906c2abe7fa..04473e302e4680 100644 --- a/x-pack/plugins/case/server/routes/api/cases/comments/patch_comment.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/comments/patch_comment.test.ts @@ -14,6 +14,7 @@ import { mockCases, } from '../../__fixtures__'; import { initPatchCommentApi } from './patch_comment'; +import { CASE_COMMENTS_URL } from '../../../../../common/constants'; describe('PATCH comment', () => { let routeHandler: RequestHandler; @@ -22,7 +23,7 @@ describe('PATCH comment', () => { }); it(`Patch a comment`, async () => { const request = httpServerMock.createKibanaRequest({ - path: '/api/cases/{case_id}/comments', + path: CASE_COMMENTS_URL, method: 'patch', params: { case_id: 'mock-id-1', @@ -50,7 +51,7 @@ describe('PATCH comment', () => { it(`Fails with 409 if version does not match`, async () => { const request = httpServerMock.createKibanaRequest({ - path: '/api/cases/{case_id}/comments', + path: CASE_COMMENTS_URL, method: 'patch', params: { case_id: 'mock-id-1', @@ -74,7 +75,7 @@ describe('PATCH comment', () => { }); it(`Returns an error if updateComment throws`, async () => { const request = httpServerMock.createKibanaRequest({ - path: '/api/cases/{case_id}/comments', + path: CASE_COMMENTS_URL, method: 'patch', params: { case_id: 'mock-id-1', diff --git a/x-pack/plugins/case/server/routes/api/cases/comments/patch_comment.ts b/x-pack/plugins/case/server/routes/api/cases/comments/patch_comment.ts index 3b38afc02ed81b..dd9b124ff1b79f 100644 --- a/x-pack/plugins/case/server/routes/api/cases/comments/patch_comment.ts +++ b/x-pack/plugins/case/server/routes/api/cases/comments/patch_comment.ts @@ -15,11 +15,12 @@ import { CASE_SAVED_OBJECT } from '../../../../saved_object_types'; import { buildCommentUserActionItem } from '../../../../services/user_actions/helpers'; import { RouteDeps } from '../../types'; import { escapeHatch, wrapError, flattenCaseSavedObject } from '../../utils'; +import { CASE_COMMENTS_URL } from '../../../../../common/constants'; export function initPatchCommentApi({ caseService, router, userActionService }: RouteDeps) { router.patch( { - path: '/api/cases/{case_id}/comments', + path: CASE_COMMENTS_URL, validate: { params: schema.object({ case_id: schema.string(), diff --git a/x-pack/plugins/case/server/routes/api/cases/comments/post_comment.test.ts b/x-pack/plugins/case/server/routes/api/cases/comments/post_comment.test.ts index 23039da681ec65..9006470f36f368 100644 --- a/x-pack/plugins/case/server/routes/api/cases/comments/post_comment.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/comments/post_comment.test.ts @@ -15,6 +15,7 @@ import { mockCaseComments, } from '../../__fixtures__'; import { initPostCommentApi } from './post_comment'; +import { CASE_COMMENTS_URL } from '../../../../../common/constants'; describe('POST comment', () => { let routeHandler: RequestHandler; @@ -27,7 +28,7 @@ describe('POST comment', () => { }); it(`Posts a new comment`, async () => { const request = httpServerMock.createKibanaRequest({ - path: '/api/cases/{case_id}/comments', + path: CASE_COMMENTS_URL, method: 'post', params: { case_id: 'mock-id-1', @@ -52,7 +53,7 @@ describe('POST comment', () => { }); it(`Returns an error if the case does not exist`, async () => { const request = httpServerMock.createKibanaRequest({ - path: '/api/cases/{case_id}/comments', + path: CASE_COMMENTS_URL, method: 'post', params: { case_id: 'this-is-not-real', @@ -75,7 +76,7 @@ describe('POST comment', () => { }); it(`Returns an error if postNewCase throws`, async () => { const request = httpServerMock.createKibanaRequest({ - path: '/api/cases/{case_id}/comments', + path: CASE_COMMENTS_URL, method: 'post', params: { case_id: 'mock-id-1', @@ -100,7 +101,7 @@ describe('POST comment', () => { routeHandler = await createRoute(initPostCommentApi, 'post', true); const request = httpServerMock.createKibanaRequest({ - path: '/api/cases/{case_id}/comments', + path: CASE_COMMENTS_URL, method: 'post', params: { case_id: 'mock-id-1', diff --git a/x-pack/plugins/case/server/routes/api/cases/comments/post_comment.ts b/x-pack/plugins/case/server/routes/api/cases/comments/post_comment.ts index 70405af26f5762..a296d9815f251b 100644 --- a/x-pack/plugins/case/server/routes/api/cases/comments/post_comment.ts +++ b/x-pack/plugins/case/server/routes/api/cases/comments/post_comment.ts @@ -15,11 +15,12 @@ import { CASE_SAVED_OBJECT } from '../../../../saved_object_types'; import { buildCommentUserActionItem } from '../../../../services/user_actions/helpers'; import { escapeHatch, transformNewComment, wrapError, flattenCaseSavedObject } from '../../utils'; import { RouteDeps } from '../../types'; +import { CASE_COMMENTS_URL } from '../../../../../common/constants'; export function initPostCommentApi({ caseService, router, userActionService }: RouteDeps) { router.post( { - path: '/api/cases/{case_id}/comments', + path: CASE_COMMENTS_URL, validate: { params: schema.object({ case_id: schema.string(), diff --git a/x-pack/plugins/case/server/routes/api/cases/configure/get_configure.test.ts b/x-pack/plugins/case/server/routes/api/cases/configure/get_configure.test.ts index 66d39c3f11d28e..5b3b6e77b94037 100644 --- a/x-pack/plugins/case/server/routes/api/cases/configure/get_configure.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/configure/get_configure.test.ts @@ -15,6 +15,7 @@ import { import { mockCaseConfigure } from '../../__fixtures__/mock_saved_objects'; import { initGetCaseConfigure } from './get_configure'; +import { CASE_CONFIGURE_URL } from '../../../../../common/constants'; describe('GET configuration', () => { let routeHandler: RequestHandler; @@ -24,7 +25,7 @@ describe('GET configuration', () => { it('returns the configuration', async () => { const req = httpServerMock.createKibanaRequest({ - path: '/api/cases/configure', + path: CASE_CONFIGURE_URL, method: 'get', }); @@ -44,7 +45,7 @@ describe('GET configuration', () => { it('handles undefined version correctly', async () => { const req = httpServerMock.createKibanaRequest({ - path: '/api/cases/configure', + path: CASE_CONFIGURE_URL, method: 'get', }); @@ -78,7 +79,7 @@ describe('GET configuration', () => { it('returns an empty object when there is no configuration', async () => { const req = httpServerMock.createKibanaRequest({ - path: '/api/cases/configure', + path: CASE_CONFIGURE_URL, method: 'get', }); @@ -95,7 +96,7 @@ describe('GET configuration', () => { it('returns an error if find throws an error', async () => { const req = httpServerMock.createKibanaRequest({ - path: '/api/cases/configure', + path: CASE_CONFIGURE_URL, method: 'get', }); diff --git a/x-pack/plugins/case/server/routes/api/cases/configure/get_configure.ts b/x-pack/plugins/case/server/routes/api/cases/configure/get_configure.ts index 2832edaa892d5d..03bec1fe72d39a 100644 --- a/x-pack/plugins/case/server/routes/api/cases/configure/get_configure.ts +++ b/x-pack/plugins/case/server/routes/api/cases/configure/get_configure.ts @@ -7,11 +7,12 @@ import { CaseConfigureResponseRt } from '../../../../../common/api'; import { RouteDeps } from '../../types'; import { wrapError } from '../../utils'; +import { CASE_CONFIGURE_URL } from '../../../../../common/constants'; export function initGetCaseConfigure({ caseConfigureService, caseService, router }: RouteDeps) { router.get( { - path: '/api/cases/configure', + path: CASE_CONFIGURE_URL, validate: false, }, async (context, request, response) => { diff --git a/x-pack/plugins/case/server/routes/api/cases/configure/get_connectors.test.ts b/x-pack/plugins/case/server/routes/api/cases/configure/get_connectors.test.ts index 62edaa0a4792aa..09692ff73b94bc 100644 --- a/x-pack/plugins/case/server/routes/api/cases/configure/get_connectors.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/configure/get_connectors.test.ts @@ -16,6 +16,7 @@ import { import { mockCaseConfigure } from '../../__fixtures__/mock_saved_objects'; import { initCaseConfigureGetActionConnector } from './get_connectors'; import { getActions } from '../../__mocks__/request_responses'; +import { CASE_CONFIGURE_CONNECTORS_URL } from '../../../../../common/constants'; describe('GET connectors', () => { let routeHandler: RequestHandler; @@ -25,7 +26,7 @@ describe('GET connectors', () => { it('returns the connectors', async () => { const req = httpServerMock.createKibanaRequest({ - path: '/api/cases/configure/connectors/_find', + path: `${CASE_CONFIGURE_CONNECTORS_URL}/_find`, method: 'get', }); @@ -44,7 +45,7 @@ describe('GET connectors', () => { it('it throws an error when actions client is null', async () => { const req = httpServerMock.createKibanaRequest({ - path: '/api/cases/configure/connectors/_find', + path: `${CASE_CONFIGURE_CONNECTORS_URL}/_find`, method: 'get', }); diff --git a/x-pack/plugins/case/server/routes/api/cases/configure/get_connectors.ts b/x-pack/plugins/case/server/routes/api/cases/configure/get_connectors.ts index 3e9a1c96d55ed8..00575655d4c426 100644 --- a/x-pack/plugins/case/server/routes/api/cases/configure/get_connectors.ts +++ b/x-pack/plugins/case/server/routes/api/cases/configure/get_connectors.ts @@ -8,6 +8,8 @@ import Boom from 'boom'; import { RouteDeps } from '../../types'; import { wrapError } from '../../utils'; +import { CASE_CONFIGURE_CONNECTORS_URL } from '../../../../../common/constants'; + /* * Be aware that this api will only return 20 connectors */ @@ -17,7 +19,7 @@ const CASE_SERVICE_NOW_ACTION = '.servicenow'; export function initCaseConfigureGetActionConnector({ caseService, router }: RouteDeps) { router.get( { - path: '/api/cases/configure/connectors/_find', + path: `${CASE_CONFIGURE_CONNECTORS_URL}/_find`, validate: false, }, async (context, request, response) => { diff --git a/x-pack/plugins/case/server/routes/api/cases/configure/patch_configure.test.ts b/x-pack/plugins/case/server/routes/api/cases/configure/patch_configure.test.ts index 5b3d68a2586644..9b71f777b95ab0 100644 --- a/x-pack/plugins/case/server/routes/api/cases/configure/patch_configure.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/configure/patch_configure.test.ts @@ -15,6 +15,7 @@ import { import { mockCaseConfigure } from '../../__fixtures__/mock_saved_objects'; import { initPatchCaseConfigure } from './patch_configure'; +import { CASE_CONFIGURE_URL } from '../../../../../common/constants'; describe('PATCH configuration', () => { let routeHandler: RequestHandler; @@ -29,7 +30,7 @@ describe('PATCH configuration', () => { it('patch configuration', async () => { const req = httpServerMock.createKibanaRequest({ - path: '/api/cases/configure', + path: CASE_CONFIGURE_URL, method: 'patch', body: { closure_type: 'close-by-pushing', @@ -61,7 +62,7 @@ describe('PATCH configuration', () => { routeHandler = await createRoute(initPatchCaseConfigure, 'patch', true); const req = httpServerMock.createKibanaRequest({ - path: '/api/cases/configure', + path: CASE_CONFIGURE_URL, method: 'patch', body: { closure_type: 'close-by-pushing', @@ -91,7 +92,7 @@ describe('PATCH configuration', () => { it('throw error when configuration have not being created', async () => { const req = httpServerMock.createKibanaRequest({ - path: '/api/cases/configure', + path: CASE_CONFIGURE_URL, method: 'patch', body: { closure_type: 'close-by-pushing', @@ -113,7 +114,7 @@ describe('PATCH configuration', () => { it('throw error when the versions are different', async () => { const req = httpServerMock.createKibanaRequest({ - path: '/api/cases/configure', + path: CASE_CONFIGURE_URL, method: 'patch', body: { closure_type: 'close-by-pushing', @@ -135,7 +136,7 @@ describe('PATCH configuration', () => { it('handles undefined version correctly', async () => { const req = httpServerMock.createKibanaRequest({ - path: '/api/cases/configure', + path: CASE_CONFIGURE_URL, method: 'patch', body: { connector_id: 'no-version', version: mockCaseConfigure[0].version }, }); diff --git a/x-pack/plugins/case/server/routes/api/cases/configure/patch_configure.ts b/x-pack/plugins/case/server/routes/api/cases/configure/patch_configure.ts index 3a1b9d5059cbc4..47f7d503e32b8d 100644 --- a/x-pack/plugins/case/server/routes/api/cases/configure/patch_configure.ts +++ b/x-pack/plugins/case/server/routes/api/cases/configure/patch_configure.ts @@ -16,11 +16,12 @@ import { } from '../../../../../common/api'; import { RouteDeps } from '../../types'; import { wrapError, escapeHatch } from '../../utils'; +import { CASE_CONFIGURE_URL } from '../../../../../common/constants'; export function initPatchCaseConfigure({ caseConfigureService, caseService, router }: RouteDeps) { router.patch( { - path: '/api/cases/configure', + path: CASE_CONFIGURE_URL, validate: { body: escapeHatch, }, diff --git a/x-pack/plugins/case/server/routes/api/cases/configure/post_configure.test.ts b/x-pack/plugins/case/server/routes/api/cases/configure/post_configure.test.ts index 7e40cad5b12981..fb95cc53a17109 100644 --- a/x-pack/plugins/case/server/routes/api/cases/configure/post_configure.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/configure/post_configure.test.ts @@ -16,6 +16,7 @@ import { import { mockCaseConfigure } from '../../__fixtures__/mock_saved_objects'; import { initPostCaseConfigure } from './post_configure'; import { newConfiguration } from '../../__mocks__/request_responses'; +import { CASE_CONFIGURE_URL } from '../../../../../common/constants'; describe('POST configuration', () => { let routeHandler: RequestHandler; @@ -30,7 +31,7 @@ describe('POST configuration', () => { it('create configuration', async () => { const req = httpServerMock.createKibanaRequest({ - path: '/api/cases/configure', + path: CASE_CONFIGURE_URL, method: 'post', body: newConfiguration, }); @@ -61,7 +62,7 @@ describe('POST configuration', () => { routeHandler = await createRoute(initPostCaseConfigure, 'post', true); const req = httpServerMock.createKibanaRequest({ - path: '/api/cases/configure', + path: CASE_CONFIGURE_URL, method: 'post', body: newConfiguration, }); @@ -90,7 +91,7 @@ describe('POST configuration', () => { it('throws when missing connector_id', async () => { const req = httpServerMock.createKibanaRequest({ - path: '/api/cases/configure', + path: CASE_CONFIGURE_URL, method: 'post', body: { connector_name: 'My connector 2', @@ -111,7 +112,7 @@ describe('POST configuration', () => { it('throws when missing connector_name', async () => { const req = httpServerMock.createKibanaRequest({ - path: '/api/cases/configure', + path: CASE_CONFIGURE_URL, method: 'post', body: { connector_id: '456', @@ -132,7 +133,7 @@ describe('POST configuration', () => { it('throws when missing closure_type', async () => { const req = httpServerMock.createKibanaRequest({ - path: '/api/cases/configure', + path: CASE_CONFIGURE_URL, method: 'post', body: { connector_id: '456', @@ -153,7 +154,7 @@ describe('POST configuration', () => { it('it deletes the previous configuration', async () => { const req = httpServerMock.createKibanaRequest({ - path: '/api/cases/configure', + path: CASE_CONFIGURE_URL, method: 'post', body: newConfiguration, }); @@ -172,7 +173,7 @@ describe('POST configuration', () => { it('it does NOT delete when not found', async () => { const req = httpServerMock.createKibanaRequest({ - path: '/api/cases/configure', + path: CASE_CONFIGURE_URL, method: 'post', body: newConfiguration, }); @@ -191,7 +192,7 @@ describe('POST configuration', () => { it('it deletes all configuration', async () => { const req = httpServerMock.createKibanaRequest({ - path: '/api/cases/configure', + path: CASE_CONFIGURE_URL, method: 'post', body: newConfiguration, }); @@ -214,7 +215,7 @@ describe('POST configuration', () => { it('returns an error if find throws an error', async () => { const req = httpServerMock.createKibanaRequest({ - path: '/api/cases/configure', + path: CASE_CONFIGURE_URL, method: 'post', body: newConfiguration, }); @@ -232,7 +233,7 @@ describe('POST configuration', () => { it('returns an error if delete throws an error', async () => { const req = httpServerMock.createKibanaRequest({ - path: '/api/cases/configure', + path: CASE_CONFIGURE_URL, method: 'post', body: newConfiguration, }); @@ -250,7 +251,7 @@ describe('POST configuration', () => { it('returns an error if post throws an error', async () => { const req = httpServerMock.createKibanaRequest({ - path: '/api/cases/configure', + path: CASE_CONFIGURE_URL, method: 'post', body: { connector_id: 'throw-error-create', @@ -272,7 +273,7 @@ describe('POST configuration', () => { it('handles undefined version correctly', async () => { const req = httpServerMock.createKibanaRequest({ - path: '/api/cases/configure', + path: CASE_CONFIGURE_URL, method: 'post', body: { ...newConfiguration, connector_id: 'no-version' }, }); diff --git a/x-pack/plugins/case/server/routes/api/cases/configure/post_configure.ts b/x-pack/plugins/case/server/routes/api/cases/configure/post_configure.ts index 2a23abf0cbf217..5c1693e728c377 100644 --- a/x-pack/plugins/case/server/routes/api/cases/configure/post_configure.ts +++ b/x-pack/plugins/case/server/routes/api/cases/configure/post_configure.ts @@ -16,11 +16,12 @@ import { } from '../../../../../common/api'; import { RouteDeps } from '../../types'; import { wrapError, escapeHatch } from '../../utils'; +import { CASE_CONFIGURE_URL } from '../../../../../common/constants'; export function initPostCaseConfigure({ caseConfigureService, caseService, router }: RouteDeps) { router.post( { - path: '/api/cases/configure', + path: CASE_CONFIGURE_URL, validate: { body: escapeHatch, }, diff --git a/x-pack/plugins/case/server/routes/api/cases/delete_cases.test.ts b/x-pack/plugins/case/server/routes/api/cases/delete_cases.test.ts index c5be6f78a15708..e655339e05eb12 100644 --- a/x-pack/plugins/case/server/routes/api/cases/delete_cases.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/delete_cases.test.ts @@ -16,6 +16,7 @@ import { mockCaseComments, } from '../__fixtures__'; import { initDeleteCasesApi } from './delete_cases'; +import { CASES_URL } from '../../../../common/constants'; describe('DELETE case', () => { let routeHandler: RequestHandler; @@ -24,7 +25,7 @@ describe('DELETE case', () => { }); it(`deletes the case. responds with 204`, async () => { const request = httpServerMock.createKibanaRequest({ - path: '/api/cases', + path: CASES_URL, method: 'delete', query: { ids: ['mock-id-1'], @@ -43,7 +44,7 @@ describe('DELETE case', () => { }); it(`returns an error when thrown from deleteCase service`, async () => { const request = httpServerMock.createKibanaRequest({ - path: '/api/cases', + path: CASES_URL, method: 'delete', query: { ids: ['not-real'], @@ -62,7 +63,7 @@ describe('DELETE case', () => { }); it(`returns an error when thrown from getAllCaseComments service`, async () => { const request = httpServerMock.createKibanaRequest({ - path: '/api/cases', + path: CASES_URL, method: 'delete', query: { ids: ['bad-guy'], @@ -81,7 +82,7 @@ describe('DELETE case', () => { }); it(`returns an error when thrown from deleteComment service`, async () => { const request = httpServerMock.createKibanaRequest({ - path: '/api/cases', + path: CASES_URL, method: 'delete', query: { ids: ['valid-id'], diff --git a/x-pack/plugins/case/server/routes/api/cases/delete_cases.ts b/x-pack/plugins/case/server/routes/api/cases/delete_cases.ts index 0214017ae5c290..20591637a6c230 100644 --- a/x-pack/plugins/case/server/routes/api/cases/delete_cases.ts +++ b/x-pack/plugins/case/server/routes/api/cases/delete_cases.ts @@ -9,11 +9,12 @@ import { schema } from '@kbn/config-schema'; import { buildCaseUserActionItem } from '../../../services/user_actions/helpers'; import { RouteDeps } from '../types'; import { wrapError } from '../utils'; +import { CASES_URL } from '../../../../common/constants'; export function initDeleteCasesApi({ caseService, router, userActionService }: RouteDeps) { router.delete( { - path: '/api/cases', + path: CASES_URL, validate: { query: schema.object({ ids: schema.arrayOf(schema.string()), diff --git a/x-pack/plugins/case/server/routes/api/cases/find_cases.test.ts b/x-pack/plugins/case/server/routes/api/cases/find_cases.test.ts index 8fafb1af0eb826..7af1cee494457a 100644 --- a/x-pack/plugins/case/server/routes/api/cases/find_cases.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/find_cases.test.ts @@ -14,6 +14,7 @@ import { mockCases, } from '../__fixtures__'; import { initFindCasesApi } from './find_cases'; +import { CASES_URL } from '../../../../common/constants'; describe('GET all cases', () => { let routeHandler: RequestHandler; @@ -22,7 +23,7 @@ describe('GET all cases', () => { }); it(`gets all the cases`, async () => { const request = httpServerMock.createKibanaRequest({ - path: '/api/cases', + path: `${CASES_URL}/_find`, method: 'get', }); 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 b2716749e97491..40fc0301b058ac 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 @@ -15,6 +15,7 @@ import { CasesFindResponseRt, CasesFindRequestRt, throwErrors } from '../../../. import { transformCases, sortToSnake, wrapError, escapeHatch } from '../utils'; import { RouteDeps, TotalCommentByCase } from '../types'; import { CASE_SAVED_OBJECT } from '../../../saved_object_types'; +import { CASES_URL } from '../../../../common/constants'; const combineFilters = (filters: string[], operator: 'OR' | 'AND'): string => filters?.filter(i => i !== '').join(` ${operator} `); @@ -41,7 +42,7 @@ const buildFilter = ( export function initFindCasesApi({ caseService, router }: RouteDeps) { router.get( { - path: '/api/cases/_find', + path: `${CASES_URL}/_find`, validate: { query: escapeHatch, }, diff --git a/x-pack/plugins/case/server/routes/api/cases/get_case.test.ts b/x-pack/plugins/case/server/routes/api/cases/get_case.test.ts index 5912df2c40aa3f..a8c12d4734b53a 100644 --- a/x-pack/plugins/case/server/routes/api/cases/get_case.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/get_case.test.ts @@ -18,6 +18,7 @@ import { } from '../__fixtures__'; import { flattenCaseSavedObject } from '../utils'; import { initGetCaseApi } from './get_case'; +import { CASE_DETAILS_URL } from '../../../../common/constants'; describe('GET case', () => { let routeHandler: RequestHandler; @@ -26,7 +27,7 @@ describe('GET case', () => { }); it(`returns the case with empty case comments when includeComments is false`, async () => { const request = httpServerMock.createKibanaRequest({ - path: '/api/cases/{case_id}', + path: CASE_DETAILS_URL, method: 'get', params: { case_id: 'mock-id-1', @@ -55,7 +56,7 @@ describe('GET case', () => { }); it(`returns an error when thrown from getCase`, async () => { const request = httpServerMock.createKibanaRequest({ - path: '/api/cases/{case_id}', + path: CASE_DETAILS_URL, method: 'get', params: { case_id: 'abcdefg', @@ -78,7 +79,7 @@ describe('GET case', () => { }); it(`returns the case with case comments when includeComments is true`, async () => { const request = httpServerMock.createKibanaRequest({ - path: '/api/cases/{case_id}', + path: CASE_DETAILS_URL, method: 'get', params: { case_id: 'mock-id-1', @@ -102,7 +103,7 @@ describe('GET case', () => { }); it(`returns an error when thrown from getAllCaseComments`, async () => { const request = httpServerMock.createKibanaRequest({ - path: '/api/cases/{case_id}', + path: CASE_DETAILS_URL, method: 'get', params: { case_id: 'bad-guy', diff --git a/x-pack/plugins/case/server/routes/api/cases/get_case.ts b/x-pack/plugins/case/server/routes/api/cases/get_case.ts index ac32b20541a9c9..1e836d38c285c3 100644 --- a/x-pack/plugins/case/server/routes/api/cases/get_case.ts +++ b/x-pack/plugins/case/server/routes/api/cases/get_case.ts @@ -9,11 +9,12 @@ import { schema } from '@kbn/config-schema'; import { CaseResponseRt } from '../../../../common/api'; import { RouteDeps } from '../types'; import { flattenCaseSavedObject, wrapError } from '../utils'; +import { CASE_DETAILS_URL } from '../../../../common/constants'; export function initGetCaseApi({ caseService, router }: RouteDeps) { router.get( { - path: '/api/cases/{case_id}', + path: CASE_DETAILS_URL, validate: { params: schema.object({ case_id: schema.string(), diff --git a/x-pack/plugins/case/server/routes/api/cases/patch_cases.ts b/x-pack/plugins/case/server/routes/api/cases/patch_cases.ts index c36ea8964dc807..57f9fc20dbf342 100644 --- a/x-pack/plugins/case/server/routes/api/cases/patch_cases.ts +++ b/x-pack/plugins/case/server/routes/api/cases/patch_cases.ts @@ -20,11 +20,12 @@ import { escapeHatch, wrapError, flattenCaseSavedObject } from '../utils'; import { RouteDeps } from '../types'; import { getCaseToUpdate } from './helpers'; import { buildCaseUserActions } from '../../../services/user_actions/helpers'; +import { CASES_URL } from '../../../../common/constants'; export function initPatchCasesApi({ caseService, router, userActionService }: RouteDeps) { router.patch( { - path: '/api/cases', + path: CASES_URL, validate: { body: escapeHatch, }, diff --git a/x-pack/plugins/case/server/routes/api/cases/post_case.test.ts b/x-pack/plugins/case/server/routes/api/cases/post_case.test.ts index 5899102224774b..0bbceb52140464 100644 --- a/x-pack/plugins/case/server/routes/api/cases/post_case.test.ts +++ b/x-pack/plugins/case/server/routes/api/cases/post_case.test.ts @@ -14,6 +14,7 @@ import { mockCases, } from '../__fixtures__'; import { initPostCaseApi } from './post_case'; +import { CASES_URL } from '../../../../common/constants'; describe('POST cases', () => { let routeHandler: RequestHandler; @@ -26,7 +27,7 @@ describe('POST cases', () => { }); it(`Posts a new case`, async () => { const request = httpServerMock.createKibanaRequest({ - path: '/api/cases', + path: CASES_URL, method: 'post', body: { description: 'This is a brand new case of a bad meanie defacing data', @@ -49,7 +50,7 @@ describe('POST cases', () => { it(`Error if you passing status for a new case`, async () => { const request = httpServerMock.createKibanaRequest({ - path: '/api/cases', + path: CASES_URL, method: 'post', body: { description: 'This is a brand new case of a bad meanie defacing data', @@ -70,7 +71,7 @@ describe('POST cases', () => { }); it(`Returns an error if postNewCase throws`, async () => { const request = httpServerMock.createKibanaRequest({ - path: '/api/cases', + path: CASES_URL, method: 'post', body: { description: 'Throw an error', @@ -93,7 +94,7 @@ describe('POST cases', () => { routeHandler = await createRoute(initPostCaseApi, 'post', true); const request = httpServerMock.createKibanaRequest({ - path: '/api/cases', + path: CASES_URL, method: 'post', body: { description: 'This is a brand new case of a bad meanie defacing data', diff --git a/x-pack/plugins/case/server/routes/api/cases/post_case.ts b/x-pack/plugins/case/server/routes/api/cases/post_case.ts index 239b8bfdf9b29a..059a8b1affd54a 100644 --- a/x-pack/plugins/case/server/routes/api/cases/post_case.ts +++ b/x-pack/plugins/case/server/routes/api/cases/post_case.ts @@ -14,11 +14,12 @@ import { flattenCaseSavedObject, transformNewCase, wrapError, escapeHatch } from import { CasePostRequestRt, throwErrors, excess, CaseResponseRt } from '../../../../common/api'; import { buildCaseUserActionItem } from '../../../services/user_actions/helpers'; import { RouteDeps } from '../types'; +import { CASES_URL } from '../../../../common/constants'; export function initPostCaseApi({ caseService, router, userActionService }: RouteDeps) { router.post( { - path: '/api/cases', + path: CASES_URL, validate: { body: escapeHatch, }, diff --git a/x-pack/plugins/case/server/routes/api/cases/push_case.ts b/x-pack/plugins/case/server/routes/api/cases/push_case.ts index aff057adea37f5..94ebe24c3d2aef 100644 --- a/x-pack/plugins/case/server/routes/api/cases/push_case.ts +++ b/x-pack/plugins/case/server/routes/api/cases/push_case.ts @@ -15,6 +15,7 @@ import { flattenCaseSavedObject, wrapError, escapeHatch } from '../utils'; import { CaseExternalServiceRequestRt, CaseResponseRt, throwErrors } from '../../../../common/api'; import { buildCaseUserActionItem } from '../../../services/user_actions/helpers'; import { RouteDeps } from '../types'; +import { CASE_DETAILS_URL } from '../../../../common/constants'; export function initPushCaseUserActionApi({ caseConfigureService, @@ -24,7 +25,7 @@ export function initPushCaseUserActionApi({ }: RouteDeps) { router.post( { - path: '/api/cases/{case_id}/_push', + path: `${CASE_DETAILS_URL}/_push`, validate: { params: schema.object({ case_id: schema.string(), diff --git a/x-pack/plugins/case/server/routes/api/cases/reporters/get_reporters.ts b/x-pack/plugins/case/server/routes/api/cases/reporters/get_reporters.ts index 56862a96e05632..3fc96f506d1757 100644 --- a/x-pack/plugins/case/server/routes/api/cases/reporters/get_reporters.ts +++ b/x-pack/plugins/case/server/routes/api/cases/reporters/get_reporters.ts @@ -7,11 +7,12 @@ import { UsersRt } from '../../../../../common/api'; import { RouteDeps } from '../../types'; import { wrapError } from '../../utils'; +import { CASE_REPORTERS_URL } from '../../../../../common/constants'; export function initGetReportersApi({ caseService, router }: RouteDeps) { router.get( { - path: '/api/cases/reporters', + path: CASE_REPORTERS_URL, validate: {}, }, async (context, request, response) => { diff --git a/x-pack/plugins/case/server/routes/api/cases/status/get_status.ts b/x-pack/plugins/case/server/routes/api/cases/status/get_status.ts index f7431729d398c2..8f86dbc91f315d 100644 --- a/x-pack/plugins/case/server/routes/api/cases/status/get_status.ts +++ b/x-pack/plugins/case/server/routes/api/cases/status/get_status.ts @@ -9,11 +9,12 @@ import { wrapError } from '../../utils'; import { CasesStatusResponseRt } from '../../../../../common/api'; import { CASE_SAVED_OBJECT } from '../../../../saved_object_types'; +import { CASE_STATUS_URL } from '../../../../../common/constants'; export function initGetCasesStatusApi({ caseService, router }: RouteDeps) { router.get( { - path: '/api/cases/status', + path: CASE_STATUS_URL, validate: {}, }, async (context, request, response) => { diff --git a/x-pack/plugins/case/server/routes/api/cases/tags/get_tags.ts b/x-pack/plugins/case/server/routes/api/cases/tags/get_tags.ts index 55e8fe2af128ca..1a3da659c58c4e 100644 --- a/x-pack/plugins/case/server/routes/api/cases/tags/get_tags.ts +++ b/x-pack/plugins/case/server/routes/api/cases/tags/get_tags.ts @@ -6,11 +6,12 @@ import { RouteDeps } from '../../types'; import { wrapError } from '../../utils'; +import { CASE_TAGS_URL } from '../../../../../common/constants'; export function initGetTagsApi({ caseService, router }: RouteDeps) { router.get( { - path: '/api/cases/tags', + path: CASE_TAGS_URL, validate: {}, }, async (context, request, response) => { diff --git a/x-pack/plugins/case/server/routes/api/cases/user_actions/get_all_user_actions.ts b/x-pack/plugins/case/server/routes/api/cases/user_actions/get_all_user_actions.ts index 2d4f16e46d5616..c90979f60d23f7 100644 --- a/x-pack/plugins/case/server/routes/api/cases/user_actions/get_all_user_actions.ts +++ b/x-pack/plugins/case/server/routes/api/cases/user_actions/get_all_user_actions.ts @@ -10,11 +10,12 @@ import { CaseUserActionsResponseRt } from '../../../../../common/api'; import { CASE_SAVED_OBJECT, CASE_COMMENT_SAVED_OBJECT } from '../../../../saved_object_types'; import { RouteDeps } from '../../types'; import { wrapError } from '../../utils'; +import { CASE_USER_ACTIONS_URL } from '../../../../../common/constants'; export function initGetAllUserActionsApi({ userActionService, router }: RouteDeps) { router.get( { - path: '/api/cases/{case_id}/user_actions', + path: CASE_USER_ACTIONS_URL, validate: { params: schema.object({ case_id: schema.string(), diff --git a/x-pack/plugins/endpoint/public/embeddables/resolver/view/defs.tsx b/x-pack/plugins/endpoint/public/embeddables/resolver/view/defs.tsx index de9c3c7e8f8f3e..064645019ca34c 100644 --- a/x-pack/plugins/endpoint/public/embeddables/resolver/view/defs.tsx +++ b/x-pack/plugins/endpoint/public/embeddables/resolver/view/defs.tsx @@ -54,7 +54,11 @@ type ResolverColorNames = | 'activeNoWarning' | 'activeWarning' | 'fullLabelBackground' - | 'inertDescription'; + | 'inertDescription' + | 'labelBackgroundTerminatedProcess' + | 'labelBackgroundTerminatedTrigger' + | 'labelBackgroundRunningProcess' + | 'labelBackgroundRunningTrigger'; export const NamedColors: Record = { ok: saturate(0.5, resolverPalette.temperatures[0]), @@ -70,6 +74,10 @@ export const NamedColors: Record = { activeNoWarning: '#0078FF', activeWarning: '#C61F38', fullLabelBackground: '#3B3C41', + labelBackgroundTerminatedProcess: '#8A96A8', + labelBackgroundTerminatedTrigger: '#8A96A8', + labelBackgroundRunningProcess: '#8A96A8', + labelBackgroundRunningTrigger: '#8A96A8', inertDescription: '#747474', }; diff --git a/x-pack/plugins/endpoint/public/embeddables/resolver/view/process_event_dot.tsx b/x-pack/plugins/endpoint/public/embeddables/resolver/view/process_event_dot.tsx index 10e331ffff02d5..3201e83164dba6 100644 --- a/x-pack/plugins/endpoint/public/embeddables/resolver/view/process_event_dot.tsx +++ b/x-pack/plugins/endpoint/public/embeddables/resolver/view/process_event_dot.tsx @@ -7,7 +7,13 @@ import React, { useCallback, useMemo } from 'react'; import styled from 'styled-components'; import { i18n } from '@kbn/i18n'; -import { htmlIdGenerator, EuiKeyboardAccessible } from '@elastic/eui'; +import { + htmlIdGenerator, + EuiKeyboardAccessible, + EuiButton, + EuiFlexGroup, + EuiFlexItem, +} from '@elastic/eui'; import { useSelector } from 'react-redux'; import { applyMatrix3 } from '../lib/vector2'; import { Vector2, Matrix3, AdjacentProcessMap, ResolverProcessType } from '../types'; @@ -21,7 +27,7 @@ import * as selectors from '../store/selectors'; const nodeAssets = { runningProcessCube: { cubeSymbol: `#${SymbolIds.runningProcessCube}`, - labelBackground: NamedColors.fullLabelBackground, + labelBackground: NamedColors.labelBackgroundRunningProcess, descriptionFill: NamedColors.empty, descriptionText: i18n.translate('xpack.endpoint.resolver.runningProcess', { defaultMessage: 'Running Process', @@ -29,7 +35,7 @@ const nodeAssets = { }, runningTriggerCube: { cubeSymbol: `#${SymbolIds.runningTriggerCube}`, - labelBackground: NamedColors.fullLabelBackground, + labelBackground: NamedColors.labelBackgroundRunningTrigger, descriptionFill: NamedColors.empty, descriptionText: i18n.translate('xpack.endpoint.resolver.runningTrigger', { defaultMessage: 'Running Trigger', @@ -37,7 +43,7 @@ const nodeAssets = { }, terminatedProcessCube: { cubeSymbol: `#${SymbolIds.terminatedProcessCube}`, - labelBackground: NamedColors.fullLabelBackground, + labelBackground: NamedColors.labelBackgroundTerminatedProcess, descriptionFill: NamedColors.empty, descriptionText: i18n.translate('xpack.endpoint.resolver.terminatedProcess', { defaultMessage: 'Terminated Process', @@ -45,7 +51,7 @@ const nodeAssets = { }, terminatedTriggerCube: { cubeSymbol: `#${SymbolIds.terminatedTriggerCube}`, - labelBackground: NamedColors.fullLabelBackground, + labelBackground: NamedColors.labelBackgroundTerminatedTrigger, descriptionFill: NamedColors.empty, descriptionText: i18n.translate('xpack.endpoint.resolver.terminatedTrigger', { defaultMessage: 'Terminated Trigger', @@ -53,8 +59,46 @@ const nodeAssets = { }, }; +const ChildEventsButton = React.memo(() => { + return ( + ) => { + clickEvent.preventDefault(); + clickEvent.stopPropagation(); + }, [])} + color="ghost" + size="s" + iconType="arrowDown" + iconSide="right" + tabIndex={-1} + > + {i18n.translate('xpack.endpoint.resolver.relatedEvents', { + defaultMessage: 'Events', + })} + + ); +}); + +const RelatedAlertsButton = React.memo(() => { + return ( + ) => { + clickEvent.preventDefault(); + clickEvent.stopPropagation(); + }, [])} + color="ghost" + size="s" + tabIndex={-1} + > + {i18n.translate('xpack.endpoint.resolver.relatedAlerts', { + defaultMessage: 'Related Alerts', + })} + + ); +}); + /** - * A placeholder view for a process node. + * An artefact that represents a process node. */ export const ProcessEventDot = styled( React.memo( @@ -184,6 +228,7 @@ export const ProcessEventDot = styled( }, [animationTarget, dispatch, nodeId] ); + /* eslint-disable jsx-a11y/click-events-have-key-events */ /** * Key event handling (e.g. 'Enter'/'Space') is provisioned by the `EuiKeyboardAccessible` component @@ -256,13 +301,17 @@ export const ProcessEventDot = styled(
{descriptionText}
= 2 ? 'euiButton' : 'euiButton euiButton--small'} data-test-subject="nodeLabel" id={labelId} style={{ backgroundColor: labelBackground, - padding: '.15em 0', + padding: '.15rem 0', textAlign: 'center', - maxWidth: '100%', + maxWidth: '20rem', + minWidth: '12rem', + width: '60%', overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis', contain: 'content', + margin: '.25rem 0 .35rem 0', }} > - {eventModel.eventName(event)} + + {eventModel.eventName(event)} +
+ {magFactorX >= 2 && ( + + + + + + + + + )}
@@ -317,6 +383,8 @@ export const ProcessEventDot = styled( white-space: nowrap; will-change: left, top, width, height; contain: strict; + min-width: 280px; + min-height: 90px; //dasharray & dashoffset should be equal to "pull" the stroke back //when it is transitioned. diff --git a/x-pack/plugins/endpoint/scripts/alert_mapping.json b/x-pack/plugins/endpoint/scripts/alert_mapping.json index a21e48b4bc95fc..2e0041d0af9867 100644 --- a/x-pack/plugins/endpoint/scripts/alert_mapping.json +++ b/x-pack/plugins/endpoint/scripts/alert_mapping.json @@ -394,7 +394,8 @@ "type": "nested" }, "file_extension": { - "type": "long" + "ignore_above": 1024, + "type": "keyword" }, "project_file": { "properties": { diff --git a/x-pack/plugins/endpoint/scripts/event_mapping.json b/x-pack/plugins/endpoint/scripts/event_mapping.json index 59d1ed17852b16..f410edc7abe5ef 100644 --- a/x-pack/plugins/endpoint/scripts/event_mapping.json +++ b/x-pack/plugins/endpoint/scripts/event_mapping.json @@ -386,7 +386,8 @@ "type": "nested" }, "file_extension": { - "type": "long" + "ignore_above": 1024, + "type": "keyword" }, "project_file": { "properties": { diff --git a/x-pack/plugins/endpoint/scripts/resolver_generator.ts b/x-pack/plugins/endpoint/scripts/resolver_generator.ts index dd9e591f4b034f..2129bef0624b87 100644 --- a/x-pack/plugins/endpoint/scripts/resolver_generator.ts +++ b/x-pack/plugins/endpoint/scripts/resolver_generator.ts @@ -29,7 +29,7 @@ async function main() { alertIndex: { alias: 'ai', describe: 'index to store alerts in', - default: '.alerts-endpoint-000001', + default: 'events-endpoint-1', type: 'string', }, eventIndex: { diff --git a/x-pack/plugins/infra/common/http_api/source_api.ts b/x-pack/plugins/infra/common/http_api/source_api.ts new file mode 100644 index 00000000000000..218f8cebc98692 --- /dev/null +++ b/x-pack/plugins/infra/common/http_api/source_api.ts @@ -0,0 +1,188 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +/* eslint-disable @typescript-eslint/no-empty-interface */ + +import * as rt from 'io-ts'; +import moment from 'moment'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { chain } from 'fp-ts/lib/Either'; + +export const TimestampFromString = new rt.Type( + 'TimestampFromString', + (input): input is number => typeof input === 'number', + (input, context) => + pipe( + rt.string.validate(input, context), + chain(stringInput => { + const momentValue = moment(stringInput); + return momentValue.isValid() + ? rt.success(momentValue.valueOf()) + : rt.failure(stringInput, context); + }) + ), + output => new Date(output).toISOString() +); + +/** + * Stored source configuration as read from and written to saved objects + */ + +const SavedSourceConfigurationFieldsRuntimeType = rt.partial({ + container: rt.string, + host: rt.string, + pod: rt.string, + tiebreaker: rt.string, + timestamp: rt.string, +}); + +export const SavedSourceConfigurationTimestampColumnRuntimeType = rt.type({ + timestampColumn: rt.type({ + id: rt.string, + }), +}); + +export const SavedSourceConfigurationMessageColumnRuntimeType = rt.type({ + messageColumn: rt.type({ + id: rt.string, + }), +}); + +export const SavedSourceConfigurationFieldColumnRuntimeType = rt.type({ + fieldColumn: rt.type({ + id: rt.string, + field: rt.string, + }), +}); + +export const SavedSourceConfigurationColumnRuntimeType = rt.union([ + SavedSourceConfigurationTimestampColumnRuntimeType, + SavedSourceConfigurationMessageColumnRuntimeType, + SavedSourceConfigurationFieldColumnRuntimeType, +]); + +export const SavedSourceConfigurationRuntimeType = rt.partial({ + name: rt.string, + description: rt.string, + metricAlias: rt.string, + logAlias: rt.string, + fields: SavedSourceConfigurationFieldsRuntimeType, + logColumns: rt.array(SavedSourceConfigurationColumnRuntimeType), +}); + +export interface InfraSavedSourceConfiguration + extends rt.TypeOf {} + +export const pickSavedSourceConfiguration = ( + value: InfraSourceConfiguration +): InfraSavedSourceConfiguration => { + const { name, description, metricAlias, logAlias, fields, logColumns } = value; + const { container, host, pod, tiebreaker, timestamp } = fields; + + return { + name, + description, + metricAlias, + logAlias, + fields: { container, host, pod, tiebreaker, timestamp }, + logColumns, + }; +}; + +/** + * Static source configuration as read from the configuration file + */ + +const StaticSourceConfigurationFieldsRuntimeType = rt.partial({ + ...SavedSourceConfigurationFieldsRuntimeType.props, + message: rt.array(rt.string), +}); + +export const StaticSourceConfigurationRuntimeType = rt.partial({ + name: rt.string, + description: rt.string, + metricAlias: rt.string, + logAlias: rt.string, + fields: StaticSourceConfigurationFieldsRuntimeType, + logColumns: rt.array(SavedSourceConfigurationColumnRuntimeType), +}); + +export interface InfraStaticSourceConfiguration + extends rt.TypeOf {} + +/** + * Full source configuration type after all cleanup has been done at the edges + */ + +const SourceConfigurationFieldsRuntimeType = rt.type({ + ...StaticSourceConfigurationFieldsRuntimeType.props, +}); + +export const SourceConfigurationRuntimeType = rt.type({ + ...SavedSourceConfigurationRuntimeType.props, + fields: SourceConfigurationFieldsRuntimeType, + logColumns: rt.array(SavedSourceConfigurationColumnRuntimeType), +}); + +export const SourceRuntimeType = rt.intersection([ + rt.type({ + id: rt.string, + origin: rt.keyof({ + fallback: null, + internal: null, + stored: null, + }), + configuration: SourceConfigurationRuntimeType, + }), + rt.partial({ + version: rt.string, + updatedAt: rt.number, + }), +]); + +export interface InfraSourceConfiguration + extends rt.TypeOf {} + +export interface InfraSource extends rt.TypeOf {} + +const SourceStatusFieldRuntimeType = rt.type({ + name: rt.string, + type: rt.string, + searchable: rt.boolean, + aggregatable: rt.boolean, + displayable: rt.boolean, +}); + +const SourceStatusRuntimeType = rt.type({ + logIndicesExist: rt.boolean, + metricIndicesExist: rt.boolean, + indexFields: rt.array(SourceStatusFieldRuntimeType), +}); + +export const SourceResponseRuntimeType = rt.type({ + source: SourceRuntimeType, + status: SourceStatusRuntimeType, +}); + +export type SourceResponse = rt.TypeOf; + +/** + * Saved object type with metadata + */ + +export const SourceConfigurationSavedObjectRuntimeType = rt.intersection([ + rt.type({ + id: rt.string, + attributes: SavedSourceConfigurationRuntimeType, + }), + rt.partial({ + version: rt.string, + updated_at: TimestampFromString, + }), +]); + +export interface SourceConfigurationSavedObject + extends rt.TypeOf {} diff --git a/x-pack/plugins/infra/common/inventory_models/aws_ec2/layout.tsx b/x-pack/plugins/infra/common/inventory_models/aws_ec2/layout.tsx index 68bfe41fd538e6..9494e4aa396a50 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_ec2/layout.tsx +++ b/x-pack/plugins/infra/common/inventory_models/aws_ec2/layout.tsx @@ -6,19 +6,19 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { LayoutPropsWithTheme } from '../../../public/pages/metrics/types'; +import { LayoutPropsWithTheme } from '../../../public/pages/metrics/metric_detail/types'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { Section } from '../../../public/pages/metrics/components/section'; +import { Section } from '../../../public/pages/metrics/metric_detail/components/section'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { SubSection } from '../../../public/pages/metrics/components/sub_section'; +import { SubSection } from '../../../public/pages/metrics/metric_detail/components/sub_section'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { LayoutContent } from '../../../public/pages/metrics/components/layout_content'; +import { LayoutContent } from '../../../public/pages/metrics/metric_detail/components/layout_content'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ChartSectionVis } from '../../../public/pages/metrics/components/chart_section_vis'; +import { ChartSectionVis } from '../../../public/pages/metrics/metric_detail/components/chart_section_vis'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { withTheme } from '../../../../observability/public'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { MetadataDetails } from '../../../public/pages/metrics/components/metadata_details'; +import { MetadataDetails } from '../../../public/pages/metrics/metric_detail/components/metadata_details'; export const Layout = withTheme(({ metrics, theme, onChangeRangeTime }: LayoutPropsWithTheme) => ( diff --git a/x-pack/plugins/infra/common/inventory_models/aws_ec2/toolbar_items.tsx b/x-pack/plugins/infra/common/inventory_models/aws_ec2/toolbar_items.tsx index 683851fec4d772..b2da7dec3f2e08 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_ec2/toolbar_items.tsx +++ b/x-pack/plugins/infra/common/inventory_models/aws_ec2/toolbar_items.tsx @@ -6,9 +6,9 @@ import React from 'react'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ToolbarProps } from '../../../public/components/inventory/toolbars/toolbar'; -import { MetricsAndGroupByToolbarItems } from '../shared/compontents/metrics_and_groupby_toolbar_items'; -import { CloudToolbarItems } from '../shared/compontents/cloud_toolbar_items'; +import { ToolbarProps } from '../../../public/pages/metrics/inventory_view/components/toolbars/toolbar'; +import { MetricsAndGroupByToolbarItems } from '../shared/components/metrics_and_groupby_toolbar_items'; +import { CloudToolbarItems } from '../shared/components/cloud_toolbar_items'; import { SnapshotMetricType } from '../types'; export const AwsEC2ToolbarItems = (props: ToolbarProps) => { diff --git a/x-pack/plugins/infra/common/inventory_models/aws_rds/layout.tsx b/x-pack/plugins/infra/common/inventory_models/aws_rds/layout.tsx index 220c6c67f4aeaa..08b865f01b06c6 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_rds/layout.tsx +++ b/x-pack/plugins/infra/common/inventory_models/aws_rds/layout.tsx @@ -6,17 +6,17 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { LayoutPropsWithTheme } from '../../../public/pages/metrics/types'; +import { LayoutPropsWithTheme } from '../../../public/pages/metrics/metric_detail/types'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { Section } from '../../../public/pages/metrics/components/section'; +import { Section } from '../../../public/pages/metrics/metric_detail/components/section'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { SubSection } from '../../../public/pages/metrics/components/sub_section'; +import { SubSection } from '../../../public/pages/metrics/metric_detail/components/sub_section'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ChartSectionVis } from '../../../public/pages/metrics/components/chart_section_vis'; +import { ChartSectionVis } from '../../../public/pages/metrics/metric_detail/components/chart_section_vis'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { withTheme } from '../../../../observability/public'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { LayoutContent } from '../../../public/pages/metrics/components/layout_content'; +import { LayoutContent } from '../../../public/pages/metrics/metric_detail/components/layout_content'; export const Layout = withTheme(({ metrics, onChangeRangeTime, theme }: LayoutPropsWithTheme) => ( diff --git a/x-pack/plugins/infra/common/inventory_models/aws_rds/toolbar_items.tsx b/x-pack/plugins/infra/common/inventory_models/aws_rds/toolbar_items.tsx index 24f05fd91589c8..2a8394b9dd3a41 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_rds/toolbar_items.tsx +++ b/x-pack/plugins/infra/common/inventory_models/aws_rds/toolbar_items.tsx @@ -6,9 +6,9 @@ import React from 'react'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ToolbarProps } from '../../../public/components/inventory/toolbars/toolbar'; -import { MetricsAndGroupByToolbarItems } from '../shared/compontents/metrics_and_groupby_toolbar_items'; -import { CloudToolbarItems } from '../shared/compontents/cloud_toolbar_items'; +import { ToolbarProps } from '../../../public/pages/metrics/inventory_view/components/toolbars/toolbar'; +import { MetricsAndGroupByToolbarItems } from '../shared/components/metrics_and_groupby_toolbar_items'; +import { CloudToolbarItems } from '../shared/components/cloud_toolbar_items'; import { SnapshotMetricType } from '../types'; export const AwsRDSToolbarItems = (props: ToolbarProps) => { diff --git a/x-pack/plugins/infra/common/inventory_models/aws_s3/layout.tsx b/x-pack/plugins/infra/common/inventory_models/aws_s3/layout.tsx index 805236cf470827..e16f8ef6addde6 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_s3/layout.tsx +++ b/x-pack/plugins/infra/common/inventory_models/aws_s3/layout.tsx @@ -6,17 +6,17 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { LayoutPropsWithTheme } from '../../../public/pages/metrics/types'; +import { LayoutPropsWithTheme } from '../../../public/pages/metrics/metric_detail/types'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { Section } from '../../../public/pages/metrics/components/section'; +import { Section } from '../../../public/pages/metrics/metric_detail/components/section'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { SubSection } from '../../../public/pages/metrics/components/sub_section'; +import { SubSection } from '../../../public/pages/metrics/metric_detail/components/sub_section'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ChartSectionVis } from '../../../public/pages/metrics/components/chart_section_vis'; +import { ChartSectionVis } from '../../../public/pages/metrics/metric_detail/components/chart_section_vis'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { withTheme } from '../../../../observability/public'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { LayoutContent } from '../../../public/pages/metrics/components/layout_content'; +import { LayoutContent } from '../../../public/pages/metrics/metric_detail/components/layout_content'; export const Layout = withTheme(({ metrics, onChangeRangeTime, theme }: LayoutPropsWithTheme) => ( diff --git a/x-pack/plugins/infra/common/inventory_models/aws_s3/toolbar_items.tsx b/x-pack/plugins/infra/common/inventory_models/aws_s3/toolbar_items.tsx index 54c3196ae28335..324bdd05860290 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_s3/toolbar_items.tsx +++ b/x-pack/plugins/infra/common/inventory_models/aws_s3/toolbar_items.tsx @@ -6,9 +6,9 @@ import React from 'react'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ToolbarProps } from '../../../public/components/inventory/toolbars/toolbar'; -import { MetricsAndGroupByToolbarItems } from '../shared/compontents/metrics_and_groupby_toolbar_items'; -import { CloudToolbarItems } from '../shared/compontents/cloud_toolbar_items'; +import { ToolbarProps } from '../../../public/pages/metrics/inventory_view/components/toolbars/toolbar'; +import { MetricsAndGroupByToolbarItems } from '../shared/components/metrics_and_groupby_toolbar_items'; +import { CloudToolbarItems } from '../shared/components/cloud_toolbar_items'; import { SnapshotMetricType } from '../types'; export const AwsS3ToolbarItems = (props: ToolbarProps) => { diff --git a/x-pack/plugins/infra/common/inventory_models/aws_sqs/layout.tsx b/x-pack/plugins/infra/common/inventory_models/aws_sqs/layout.tsx index d581ac751682d5..ff13f2db104de9 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_sqs/layout.tsx +++ b/x-pack/plugins/infra/common/inventory_models/aws_sqs/layout.tsx @@ -6,17 +6,17 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { LayoutPropsWithTheme } from '../../../public/pages/metrics/types'; +import { LayoutPropsWithTheme } from '../../../public/pages/metrics/metric_detail/types'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { Section } from '../../../public/pages/metrics/components/section'; +import { Section } from '../../../public/pages/metrics/metric_detail/components/section'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { SubSection } from '../../../public/pages/metrics/components/sub_section'; +import { SubSection } from '../../../public/pages/metrics/metric_detail/components/sub_section'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ChartSectionVis } from '../../../public/pages/metrics/components/chart_section_vis'; +import { ChartSectionVis } from '../../../public/pages/metrics/metric_detail/components/chart_section_vis'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { withTheme } from '../../../../observability/public'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { LayoutContent } from '../../../public/pages/metrics/components/layout_content'; +import { LayoutContent } from '../../../public/pages/metrics/metric_detail/components/layout_content'; export const Layout = withTheme(({ metrics, onChangeRangeTime, theme }: LayoutPropsWithTheme) => ( diff --git a/x-pack/plugins/infra/common/inventory_models/aws_sqs/toolbar_items.tsx b/x-pack/plugins/infra/common/inventory_models/aws_sqs/toolbar_items.tsx index 22cb2740a4a7f7..3229c07034772c 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_sqs/toolbar_items.tsx +++ b/x-pack/plugins/infra/common/inventory_models/aws_sqs/toolbar_items.tsx @@ -6,9 +6,9 @@ import React from 'react'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ToolbarProps } from '../../../public/components/inventory/toolbars/toolbar'; -import { MetricsAndGroupByToolbarItems } from '../shared/compontents/metrics_and_groupby_toolbar_items'; -import { CloudToolbarItems } from '../shared/compontents/cloud_toolbar_items'; +import { ToolbarProps } from '../../../public/pages/metrics/inventory_view/components/toolbars/toolbar'; +import { MetricsAndGroupByToolbarItems } from '../shared/components/metrics_and_groupby_toolbar_items'; +import { CloudToolbarItems } from '../shared/components/cloud_toolbar_items'; import { SnapshotMetricType } from '../types'; export const AwsSQSToolbarItems = (props: ToolbarProps) => { diff --git a/x-pack/plugins/infra/common/inventory_models/container/layout.tsx b/x-pack/plugins/infra/common/inventory_models/container/layout.tsx index 9956b2c9a2ce46..b9366a43e40c6b 100644 --- a/x-pack/plugins/infra/common/inventory_models/container/layout.tsx +++ b/x-pack/plugins/infra/common/inventory_models/container/layout.tsx @@ -6,21 +6,21 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { LayoutPropsWithTheme } from '../../../public/pages/metrics/types'; +import { LayoutPropsWithTheme } from '../../../public/pages/metrics/metric_detail/types'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { Section } from '../../../public/pages/metrics/components/section'; +import { Section } from '../../../public/pages/metrics/metric_detail/components/section'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { SubSection } from '../../../public/pages/metrics/components/sub_section'; +import { SubSection } from '../../../public/pages/metrics/metric_detail/components/sub_section'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { GaugesSectionVis } from '../../../public/pages/metrics/components/gauges_section_vis'; +import { GaugesSectionVis } from '../../../public/pages/metrics/metric_detail/components/gauges_section_vis'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ChartSectionVis } from '../../../public/pages/metrics/components/chart_section_vis'; +import { ChartSectionVis } from '../../../public/pages/metrics/metric_detail/components/chart_section_vis'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { withTheme } from '../../../../observability/public'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { LayoutContent } from '../../../public/pages/metrics/components/layout_content'; +import { LayoutContent } from '../../../public/pages/metrics/metric_detail/components/layout_content'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { MetadataDetails } from '../../../public/pages/metrics/components/metadata_details'; +import { MetadataDetails } from '../../../public/pages/metrics/metric_detail/components/metadata_details'; export const Layout = withTheme(({ metrics, onChangeRangeTime, theme }: LayoutPropsWithTheme) => ( diff --git a/x-pack/plugins/infra/common/inventory_models/container/toolbar_items.tsx b/x-pack/plugins/infra/common/inventory_models/container/toolbar_items.tsx index dbb77cb3b677ee..f6c707726d9ca1 100644 --- a/x-pack/plugins/infra/common/inventory_models/container/toolbar_items.tsx +++ b/x-pack/plugins/infra/common/inventory_models/container/toolbar_items.tsx @@ -6,8 +6,8 @@ import React from 'react'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ToolbarProps } from '../../../public/components/inventory/toolbars/toolbar'; -import { MetricsAndGroupByToolbarItems } from '../shared/compontents/metrics_and_groupby_toolbar_items'; +import { ToolbarProps } from '../../../public/pages/metrics/inventory_view/components/toolbars/toolbar'; +import { MetricsAndGroupByToolbarItems } from '../shared/components/metrics_and_groupby_toolbar_items'; import { SnapshotMetricType } from '../types'; export const ContainerToolbarItems = (props: ToolbarProps) => { diff --git a/x-pack/plugins/infra/common/inventory_models/host/layout.tsx b/x-pack/plugins/infra/common/inventory_models/host/layout.tsx index 6d7d3612542208..e23118c747a9ba 100644 --- a/x-pack/plugins/infra/common/inventory_models/host/layout.tsx +++ b/x-pack/plugins/infra/common/inventory_models/host/layout.tsx @@ -8,21 +8,21 @@ import { i18n } from '@kbn/i18n'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { withTheme } from '../../../../observability/public'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { LayoutPropsWithTheme } from '../../../public/pages/metrics/types'; +import { LayoutPropsWithTheme } from '../../../public/pages/metrics/metric_detail/types'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { Section } from '../../../public/pages/metrics/components/section'; +import { Section } from '../../../public/pages/metrics/metric_detail/components/section'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { SubSection } from '../../../public/pages/metrics/components/sub_section'; +import { SubSection } from '../../../public/pages/metrics/metric_detail/components/sub_section'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { GaugesSectionVis } from '../../../public/pages/metrics/components/gauges_section_vis'; +import { GaugesSectionVis } from '../../../public/pages/metrics/metric_detail/components/gauges_section_vis'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ChartSectionVis } from '../../../public/pages/metrics/components/chart_section_vis'; +import { ChartSectionVis } from '../../../public/pages/metrics/metric_detail/components/chart_section_vis'; import * as Aws from '../shared/layouts/aws'; import * as Ngnix from '../shared/layouts/nginx'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { MetadataDetails } from '../../../public/pages/metrics/components/metadata_details'; +import { MetadataDetails } from '../../../public/pages/metrics/metric_detail/components/metadata_details'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { LayoutContent } from '../../../public/pages/metrics/components/layout_content'; +import { LayoutContent } from '../../../public/pages/metrics/metric_detail/components/layout_content'; export const Layout = withTheme(({ metrics, onChangeRangeTime, theme }: LayoutPropsWithTheme) => ( diff --git a/x-pack/plugins/infra/common/inventory_models/host/toolbar_items.tsx b/x-pack/plugins/infra/common/inventory_models/host/toolbar_items.tsx index fc7696ee53c9d6..136264c0e26f4d 100644 --- a/x-pack/plugins/infra/common/inventory_models/host/toolbar_items.tsx +++ b/x-pack/plugins/infra/common/inventory_models/host/toolbar_items.tsx @@ -6,8 +6,8 @@ import React from 'react'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ToolbarProps } from '../../../public/components/inventory/toolbars/toolbar'; -import { MetricsAndGroupByToolbarItems } from '../shared/compontents/metrics_and_groupby_toolbar_items'; +import { ToolbarProps } from '../../../public/pages/metrics/inventory_view/components/toolbars/toolbar'; +import { MetricsAndGroupByToolbarItems } from '../shared/components/metrics_and_groupby_toolbar_items'; import { SnapshotMetricType } from '../types'; export const HostToolbarItems = (props: ToolbarProps) => { diff --git a/x-pack/plugins/infra/common/inventory_models/layouts.ts b/x-pack/plugins/infra/common/inventory_models/layouts.ts index b59ce010361ecd..df82f154b47b3b 100644 --- a/x-pack/plugins/infra/common/inventory_models/layouts.ts +++ b/x-pack/plugins/infra/common/inventory_models/layouts.ts @@ -23,7 +23,7 @@ import { Layout as AwsRDSLayout } from './aws_rds/layout'; import { Layout as AwsSQSLayout } from './aws_sqs/layout'; import { InventoryItemType } from './types'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { LayoutProps } from '../../public/pages/metrics/types'; +import { LayoutProps } from '../../public/pages/metrics/metric_detail/types'; interface Layouts { [type: string]: ReactNode; diff --git a/x-pack/plugins/infra/common/inventory_models/pod/layout.tsx b/x-pack/plugins/infra/common/inventory_models/pod/layout.tsx index 8bc2f3ee8b4b31..271e32556ae286 100644 --- a/x-pack/plugins/infra/common/inventory_models/pod/layout.tsx +++ b/x-pack/plugins/infra/common/inventory_models/pod/layout.tsx @@ -6,22 +6,22 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { LayoutPropsWithTheme } from '../../../public/pages/metrics/types'; +import { LayoutPropsWithTheme } from '../../../public/pages/metrics/metric_detail/types'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { Section } from '../../../public/pages/metrics/components/section'; +import { Section } from '../../../public/pages/metrics/metric_detail/components/section'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { SubSection } from '../../../public/pages/metrics/components/sub_section'; +import { SubSection } from '../../../public/pages/metrics/metric_detail/components/sub_section'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { GaugesSectionVis } from '../../../public/pages/metrics/components/gauges_section_vis'; +import { GaugesSectionVis } from '../../../public/pages/metrics/metric_detail/components/gauges_section_vis'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ChartSectionVis } from '../../../public/pages/metrics/components/chart_section_vis'; +import { ChartSectionVis } from '../../../public/pages/metrics/metric_detail/components/chart_section_vis'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { withTheme } from '../../../../observability/public'; import * as Nginx from '../shared/layouts/nginx'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { MetadataDetails } from '../../../public/pages/metrics/components/metadata_details'; +import { MetadataDetails } from '../../../public/pages/metrics/metric_detail/components/metadata_details'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { LayoutContent } from '../../../public/pages/metrics/components/layout_content'; +import { LayoutContent } from '../../../public/pages/metrics/metric_detail/components/layout_content'; export const Layout = withTheme(({ metrics, onChangeRangeTime, theme }: LayoutPropsWithTheme) => ( diff --git a/x-pack/plugins/infra/common/inventory_models/pod/toolbar_items.tsx b/x-pack/plugins/infra/common/inventory_models/pod/toolbar_items.tsx index d48c27efd88fda..c1cd375ff47bf9 100644 --- a/x-pack/plugins/infra/common/inventory_models/pod/toolbar_items.tsx +++ b/x-pack/plugins/infra/common/inventory_models/pod/toolbar_items.tsx @@ -6,8 +6,8 @@ import React from 'react'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ToolbarProps } from '../../../public/components/inventory/toolbars/toolbar'; -import { MetricsAndGroupByToolbarItems } from '../shared/compontents/metrics_and_groupby_toolbar_items'; +import { ToolbarProps } from '../../../public/pages/metrics/inventory_view/components/toolbars/toolbar'; +import { MetricsAndGroupByToolbarItems } from '../shared/components/metrics_and_groupby_toolbar_items'; import { SnapshotMetricType } from '../types'; export const PodToolbarItems = (props: ToolbarProps) => { diff --git a/x-pack/plugins/infra/common/inventory_models/shared/compontents/cloud_toolbar_items.tsx b/x-pack/plugins/infra/common/inventory_models/shared/components/cloud_toolbar_items.tsx similarity index 75% rename from x-pack/plugins/infra/common/inventory_models/shared/compontents/cloud_toolbar_items.tsx rename to x-pack/plugins/infra/common/inventory_models/shared/components/cloud_toolbar_items.tsx index 766a8ae8142f57..da5017b0f3a36f 100644 --- a/x-pack/plugins/infra/common/inventory_models/shared/compontents/cloud_toolbar_items.tsx +++ b/x-pack/plugins/infra/common/inventory_models/shared/components/cloud_toolbar_items.tsx @@ -7,11 +7,11 @@ import React from 'react'; import { EuiFlexItem } from '@elastic/eui'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ToolbarProps } from '../../../../public/components/inventory/toolbars/toolbar'; +import { ToolbarProps } from '../../../../public/pages/metrics/inventory_view/components/toolbars/toolbar'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { WaffleAccountsControls } from '../../../../public/components/waffle/waffle_accounts_controls'; +import { WaffleAccountsControls } from '../../../../public/pages/metrics/inventory_view/components/waffle/waffle_accounts_controls'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { WaffleRegionControls } from '../../../../public/components/waffle/waffle_region_controls'; +import { WaffleRegionControls } from '../../../../public/pages/metrics/inventory_view/components/waffle/waffle_region_controls'; type Props = ToolbarProps; diff --git a/x-pack/plugins/infra/common/inventory_models/shared/compontents/metrics_and_groupby_toolbar_items.tsx b/x-pack/plugins/infra/common/inventory_models/shared/components/metrics_and_groupby_toolbar_items.tsx similarity index 81% rename from x-pack/plugins/infra/common/inventory_models/shared/compontents/metrics_and_groupby_toolbar_items.tsx rename to x-pack/plugins/infra/common/inventory_models/shared/components/metrics_and_groupby_toolbar_items.tsx index 738fce45ee99f1..bf37828ed0856f 100644 --- a/x-pack/plugins/infra/common/inventory_models/shared/compontents/metrics_and_groupby_toolbar_items.tsx +++ b/x-pack/plugins/infra/common/inventory_models/shared/components/metrics_and_groupby_toolbar_items.tsx @@ -7,16 +7,16 @@ import React, { useMemo } from 'react'; import { EuiFlexItem } from '@elastic/eui'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ToolbarProps } from '../../../../public/components/inventory/toolbars/toolbar'; +import { ToolbarProps } from '../../../../public/pages/metrics/inventory_view/components/toolbars/toolbar'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { WaffleMetricControls } from '../../../../public/components/waffle/metric_control'; +import { WaffleMetricControls } from '../../../../public/pages/metrics/inventory_view/components/waffle/metric_control'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { WaffleGroupByControls } from '../../../../public/components/waffle/waffle_group_by_controls'; +import { WaffleGroupByControls } from '../../../../public/pages/metrics/inventory_view/components/waffle/waffle_group_by_controls'; import { toGroupByOpt, toMetricOpt, // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../public/components/inventory/toolbars/toolbar_wrapper'; +} from '../../../../public/pages/metrics/inventory_view/components/toolbars/toolbar_wrapper'; import { SnapshotMetricType } from '../../types'; interface Props extends ToolbarProps { diff --git a/x-pack/plugins/infra/common/inventory_models/shared/layouts/aws.tsx b/x-pack/plugins/infra/common/inventory_models/shared/layouts/aws.tsx index 7a0b898d406ce7..6f2791534c17e8 100644 --- a/x-pack/plugins/infra/common/inventory_models/shared/layouts/aws.tsx +++ b/x-pack/plugins/infra/common/inventory_models/shared/layouts/aws.tsx @@ -6,15 +6,15 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { LayoutPropsWithTheme } from '../../../../public/pages/metrics/types'; +import { LayoutPropsWithTheme } from '../../../../public/pages/metrics/metric_detail/types'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { Section } from '../../../../public/pages/metrics/components/section'; +import { Section } from '../../../../public/pages/metrics/metric_detail/components/section'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { SubSection } from '../../../../public/pages/metrics/components/sub_section'; +import { SubSection } from '../../../../public/pages/metrics/metric_detail/components/sub_section'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { GaugesSectionVis } from '../../../../public/pages/metrics/components/gauges_section_vis'; +import { GaugesSectionVis } from '../../../../public/pages/metrics/metric_detail/components/gauges_section_vis'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ChartSectionVis } from '../../../../public/pages/metrics/components/chart_section_vis'; +import { ChartSectionVis } from '../../../../public/pages/metrics/metric_detail/components/chart_section_vis'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { withTheme } from '../../../../../observability/public'; diff --git a/x-pack/plugins/infra/common/inventory_models/shared/layouts/nginx.tsx b/x-pack/plugins/infra/common/inventory_models/shared/layouts/nginx.tsx index 79cea5150d498d..cf3a06994cc96c 100644 --- a/x-pack/plugins/infra/common/inventory_models/shared/layouts/nginx.tsx +++ b/x-pack/plugins/infra/common/inventory_models/shared/layouts/nginx.tsx @@ -6,13 +6,13 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { LayoutPropsWithTheme } from '../../../../public/pages/metrics/types'; +import { LayoutPropsWithTheme } from '../../../../public/pages/metrics/metric_detail/types'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { Section } from '../../../../public/pages/metrics/components/section'; +import { Section } from '../../../../public/pages/metrics/metric_detail/components/section'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { SubSection } from '../../../../public/pages/metrics/components/sub_section'; +import { SubSection } from '../../../../public/pages/metrics/metric_detail/components/sub_section'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ChartSectionVis } from '../../../../public/pages/metrics/components/chart_section_vis'; +import { ChartSectionVis } from '../../../../public/pages/metrics/metric_detail/components/chart_section_vis'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { withTheme } from '../../../../../observability/public'; diff --git a/x-pack/plugins/infra/common/inventory_models/toolbars.ts b/x-pack/plugins/infra/common/inventory_models/toolbars.ts index 39e9f5a260f7a9..e00cb094d04550 100644 --- a/x-pack/plugins/infra/common/inventory_models/toolbars.ts +++ b/x-pack/plugins/infra/common/inventory_models/toolbars.ts @@ -11,7 +11,7 @@ import { HostToolbarItems } from './host/toolbar_items'; import { ContainerToolbarItems } from './container/toolbar_items'; import { PodToolbarItems } from './pod/toolbar_items'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ToolbarProps } from '../../public/components/inventory/toolbars/toolbar'; +import { ToolbarProps } from '../../public/pages/metrics/inventory_view/components/toolbars/toolbar'; import { AwsEC2ToolbarItems } from './aws_ec2/toolbar_items'; import { AwsS3ToolbarItems } from './aws_s3/toolbar_items'; import { AwsRDSToolbarItems } from './aws_rds/toolbar_items'; diff --git a/x-pack/plugins/infra/common/saved_objects/inventory_view.ts b/x-pack/plugins/infra/common/saved_objects/inventory_view.ts index 8ae765f379add1..8933de57b04485 100644 --- a/x-pack/plugins/infra/common/saved_objects/inventory_view.ts +++ b/x-pack/plugins/infra/common/saved_objects/inventory_view.ts @@ -7,7 +7,7 @@ // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { ElasticsearchMappingOf } from '../../server/utils/typed_elasticsearch_mappings'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { WaffleViewState } from '../../public/pages/inventory_view/hooks/use_waffle_view_state'; +import { WaffleViewState } from '../../public/pages/metrics/inventory_view/hooks/use_waffle_view_state'; export const inventoryViewSavedObjectType = 'inventory-view'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths diff --git a/x-pack/plugins/infra/common/saved_objects/metrics_explorer_view.ts b/x-pack/plugins/infra/common/saved_objects/metrics_explorer_view.ts index a9f11948446408..6eb08eabc15b5d 100644 --- a/x-pack/plugins/infra/common/saved_objects/metrics_explorer_view.ts +++ b/x-pack/plugins/infra/common/saved_objects/metrics_explorer_view.ts @@ -11,7 +11,7 @@ import { MetricsExplorerChartOptions, MetricsExplorerTimeOptions, // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../public/containers/metrics_explorer/use_metrics_explorer_options'; +} from '../../public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { SavedViewSavedObject } from '../../public/hooks/use_saved_view'; diff --git a/x-pack/plugins/infra/public/components/alerting/metrics/alert_flyout.tsx b/x-pack/plugins/infra/public/components/alerting/metrics/alert_flyout.tsx index 914054e1fd9b7e..38709c117c8176 100644 --- a/x-pack/plugins/infra/public/components/alerting/metrics/alert_flyout.tsx +++ b/x-pack/plugins/infra/public/components/alerting/metrics/alert_flyout.tsx @@ -10,8 +10,8 @@ import { TriggerActionsContext } from '../../../utils/triggers_actions_context'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { METRIC_THRESHOLD_ALERT_TYPE_ID } from '../../../../server/lib/alerting/metric_threshold/types'; -import { MetricsExplorerOptions } from '../../../containers/metrics_explorer/use_metrics_explorer_options'; import { MetricsExplorerSeries } from '../../../../common/http_api/metrics_explorer'; +import { MetricsExplorerOptions } from '../../../pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options'; interface Props { visible?: boolean; diff --git a/x-pack/plugins/infra/public/components/alerting/metrics/expression.tsx b/x-pack/plugins/infra/public/components/alerting/metrics/expression.tsx index 7de52840777f9c..665da25dcbfffd 100644 --- a/x-pack/plugins/infra/public/components/alerting/metrics/expression.tsx +++ b/x-pack/plugins/infra/public/components/alerting/metrics/expression.tsx @@ -17,9 +17,6 @@ import { import { IFieldType } from 'src/plugins/data/public'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import { EuiExpression } from '@elastic/eui'; -import { EuiCallOut } from '@elastic/eui'; -import { EuiLink } from '@elastic/eui'; import { MetricExpressionParams, Comparator, @@ -38,11 +35,11 @@ import { IErrorObject } from '../../../../../triggers_actions_ui/public/types'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { AlertsContextValue } from '../../../../../triggers_actions_ui/public/application/context/alerts_context'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { MetricsExplorerOptions } from '../../../containers/metrics_explorer/use_metrics_explorer_options'; -import { MetricsExplorerKueryBar } from '../../metrics_explorer/kuery_bar'; import { MetricsExplorerSeries } from '../../../../common/http_api/metrics_explorer'; -import { useSource } from '../../../containers/source'; -import { MetricsExplorerGroupBy } from '../../metrics_explorer/group_by'; +import { MetricsExplorerKueryBar } from '../../../pages/metrics/metrics_explorer/components/kuery_bar'; +import { MetricsExplorerOptions } from '../../../pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options'; +import { MetricsExplorerGroupBy } from '../../../pages/metrics/metrics_explorer/components/group_by'; +import { useSourceViaHttp } from '../../../containers/source/use_source_via_http'; interface AlertContextMeta { currentOptions?: Partial; @@ -87,7 +84,12 @@ const defaultExpression = { export const Expressions: React.FC = props => { const { setAlertParams, alertParams, errors, alertsContext } = props; - const { source, createDerivedIndexPattern } = useSource({ sourceId: 'default' }); + const { source, createDerivedIndexPattern } = useSourceViaHttp({ + sourceId: 'default', + type: 'metrics', + fetch: alertsContext.http.fetch, + toastWarning: alertsContext.toastNotifications.addWarning, + }); const [timeSize, setTimeSize] = useState(1); const [timeUnit, setTimeUnit] = useState('m'); @@ -208,40 +210,11 @@ export const Expressions: React.FC = props => { setAlertParams('groupBy', md.currentOptions.groupBy); } setAlertParams('sourceId', source?.id); + } else { + setAlertParams('criteria', [defaultExpression]); } }, [alertsContext.metadata, defaultExpression, source]); // eslint-disable-line react-hooks/exhaustive-deps - // INFO: If there is metadata, you're in the metrics explorer context - const canAddConditions = !!alertsContext.metadata; - - if (!canAddConditions && !alertParams.criteria) { - return ( - <> - - - {' '} - - - - . - - } - color="warning" - iconType="help" - /> - - - ); - } - return ( <> @@ -258,7 +231,6 @@ export const Expressions: React.FC = props => { alertParams.criteria.map((e, idx) => { return ( 1} fields={derivedIndexPattern.fields} remove={removeExpression} @@ -281,20 +253,18 @@ export const Expressions: React.FC = props => { />
- {canAddConditions && ( - - - - )} + + +
@@ -347,7 +317,6 @@ export const Expressions: React.FC = props => { interface ExpressionRowProps { fields: IFieldType[]; - canEditAggField: boolean; expressionId: number; expression: MetricExpression; errors: IErrorObject; @@ -378,7 +347,11 @@ export const ExpressionRow: React.FC = props => { const updateAggType = useCallback( (at: string) => { - setAlertParams(expressionId, { ...expression, aggType: at as MetricExpression['aggType'] }); + setAlertParams(expressionId, { + ...expression, + aggType: at as MetricExpression['aggType'], + metric: at === 'count' ? undefined : expression.metric, + }); }, [expressionId, expression, setAlertParams] ); @@ -420,20 +393,17 @@ export const ExpressionRow: React.FC = props => { {aggType !== 'count' && ( - {!props.canEditAggField && } - {props.canEditAggField && ( - ({ - normalizedType: f.type, - name: f.name, - }))} - aggType={aggType} - errors={errors} - onChangeSelectedAggField={updateMetric} - /> - )} + ({ + normalizedType: f.type, + name: f.name, + }))} + aggType={aggType} + errors={errors} + onChangeSelectedAggField={updateMetric} + /> )} @@ -465,19 +435,6 @@ export const ExpressionRow: React.FC = props => { ); }; -export const DisabledAggField = ({ text }: { text: string }) => { - return ( - - ); -}; - export const aggregationType: { [key: string]: any } = { avg: { text: i18n.translate('xpack.infra.metrics.alertFlyout.aggregationText.avg', { diff --git a/x-pack/plugins/infra/public/components/waffle/lib/type_guards.ts b/x-pack/plugins/infra/public/components/waffle/lib/type_guards.ts deleted file mode 100644 index f793afee1b948b..00000000000000 --- a/x-pack/plugins/infra/public/components/waffle/lib/type_guards.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { InfraWaffleMapGradientLegend, InfraWaffleMapStepLegend } from '../../../lib/lib'; - -export function isInfraWaffleMapStepLegend(subject: any): subject is InfraWaffleMapStepLegend { - return subject.type && subject.type === 'step'; -} - -export function isInfraWaffleMapGradientLegend( - subject: any -): subject is InfraWaffleMapGradientLegend { - return subject.type && subject.type === 'gradient'; -} diff --git a/x-pack/plugins/infra/public/containers/metrics_explorer/with_metrics_explorer_options_url_state.tsx b/x-pack/plugins/infra/public/containers/metrics_explorer/with_metrics_explorer_options_url_state.tsx index d2fa49e8d5d9fc..04f518aa9080fe 100644 --- a/x-pack/plugins/infra/public/containers/metrics_explorer/with_metrics_explorer_options_url_state.tsx +++ b/x-pack/plugins/infra/public/containers/metrics_explorer/with_metrics_explorer_options_url_state.tsx @@ -17,7 +17,7 @@ import { MetricsExplorerYAxisMode, MetricsExplorerChartType, MetricsExplorerChartOptions, -} from './use_metrics_explorer_options'; +} from '../../pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options'; interface MetricsExplorerUrlState { timerange?: MetricsExplorerTimeOptions; diff --git a/x-pack/plugins/infra/public/containers/source/source.tsx b/x-pack/plugins/infra/public/containers/source/source.tsx index a1310b1f336140..c2206769ef0efd 100644 --- a/x-pack/plugins/infra/public/containers/source/source.tsx +++ b/x-pack/plugins/infra/public/containers/source/source.tsx @@ -21,7 +21,7 @@ import { updateSourceMutation } from './update_source.gql_query'; type Source = SourceQuery.Query['source']; -const pickIndexPattern = (source: Source | undefined, type: 'logs' | 'metrics' | 'both') => { +export const pickIndexPattern = (source: Source | undefined, type: 'logs' | 'metrics' | 'both') => { if (!source) { return 'unknown-index'; } diff --git a/x-pack/plugins/infra/public/containers/source/use_source_via_http.ts b/x-pack/plugins/infra/public/containers/source/use_source_via_http.ts new file mode 100644 index 00000000000000..bc6374a6538e37 --- /dev/null +++ b/x-pack/plugins/infra/public/containers/source/use_source_via_http.ts @@ -0,0 +1,92 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { useEffect, useMemo } from 'react'; +import { fold } from 'fp-ts/lib/Either'; +import { identity } from 'fp-ts/lib/function'; +import { pipe } from 'fp-ts/lib/pipeable'; +import createContainer from 'constate'; +import { HttpHandler } from 'target/types/core/public/http'; +import { ToastInput } from 'target/types/core/public/notifications/toasts/toasts_api'; +import { + SourceResponseRuntimeType, + SourceResponse, + InfraSource, +} from '../../../common/http_api/source_api'; +import { useHTTPRequest } from '../../hooks/use_http_request'; +import { throwErrors, createPlainError } from '../../../common/runtime_types'; + +export const pickIndexPattern = ( + source: InfraSource | undefined, + type: 'logs' | 'metrics' | 'both' +) => { + if (!source) { + return 'unknown-index'; + } + if (type === 'logs') { + return source.configuration.logAlias; + } + if (type === 'metrics') { + return source.configuration.metricAlias; + } + return `${source.configuration.logAlias},${source.configuration.metricAlias}`; +}; + +interface Props { + sourceId: string; + type: 'logs' | 'metrics' | 'both'; + fetch?: HttpHandler; + toastWarning?: (input: ToastInput) => void; +} + +export const useSourceViaHttp = ({ + sourceId = 'default', + type = 'both', + fetch, + toastWarning, +}: Props) => { + const decodeResponse = (response: any) => { + return pipe( + SourceResponseRuntimeType.decode(response), + fold(throwErrors(createPlainError), identity) + ); + }; + + const { error, loading, response, makeRequest } = useHTTPRequest( + `/api/metrics/source/${sourceId}/${type}`, + 'GET', + null, + decodeResponse, + fetch, + toastWarning + ); + + useEffect(() => { + (async () => { + await makeRequest(); + })(); + }, [makeRequest]); + + const createDerivedIndexPattern = (indexType: 'logs' | 'metrics' | 'both' = type) => { + return { + fields: response?.source ? response.status.indexFields : [], + title: pickIndexPattern(response?.source, indexType), + }; + }; + + const source = useMemo(() => { + return response ? { ...response.source, status: response.status } : null; + }, [response]); + + return { + createDerivedIndexPattern, + source, + loading, + error, + }; +}; + +export const SourceViaHttp = createContainer(useSourceViaHttp); +export const [SourceViaHttpProvider, useSourceViaHttpContext] = SourceViaHttp; diff --git a/x-pack/plugins/infra/public/containers/with_options.tsx b/x-pack/plugins/infra/public/containers/with_options.tsx deleted file mode 100644 index e18fc85a68d60b..00000000000000 --- a/x-pack/plugins/infra/public/containers/with_options.tsx +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import moment from 'moment'; -import React from 'react'; - -import { euiPaletteColorBlind } from '@elastic/eui'; -import { InfraFormatterType, InfraOptions } from '../lib/lib'; -import { RendererFunction } from '../utils/typed_react'; - -const euiVisColorPalette = euiPaletteColorBlind(); - -const initialState = { - options: { - timerange: { - interval: '1m', - to: moment.utc().valueOf(), - from: moment - .utc() - .subtract(1, 'h') - .valueOf(), - }, - wafflemap: { - formatter: InfraFormatterType.percent, - formatTemplate: '{{value}}', - metric: { type: 'cpu' }, - groupBy: [], - legend: { - type: 'gradient', - rules: [ - { - value: 0, - color: '#D3DAE6', - }, - { - value: 1, - color: euiVisColorPalette[1], - }, - ], - }, - }, - } as InfraOptions, -}; - -interface WithOptionsProps { - children: RendererFunction; -} - -type State = Readonly; - -export const withOptions = (WrappedComponent: React.ComponentType) => ( - {args => } -); - -export class WithOptions extends React.Component { - public readonly state: State = initialState; - - public render() { - return this.props.children(this.state.options); - } -} diff --git a/x-pack/plugins/infra/public/hooks/use_http_request.tsx b/x-pack/plugins/infra/public/hooks/use_http_request.tsx index 50f4a636b48a35..e00abe6380498f 100644 --- a/x-pack/plugins/infra/public/hooks/use_http_request.tsx +++ b/x-pack/plugins/infra/public/hooks/use_http_request.tsx @@ -7,28 +7,32 @@ import React, { useMemo, useState } from 'react'; import { IHttpFetchError } from 'src/core/public'; import { i18n } from '@kbn/i18n'; +import { HttpHandler } from 'target/types/core/public/http'; +import { ToastInput } from 'target/types/core/public/notifications/toasts/toasts_api'; import { useTrackedPromise } from '../utils/use_tracked_promise'; import { useKibana } from '../../../../../src/plugins/kibana_react/public'; export function useHTTPRequest( pathname: string, method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'HEAD', - body?: string, - decode: (response: any) => Response = response => response + body?: string | null, + decode: (response: any) => Response = response => response, + fetch?: HttpHandler, + toastWarning?: (input: ToastInput) => void ) { const kibana = useKibana(); - const fetch = kibana.services.http?.fetch; - const toasts = kibana.notifications.toasts; + const fetchService = fetch ? fetch : kibana.services.http?.fetch; + const toast = toastWarning ? toastWarning : kibana.notifications.toasts.warning; const [response, setResponse] = useState(null); const [error, setError] = useState(null); const [request, makeRequest] = useTrackedPromise( { cancelPreviousOn: 'resolution', createPromise: () => { - if (!fetch) { + if (!fetchService) { throw new Error('HTTP service is unavailable'); } - return fetch(pathname, { + return fetchService(pathname, { method, body, }); @@ -37,7 +41,7 @@ export function useHTTPRequest( onReject: (e: unknown) => { const err = e as IHttpFetchError; setError(err); - toasts.warning({ + toast({ toastLifeTimeMs: 3000, title: i18n.translate('xpack.infra.useHTTPRequest.error.title', { defaultMessage: `Error while fetching resource`, @@ -67,7 +71,7 @@ export function useHTTPRequest( }); }, }, - [pathname, body, method, fetch, toasts] + [pathname, body, method, fetch, toast] ); const loading = useMemo(() => { diff --git a/x-pack/plugins/infra/public/pages/infrastructure/index.tsx b/x-pack/plugins/infra/public/pages/infrastructure/index.tsx deleted file mode 100644 index d592ae3480fc95..00000000000000 --- a/x-pack/plugins/infra/public/pages/infrastructure/index.tsx +++ /dev/null @@ -1,135 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; - -import React from 'react'; -import { Route, RouteComponentProps, Switch } from 'react-router-dom'; - -import { EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; -import { DocumentTitle } from '../../components/document_title'; -import { HelpCenterContent } from '../../components/help_center_content'; -import { RoutedTabs } from '../../components/navigation/routed_tabs'; -import { ColumnarPage } from '../../components/page'; -import { Header } from '../../components/header'; -import { MetricsExplorerOptionsContainer } from '../../containers/metrics_explorer/use_metrics_explorer_options'; -import { WithMetricsExplorerOptionsUrlState } from '../../containers/metrics_explorer/with_metrics_explorer_options_url_state'; -import { WithSource } from '../../containers/with_source'; -import { Source } from '../../containers/source'; -import { MetricsExplorerPage } from './metrics_explorer'; -import { SnapshotPage } from './snapshot'; -import { MetricsSettingsPage } from './settings'; -import { AppNavigation } from '../../components/navigation/app_navigation'; -import { SourceLoadingPage } from '../../components/source_loading_page'; -import { useKibana } from '../../../../../../src/plugins/kibana_react/public'; -import { WaffleOptionsProvider } from '../inventory_view/hooks/use_waffle_options'; -import { WaffleTimeProvider } from '../inventory_view/hooks/use_waffle_time'; -import { WaffleFiltersProvider } from '../inventory_view/hooks/use_waffle_filters'; -import { AlertDropdown } from '../../components/alerting/metrics/alert_dropdown'; - -export const InfrastructurePage = ({ match }: RouteComponentProps) => { - const uiCapabilities = useKibana().services.application?.capabilities; - - return ( - - - - - - - - - -
- - - - - - - - - - - - - - ( - - {({ configuration, createDerivedIndexPattern }) => ( - - - {configuration ? ( - - ) : ( - - )} - - )} - - )} - /> - - - - - - - - ); -}; diff --git a/x-pack/plugins/infra/public/pages/link_to/redirect_to_host_detail_via_ip.tsx b/x-pack/plugins/infra/public/pages/link_to/redirect_to_host_detail_via_ip.tsx index b1dab3bd3f6737..3ad242c77412db 100644 --- a/x-pack/plugins/infra/public/pages/link_to/redirect_to_host_detail_via_ip.tsx +++ b/x-pack/plugins/infra/public/pages/link_to/redirect_to_host_detail_via_ip.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { Redirect, RouteComponentProps } from 'react-router-dom'; import { i18n } from '@kbn/i18n'; -import { replaceMetricTimeInQueryString } from '../metrics/hooks/use_metrics_time'; +import { replaceMetricTimeInQueryString } from '../metrics/metric_detail/hooks/use_metrics_time'; import { useHostIpToName } from './use_host_ip_to_name'; import { getFromFromLocation, getToFromLocation } from './query_params'; import { LoadingPage } from '../../components/loading_page'; diff --git a/x-pack/plugins/infra/public/pages/link_to/redirect_to_node_detail.tsx b/x-pack/plugins/infra/public/pages/link_to/redirect_to_node_detail.tsx index 72a41f5264244f..3d25e4c6c258d3 100644 --- a/x-pack/plugins/infra/public/pages/link_to/redirect_to_node_detail.tsx +++ b/x-pack/plugins/infra/public/pages/link_to/redirect_to_node_detail.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { Redirect, RouteComponentProps } from 'react-router-dom'; -import { replaceMetricTimeInQueryString } from '../metrics/hooks/use_metrics_time'; +import { replaceMetricTimeInQueryString } from '../metrics/metric_detail/hooks/use_metrics_time'; import { getFromFromLocation, getToFromLocation } from './query_params'; import { InventoryItemType } from '../../../common/inventory_models/types'; import { LinkDescriptor } from '../../hooks/use_link_props'; diff --git a/x-pack/plugins/infra/public/pages/metrics/index.tsx b/x-pack/plugins/infra/public/pages/metrics/index.tsx index 531be40d2dc43b..cc88dd9e0d0f8f 100644 --- a/x-pack/plugins/infra/public/pages/metrics/index.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/index.tsx @@ -3,138 +3,133 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ + import { i18n } from '@kbn/i18n'; -import React, { useContext, useState } from 'react'; -import { euiStyled, EuiTheme, withTheme } from '../../../../observability/public'; + +import React from 'react'; +import { Route, RouteComponentProps, Switch } from 'react-router-dom'; + +import { EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; import { DocumentTitle } from '../../components/document_title'; +import { HelpCenterContent } from '../../components/help_center_content'; +import { RoutedTabs } from '../../components/navigation/routed_tabs'; +import { ColumnarPage } from '../../components/page'; import { Header } from '../../components/header'; -import { ColumnarPage, PageContent } from '../../components/page'; -import { withMetricPageProviders } from './page_providers'; -import { useMetadata } from '../../containers/metadata/use_metadata'; +import { MetricsExplorerOptionsContainer } from './metrics_explorer/hooks/use_metrics_explorer_options'; +import { WithMetricsExplorerOptionsUrlState } from '../../containers/metrics_explorer/with_metrics_explorer_options_url_state'; +import { WithSource } from '../../containers/with_source'; import { Source } from '../../containers/source'; -import { InfraLoadingPanel } from '../../components/loading'; -import { findInventoryModel } from '../../../common/inventory_models'; -import { NavItem } from './lib/side_nav_context'; -import { NodeDetailsPage } from './components/node_details_page'; +import { MetricsExplorerPage } from './metrics_explorer'; +import { SnapshotPage } from './inventory_view'; +import { MetricsSettingsPage } from './settings'; +import { AppNavigation } from '../../components/navigation/app_navigation'; +import { SourceLoadingPage } from '../../components/source_loading_page'; import { useKibana } from '../../../../../../src/plugins/kibana_react/public'; -import { InventoryItemType } from '../../../common/inventory_models/types'; -import { useMetricsTimeContext } from './hooks/use_metrics_time'; -import { useLinkProps } from '../../hooks/use_link_props'; - -const DetailPageContent = euiStyled(PageContent)` - overflow: auto; - background-color: ${props => props.theme.eui.euiColorLightestShade}; -`; - -interface Props { - theme: EuiTheme; - match: { - params: { - type: string; - node: string; - }; - }; -} - -export const MetricDetail = withMetricPageProviders( - withTheme(({ match }: Props) => { - const uiCapabilities = useKibana().services.application?.capabilities; - const nodeId = match.params.node; - const nodeType = match.params.type as InventoryItemType; - const inventoryModel = findInventoryModel(nodeType); - const { sourceId } = useContext(Source.Context); - const { - timeRange, - parsedTimeRange, - setTimeRange, - refreshInterval, - setRefreshInterval, - isAutoReloading, - setAutoReload, - triggerRefresh, - } = useMetricsTimeContext(); - const { - name, - filteredRequiredMetrics, - loading: metadataLoading, - cloudId, - metadata, - } = useMetadata(nodeId, nodeType, inventoryModel.requiredMetrics, sourceId, parsedTimeRange); - - const [sideNav, setSideNav] = useState([]); +import { WaffleOptionsProvider } from './inventory_view/hooks/use_waffle_options'; +import { WaffleTimeProvider } from './inventory_view/hooks/use_waffle_time'; +import { WaffleFiltersProvider } from './inventory_view/hooks/use_waffle_filters'; +import { AlertDropdown } from '../../components/alerting/metrics/alert_dropdown'; - const addNavItem = React.useCallback( - (item: NavItem) => { - if (!sideNav.some(n => n.id === item.id)) { - setSideNav([item, ...sideNav]); - } - }, - [sideNav] - ); +export const InfrastructurePage = ({ match }: RouteComponentProps) => { + const uiCapabilities = useKibana().services.application?.capabilities; - const metricsLinkProps = useLinkProps({ - app: 'metrics', - pathname: '/', - }); + return ( + + + + + + - const breadcrumbs = [ - { - ...metricsLinkProps, - text: i18n.translate('xpack.infra.header.infrastructureTitle', { - defaultMessage: 'Metrics', - }), - }, - { text: name }, - ]; + - if (metadataLoading && !filteredRequiredMetrics.length) { - return ( - - ); - } +
+ + + + + + + + + + - return ( - -
- - - {metadata ? ( - - ) : null} - - - ); - }) -); + + + ( + + {({ configuration, createDerivedIndexPattern }) => ( + + + {configuration ? ( + + ) : ( + + )} + + )} + + )} + /> + + + + + + + + ); +}; diff --git a/x-pack/plugins/infra/public/components/inventory/layout.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/layout.tsx similarity index 78% rename from x-pack/plugins/infra/public/components/inventory/layout.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/layout.tsx index 3c91f9fa5946fc..bc8be9862fe636 100644 --- a/x-pack/plugins/infra/public/components/inventory/layout.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/layout.tsx @@ -8,16 +8,16 @@ import React from 'react'; import { useInterval } from 'react-use'; import { euiPaletteColorBlind } from '@elastic/eui'; -import { NodesOverview } from '../nodes_overview'; +import { NodesOverview } from './nodes_overview'; import { Toolbar } from './toolbars/toolbar'; -import { PageContent } from '../page'; -import { useSnapshot } from '../../containers/waffle/use_snaphot'; -import { useInventoryMeta } from '../../containers/inventory_metadata/use_inventory_meta'; -import { useWaffleTimeContext } from '../../pages/inventory_view/hooks/use_waffle_time'; -import { useWaffleFiltersContext } from '../../pages/inventory_view/hooks/use_waffle_filters'; -import { useWaffleOptionsContext } from '../../pages/inventory_view/hooks/use_waffle_options'; -import { useSourceContext } from '../../containers/source'; -import { InfraFormatterType, InfraWaffleMapGradientLegend } from '../../lib/lib'; +import { PageContent } from '../../../../components/page'; +import { useSnapshot } from '../hooks/use_snaphot'; +import { useInventoryMeta } from '../hooks/use_inventory_meta'; +import { useWaffleTimeContext } from '../hooks/use_waffle_time'; +import { useWaffleFiltersContext } from '../hooks/use_waffle_filters'; +import { useWaffleOptionsContext } from '../hooks/use_waffle_options'; +import { useSourceContext } from '../../../../containers/source'; +import { InfraFormatterType, InfraWaffleMapGradientLegend } from '../../../../lib/lib'; const euiVisColorPalette = euiPaletteColorBlind(); diff --git a/x-pack/plugins/infra/public/components/nodes_overview/index.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/nodes_overview.tsx similarity index 88% rename from x-pack/plugins/infra/public/components/nodes_overview/index.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/nodes_overview.tsx index ef22e0486f8921..afbfd2a079253d 100644 --- a/x-pack/plugins/infra/public/components/nodes_overview/index.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/nodes_overview.tsx @@ -10,18 +10,25 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { get, max, min } from 'lodash'; import React from 'react'; -import { euiStyled } from '../../../../observability/public'; -import { InfraFormatterType, InfraWaffleMapBounds, InfraWaffleMapOptions } from '../../lib/lib'; -import { createFormatter } from '../../utils/formatters'; -import { NoData } from '../empty_states'; -import { InfraLoadingPanel } from '../loading'; -import { Map } from '../waffle/map'; -import { ViewSwitcher } from '../waffle/view_switcher'; -import { TableView } from './table'; -import { SnapshotNode, SnapshotCustomMetricInputRT } from '../../../common/http_api/snapshot_api'; -import { convertIntervalToString } from '../../utils/convert_interval_to_string'; -import { InventoryItemType } from '../../../common/inventory_models/types'; -import { createFormatterForMetric } from '../metrics_explorer/helpers/create_formatter_for_metric'; +import { euiStyled } from '../../../../../../observability/public'; +import { + InfraFormatterType, + InfraWaffleMapBounds, + InfraWaffleMapOptions, +} from '../../../../lib/lib'; +import { createFormatter } from '../../../../utils/formatters'; +import { NoData } from '../../../../components/empty_states'; +import { InfraLoadingPanel } from '../../../../components/loading'; +import { Map } from './waffle/map'; +import { ViewSwitcher } from './waffle/view_switcher'; +import { TableView } from './table_view'; +import { + SnapshotNode, + SnapshotCustomMetricInputRT, +} from '../../../../../common/http_api/snapshot_api'; +import { convertIntervalToString } from '../../../../utils/convert_interval_to_string'; +import { InventoryItemType } from '../../../../../common/inventory_models/types'; +import { createFormatterForMetric } from '../../metrics_explorer/components/helpers/create_formatter_for_metric'; export interface KueryFilterQuery { kind: 'kuery'; diff --git a/x-pack/plugins/infra/public/pages/inventory_view/compontents/search_bar.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/search_bar.tsx similarity index 86% rename from x-pack/plugins/infra/public/pages/inventory_view/compontents/search_bar.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/search_bar.tsx index f4fde46d434f83..1f84ef3685f342 100644 --- a/x-pack/plugins/infra/public/pages/inventory_view/compontents/search_bar.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/search_bar.tsx @@ -5,9 +5,9 @@ */ import React, { useContext } from 'react'; import { i18n } from '@kbn/i18n'; -import { Source } from '../../../containers/source'; -import { AutocompleteField } from '../../../components/autocomplete_field'; -import { WithKueryAutocompletion } from '../../../containers/with_kuery_autocompletion'; +import { Source } from '../../../../containers/source'; +import { AutocompleteField } from '../../../../components/autocomplete_field'; +import { WithKueryAutocompletion } from '../../../../containers/with_kuery_autocompletion'; import { useWaffleFiltersContext } from '../hooks/use_waffle_filters'; export const SearchBar = () => { diff --git a/x-pack/plugins/infra/public/components/nodes_overview/table.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/table_view.tsx similarity index 92% rename from x-pack/plugins/infra/public/components/nodes_overview/table.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/table_view.tsx index 82991076255eef..0557343e735f91 100644 --- a/x-pack/plugins/infra/public/components/nodes_overview/table.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/table_view.tsx @@ -9,13 +9,13 @@ import { i18n } from '@kbn/i18n'; import { last } from 'lodash'; import React, { useState, useCallback, useEffect } from 'react'; -import { createWaffleMapNode } from '../../containers/waffle/nodes_to_wafflemap'; -import { InfraWaffleMapNode, InfraWaffleMapOptions } from '../../lib/lib'; -import { fieldToName } from '../waffle/lib/field_to_display_name'; -import { NodeContextMenu } from '../waffle/node_context_menu'; -import { InventoryItemType } from '../../../common/inventory_models/types'; -import { SnapshotNode, SnapshotNodePath } from '../../../common/http_api/snapshot_api'; -import { CONTAINER_CLASSNAME } from '../../apps/start_app'; +import { createWaffleMapNode } from '../lib/nodes_to_wafflemap'; +import { InfraWaffleMapNode, InfraWaffleMapOptions } from '../../../../lib/lib'; +import { fieldToName } from '../lib/field_to_display_name'; +import { NodeContextMenu } from './waffle/node_context_menu'; +import { InventoryItemType } from '../../../../../common/inventory_models/types'; +import { SnapshotNode, SnapshotNodePath } from '../../../../../common/http_api/snapshot_api'; +import { CONTAINER_CLASSNAME } from '../../../../apps/start_app'; interface Props { nodes: SnapshotNode[]; diff --git a/x-pack/plugins/infra/public/components/inventory/toolbars/save_views.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/toolbars/save_views.tsx similarity index 68% rename from x-pack/plugins/infra/public/components/inventory/toolbars/save_views.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/toolbars/save_views.tsx index cb315d3e17b032..eb40ea595662a2 100644 --- a/x-pack/plugins/infra/public/components/inventory/toolbars/save_views.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/toolbars/save_views.tsx @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ import React from 'react'; -import { SavedViewsToolbarControls } from '../../saved_views/toolbar_control'; -import { inventoryViewSavedObjectType } from '../../../../common/saved_objects/inventory_view'; -import { useWaffleViewState } from '../../../pages/inventory_view/hooks/use_waffle_view_state'; +import { SavedViewsToolbarControls } from '../../../../../components/saved_views/toolbar_control'; +import { inventoryViewSavedObjectType } from '../../../../../../common/saved_objects/inventory_view'; +import { useWaffleViewState } from '../../hooks/use_waffle_view_state'; export const SavedViews = () => { const { viewState, defaultViewState, onViewChange } = useWaffleViewState(); diff --git a/x-pack/plugins/infra/public/components/inventory/toolbars/toolbar.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/toolbars/toolbar.tsx similarity index 77% rename from x-pack/plugins/infra/public/components/inventory/toolbars/toolbar.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/toolbars/toolbar.tsx index 63ab6d2f4465a4..3ac9c2c1896286 100644 --- a/x-pack/plugins/infra/public/components/inventory/toolbars/toolbar.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/toolbars/toolbar.tsx @@ -10,15 +10,15 @@ import { SnapshotMetricInput, SnapshotGroupBy, SnapshotCustomMetricInput, -} from '../../../../common/http_api/snapshot_api'; -import { InventoryCloudAccount } from '../../../../common/http_api/inventory_meta_api'; -import { findToolbar } from '../../../../common/inventory_models/toolbars'; +} from '../../../../../../common/http_api/snapshot_api'; +import { InventoryCloudAccount } from '../../../../../../common/http_api/inventory_meta_api'; +import { findToolbar } from '../../../../../../common/inventory_models/toolbars'; import { ToolbarWrapper } from './toolbar_wrapper'; -import { InfraGroupByOptions } from '../../../lib/lib'; -import { IIndexPattern } from '../../../../../../../src/plugins/data/public'; -import { InventoryItemType } from '../../../../common/inventory_models/types'; -import { WaffleOptionsState } from '../../../pages/inventory_view/hooks/use_waffle_options'; +import { InfraGroupByOptions } from '../../../../../lib/lib'; +import { IIndexPattern } from '../../../../../../../../../src/plugins/data/public'; +import { InventoryItemType } from '../../../../../../common/inventory_models/types'; +import { WaffleOptionsState } from '../../hooks/use_waffle_options'; import { SavedViews } from './save_views'; export interface ToolbarProps diff --git a/x-pack/plugins/infra/public/components/inventory/toolbars/toolbar_wrapper.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/toolbars/toolbar_wrapper.tsx similarity index 95% rename from x-pack/plugins/infra/public/components/inventory/toolbars/toolbar_wrapper.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/toolbars/toolbar_wrapper.tsx index fefda94372cfb4..86cc0d8ee62e00 100644 --- a/x-pack/plugins/infra/public/components/inventory/toolbars/toolbar_wrapper.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/toolbars/toolbar_wrapper.tsx @@ -7,12 +7,12 @@ import React from 'react'; import { EuiFlexGroup } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { SnapshotMetricType } from '../../../../common/inventory_models/types'; -import { Toolbar } from '../../eui/toolbar'; +import { SnapshotMetricType } from '../../../../../../common/inventory_models/types'; +import { Toolbar } from '../../../../../components/eui/toolbar'; import { ToolbarProps } from './toolbar'; -import { fieldToName } from '../../waffle/lib/field_to_display_name'; -import { useSourceContext } from '../../../containers/source'; -import { useWaffleOptionsContext } from '../../../pages/inventory_view/hooks/use_waffle_options'; +import { fieldToName } from '../../lib/field_to_display_name'; +import { useSourceContext } from '../../../../../containers/source'; +import { useWaffleOptionsContext } from '../../hooks/use_waffle_options'; interface Props { children: (props: Omit) => React.ReactElement; diff --git a/x-pack/plugins/infra/public/components/waffle/conditional_tooltip.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.tsx similarity index 100% rename from x-pack/plugins/infra/public/components/waffle/conditional_tooltip.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.tsx diff --git a/x-pack/plugins/infra/public/components/waffle/custom_field_panel.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/custom_field_panel.tsx similarity index 97% rename from x-pack/plugins/infra/public/components/waffle/custom_field_panel.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/custom_field_panel.tsx index d2dc535f6d6b32..090d53f1ff7379 100644 --- a/x-pack/plugins/infra/public/components/waffle/custom_field_panel.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/custom_field_panel.tsx @@ -8,7 +8,7 @@ import { EuiButton, EuiComboBox, EuiForm, EuiFormRow } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; import { IFieldType } from 'src/plugins/data/public'; -import { InfraGroupByOptions } from '../../lib/lib'; +import { InfraGroupByOptions } from '../../../../../lib/lib'; interface Props { onSubmit: (field: string) => void; diff --git a/x-pack/plugins/infra/public/components/waffle/gradient_legend.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/gradient_legend.tsx similarity index 96% rename from x-pack/plugins/infra/public/components/waffle/gradient_legend.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/gradient_legend.tsx index 6b0c4bb41dc980..87f7e4cbff11e6 100644 --- a/x-pack/plugins/infra/public/components/waffle/gradient_legend.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/gradient_legend.tsx @@ -6,13 +6,13 @@ import React from 'react'; -import { euiStyled } from '../../../../observability/public'; +import { euiStyled } from '../../../../../../../observability/public'; import { InfraFormatter, InfraWaffleMapBounds, InfraWaffleMapGradientLegend, InfraWaffleMapGradientRule, -} from '../../lib/lib'; +} from '../../../../../lib/lib'; interface Props { legend: InfraWaffleMapGradientLegend; diff --git a/x-pack/plugins/infra/public/components/waffle/group_name.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/group_name.tsx similarity index 96% rename from x-pack/plugins/infra/public/components/waffle/group_name.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/group_name.tsx index 01bd3600a1624e..308460203b132e 100644 --- a/x-pack/plugins/infra/public/components/waffle/group_name.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/group_name.tsx @@ -6,8 +6,8 @@ import { EuiLink, EuiToolTip } from '@elastic/eui'; import React from 'react'; -import { euiStyled } from '../../../../observability/public'; -import { InfraWaffleMapGroup, InfraWaffleMapOptions } from '../../lib/lib'; +import { euiStyled } from '../../../../../../../observability/public'; +import { InfraWaffleMapGroup, InfraWaffleMapOptions } from '../../../../../lib/lib'; interface Props { onDrilldown: (filter: string) => void; diff --git a/x-pack/plugins/infra/public/components/waffle/group_of_groups.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/group_of_groups.tsx similarity index 90% rename from x-pack/plugins/infra/public/components/waffle/group_of_groups.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/group_of_groups.tsx index 9634293587d49b..6b3f22007f580c 100644 --- a/x-pack/plugins/infra/public/components/waffle/group_of_groups.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/group_of_groups.tsx @@ -6,15 +6,15 @@ import React from 'react'; -import { euiStyled } from '../../../../observability/public'; +import { euiStyled } from '../../../../../../../observability/public'; import { InfraWaffleMapBounds, InfraWaffleMapGroupOfGroups, InfraWaffleMapOptions, -} from '../../lib/lib'; +} from '../../../../../lib/lib'; import { GroupName } from './group_name'; import { GroupOfNodes } from './group_of_nodes'; -import { InventoryItemType } from '../../../common/inventory_models/types'; +import { InventoryItemType } from '../../../../../../common/inventory_models/types'; interface Props { onDrilldown: (filter: string) => void; diff --git a/x-pack/plugins/infra/public/components/waffle/group_of_nodes.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/group_of_nodes.tsx similarity index 90% rename from x-pack/plugins/infra/public/components/waffle/group_of_nodes.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/group_of_nodes.tsx index 6b82671617df7a..fc438ed4ca0a2e 100644 --- a/x-pack/plugins/infra/public/components/waffle/group_of_nodes.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/group_of_nodes.tsx @@ -6,15 +6,15 @@ import React from 'react'; -import { euiStyled } from '../../../../observability/public'; +import { euiStyled } from '../../../../../../../observability/public'; import { InfraWaffleMapBounds, InfraWaffleMapGroupOfNodes, InfraWaffleMapOptions, -} from '../../lib/lib'; +} from '../../../../../lib/lib'; import { GroupName } from './group_name'; import { Node } from './node'; -import { InventoryItemType } from '../../../common/inventory_models/types'; +import { InventoryItemType } from '../../../../../../common/inventory_models/types'; interface Props { onDrilldown: (filter: string) => void; diff --git a/x-pack/plugins/infra/public/components/waffle/legend.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/legend.tsx similarity index 88% rename from x-pack/plugins/infra/public/components/waffle/legend.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/legend.tsx index 13e533b225d4df..ccb4cc71924f42 100644 --- a/x-pack/plugins/infra/public/components/waffle/legend.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/legend.tsx @@ -5,13 +5,13 @@ */ import React from 'react'; -import { euiStyled } from '../../../../observability/public'; -import { InfraFormatter, InfraWaffleMapBounds, InfraWaffleMapLegend } from '../../lib/lib'; +import { euiStyled } from '../../../../../../../observability/public'; +import { InfraFormatter, InfraWaffleMapBounds, InfraWaffleMapLegend } from '../../../../../lib/lib'; import { GradientLegend } from './gradient_legend'; import { LegendControls } from './legend_controls'; -import { isInfraWaffleMapGradientLegend, isInfraWaffleMapStepLegend } from './lib/type_guards'; +import { isInfraWaffleMapGradientLegend, isInfraWaffleMapStepLegend } from '../../lib/type_guards'; import { StepLegend } from './steps_legend'; -import { useWaffleOptionsContext } from '../../pages/inventory_view/hooks/use_waffle_options'; +import { useWaffleOptionsContext } from '../../hooks/use_waffle_options'; interface Props { legend: InfraWaffleMapLegend; bounds: InfraWaffleMapBounds; diff --git a/x-pack/plugins/infra/public/components/waffle/legend_controls.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/legend_controls.tsx similarity index 97% rename from x-pack/plugins/infra/public/components/waffle/legend_controls.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/legend_controls.tsx index 26b5b1c0af727d..6ec21ad2e1b49b 100644 --- a/x-pack/plugins/infra/public/components/waffle/legend_controls.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/legend_controls.tsx @@ -23,8 +23,8 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { SyntheticEvent, useState } from 'react'; -import { euiStyled } from '../../../../observability/public'; -import { InfraWaffleMapBounds } from '../../lib/lib'; +import { euiStyled } from '../../../../../../../observability/public'; +import { InfraWaffleMapBounds } from '../../../../../lib/lib'; interface Props { onChange: (options: { auto: boolean; bounds: InfraWaffleMapBounds }) => void; diff --git a/x-pack/plugins/infra/public/components/waffle/map.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/map.tsx similarity index 84% rename from x-pack/plugins/infra/public/components/waffle/map.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/map.tsx index 7cab2307dacfa1..e34c63d332fd87 100644 --- a/x-pack/plugins/infra/public/components/waffle/map.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/map.tsx @@ -5,20 +5,17 @@ */ import React from 'react'; -import { euiStyled } from '../../../../observability/public'; -import { nodesToWaffleMap } from '../../containers/waffle/nodes_to_wafflemap'; -import { - isWaffleMapGroupWithGroups, - isWaffleMapGroupWithNodes, -} from '../../containers/waffle/type_guards'; -import { InfraWaffleMapBounds, InfraWaffleMapOptions } from '../../lib/lib'; -import { AutoSizer } from '../auto_sizer'; +import { euiStyled } from '../../../../../../../observability/public'; +import { nodesToWaffleMap } from '../../lib/nodes_to_wafflemap'; +import { isWaffleMapGroupWithGroups, isWaffleMapGroupWithNodes } from '../../lib/type_guards'; +import { InfraWaffleMapBounds, InfraWaffleMapOptions } from '../../../../../lib/lib'; +import { AutoSizer } from '../../../../../components/auto_sizer'; import { GroupOfGroups } from './group_of_groups'; import { GroupOfNodes } from './group_of_nodes'; import { Legend } from './legend'; -import { applyWaffleMapLayout } from './lib/apply_wafflemap_layout'; -import { SnapshotNode } from '../../../common/http_api/snapshot_api'; -import { InventoryItemType } from '../../../common/inventory_models/types'; +import { applyWaffleMapLayout } from '../../lib/apply_wafflemap_layout'; +import { SnapshotNode } from '../../../../../../common/http_api/snapshot_api'; +import { InventoryItemType } from '../../../../../../common/inventory_models/types'; interface Props { nodes: SnapshotNode[]; diff --git a/x-pack/plugins/infra/public/components/waffle/metric_control/custom_metric_form.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/metric_control/custom_metric_form.tsx similarity index 97% rename from x-pack/plugins/infra/public/components/waffle/metric_control/custom_metric_form.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/metric_control/custom_metric_form.tsx index 26e42061ed10bd..aec624c0aff1f5 100644 --- a/x-pack/plugins/infra/public/components/waffle/metric_control/custom_metric_form.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/metric_control/custom_metric_form.tsx @@ -26,8 +26,11 @@ import { SnapshotCustomMetricInput, SNAPSHOT_CUSTOM_AGGREGATIONS, SnapshotCustomAggregationRT, -} from '../../../../common/http_api/snapshot_api'; -import { EuiTheme, withTheme } from '../../../../../../legacy/common/eui_styled_components'; +} from '../../../../../../../common/http_api/snapshot_api'; +import { + EuiTheme, + withTheme, +} from '../../../../../../../../../legacy/common/eui_styled_components'; interface SelectedOption { label: string; diff --git a/x-pack/plugins/infra/public/components/waffle/metric_control/get_custom_metric_label.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/metric_control/get_custom_metric_label.ts similarity index 91% rename from x-pack/plugins/infra/public/components/waffle/metric_control/get_custom_metric_label.ts rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/metric_control/get_custom_metric_label.ts index 4f88c1b29c1f25..495cc8197d2e78 100644 --- a/x-pack/plugins/infra/public/components/waffle/metric_control/get_custom_metric_label.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/metric_control/get_custom_metric_label.ts @@ -5,7 +5,7 @@ */ import { i18n } from '@kbn/i18n'; -import { SnapshotCustomMetricInput } from '../../../../common/http_api/snapshot_api'; +import { SnapshotCustomMetricInput } from '../../../../../../../common/http_api/snapshot_api'; export const getCustomMetricLabel = (metric: SnapshotCustomMetricInput) => { const METRIC_LABELS = { diff --git a/x-pack/plugins/infra/public/components/waffle/metric_control/index.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/metric_control/index.tsx similarity index 97% rename from x-pack/plugins/infra/public/components/waffle/metric_control/index.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/metric_control/index.tsx index 0f2034fe9cb258..08d5b3e9e06706 100644 --- a/x-pack/plugins/infra/public/components/waffle/metric_control/index.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/metric_control/index.tsx @@ -13,14 +13,14 @@ import { SnapshotMetricInput, SnapshotCustomMetricInput, SnapshotCustomMetricInputRT, -} from '../../../../common/http_api/snapshot_api'; +} from '../../../../../../../common/http_api/snapshot_api'; import { CustomMetricForm } from './custom_metric_form'; import { getCustomMetricLabel } from './get_custom_metric_label'; import { MetricsContextMenu } from './metrics_context_menu'; import { ModeSwitcher } from './mode_switcher'; import { MetricsEditMode } from './metrics_edit_mode'; import { CustomMetricMode } from './types'; -import { SnapshotMetricType } from '../../../../common/inventory_models/types'; +import { SnapshotMetricType } from '../../../../../../../common/inventory_models/types'; interface Props { options: Array<{ text: string; value: string }>; diff --git a/x-pack/plugins/infra/public/components/waffle/metric_control/metrics_context_menu.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/metric_control/metrics_context_menu.tsx similarity index 94% rename from x-pack/plugins/infra/public/components/waffle/metric_control/metrics_context_menu.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/metric_control/metrics_context_menu.tsx index 1aacf54244c375..1cdef493aee4f2 100644 --- a/x-pack/plugins/infra/public/components/waffle/metric_control/metrics_context_menu.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/metric_control/metrics_context_menu.tsx @@ -9,11 +9,11 @@ import { SnapshotMetricInput, SnapshotCustomMetricInput, SnapshotCustomMetricInputRT, -} from '../../../../common/http_api/snapshot_api'; +} from '../../../../../../../common/http_api/snapshot_api'; import { SnapshotMetricTypeRT, SnapshotMetricType, -} from '../../../../common/inventory_models/types'; +} from '../../../../../../../common/inventory_models/types'; import { getCustomMetricLabel } from './get_custom_metric_label'; interface Props { diff --git a/x-pack/plugins/infra/public/components/waffle/metric_control/metrics_edit_mode.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/metric_control/metrics_edit_mode.tsx similarity index 92% rename from x-pack/plugins/infra/public/components/waffle/metric_control/metrics_edit_mode.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/metric_control/metrics_edit_mode.tsx index ba1f46815db20c..4d1bc906de0b92 100644 --- a/x-pack/plugins/infra/public/components/waffle/metric_control/metrics_edit_mode.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/metric_control/metrics_edit_mode.tsx @@ -6,9 +6,12 @@ import React from 'react'; import { EuiFlexItem, EuiFlexGroup, EuiButtonIcon } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { SnapshotCustomMetricInput } from '../../../../common/http_api/snapshot_api'; +import { SnapshotCustomMetricInput } from '../../../../../../../common/http_api/snapshot_api'; import { getCustomMetricLabel } from './get_custom_metric_label'; -import { EuiTheme, withTheme } from '../../../../../../legacy/common/eui_styled_components'; +import { + EuiTheme, + withTheme, +} from '../../../../../../../../../legacy/common/eui_styled_components'; interface Props { theme: EuiTheme; diff --git a/x-pack/plugins/infra/public/components/waffle/metric_control/mode_switcher.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/metric_control/mode_switcher.tsx similarity index 95% rename from x-pack/plugins/infra/public/components/waffle/metric_control/mode_switcher.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/metric_control/mode_switcher.tsx index 43bb904594c68f..acb740f1750c8d 100644 --- a/x-pack/plugins/infra/public/components/waffle/metric_control/mode_switcher.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/metric_control/mode_switcher.tsx @@ -8,8 +8,11 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { CustomMetricMode } from './types'; -import { SnapshotCustomMetricInput } from '../../../../common/http_api/snapshot_api'; -import { EuiTheme, withTheme } from '../../../../../../legacy/common/eui_styled_components'; +import { SnapshotCustomMetricInput } from '../../../../../../../common/http_api/snapshot_api'; +import { + EuiTheme, + withTheme, +} from '../../../../../../../../../legacy/common/eui_styled_components'; interface Props { theme: EuiTheme; diff --git a/x-pack/plugins/infra/public/components/waffle/metric_control/types.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/metric_control/types.ts similarity index 100% rename from x-pack/plugins/infra/public/components/waffle/metric_control/types.ts rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/metric_control/types.ts diff --git a/x-pack/plugins/infra/public/components/waffle/node.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node.tsx similarity index 93% rename from x-pack/plugins/infra/public/components/waffle/node.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node.tsx index 4eb5ccb8c1b4d9..fd5b5b01f329fa 100644 --- a/x-pack/plugins/infra/public/components/waffle/node.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node.tsx @@ -10,11 +10,15 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { ConditionalToolTip } from './conditional_tooltip'; -import { euiStyled } from '../../../../observability/public'; -import { InfraWaffleMapBounds, InfraWaffleMapNode, InfraWaffleMapOptions } from '../../lib/lib'; -import { colorFromValue } from './lib/color_from_value'; +import { euiStyled } from '../../../../../../../observability/public'; +import { + InfraWaffleMapBounds, + InfraWaffleMapNode, + InfraWaffleMapOptions, +} from '../../../../../lib/lib'; +import { colorFromValue } from '../../lib/color_from_value'; import { NodeContextMenu } from './node_context_menu'; -import { InventoryItemType } from '../../../common/inventory_models/types'; +import { InventoryItemType } from '../../../../../../common/inventory_models/types'; const initialState = { isPopoverOpen: false, diff --git a/x-pack/plugins/infra/public/components/waffle/node_context_menu.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node_context_menu.tsx similarity index 91% rename from x-pack/plugins/infra/public/components/waffle/node_context_menu.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node_context_menu.tsx index 5f05cebd8f616a..275635a33ec266 100644 --- a/x-pack/plugins/infra/public/components/waffle/node_context_menu.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node_context_menu.tsx @@ -9,12 +9,13 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { useMemo, useState } from 'react'; -import { InfraWaffleMapNode, InfraWaffleMapOptions } from '../../lib/lib'; -import { getNodeDetailUrl, getNodeLogsUrl } from '../../pages/link_to'; -import { createUptimeLink } from './lib/create_uptime_link'; -import { findInventoryModel, findInventoryFields } from '../../../common/inventory_models'; -import { useKibana } from '../../../../../../src/plugins/kibana_react/public'; -import { InventoryItemType } from '../../../common/inventory_models/types'; +import { AlertFlyout } from '../../../../../components/alerting/metrics/alert_flyout'; +import { InfraWaffleMapNode, InfraWaffleMapOptions } from '../../../../../lib/lib'; +import { getNodeDetailUrl, getNodeLogsUrl } from '../../../../link_to'; +import { createUptimeLink } from '../../lib/create_uptime_link'; +import { findInventoryModel, findInventoryFields } from '../../../../../../common/inventory_models'; +import { useKibana } from '../../../../../../../../../src/plugins/kibana_react/public'; +import { InventoryItemType } from '../../../../../../common/inventory_models/types'; import { Section, SectionLinkProps, @@ -23,9 +24,8 @@ import { SectionSubtitle, SectionLinks, SectionLink, -} from '../../../../observability/public'; -import { useLinkProps } from '../../hooks/use_link_props'; -import { AlertFlyout } from '../alerting/metrics/alert_flyout'; +} from '../../../../../../../observability/public'; +import { useLinkProps } from '../../../../../hooks/use_link_props'; interface Props { options: InfraWaffleMapOptions; diff --git a/x-pack/plugins/infra/public/components/waffle/steps_legend.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/steps_legend.tsx similarity index 95% rename from x-pack/plugins/infra/public/components/waffle/steps_legend.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/steps_legend.tsx index d2079d53dad71b..1ef0f2d0c42889 100644 --- a/x-pack/plugins/infra/public/components/waffle/steps_legend.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/steps_legend.tsx @@ -7,13 +7,13 @@ import { darken } from 'polished'; import React from 'react'; -import { euiStyled } from '../../../../observability/public'; +import { euiStyled } from '../../../../../../../observability/public'; import { InfraFormatter, InfraWaffleMapRuleOperator, InfraWaffleMapStepLegend, InfraWaffleMapStepRule, -} from '../../lib/lib'; +} from '../../../../../lib/lib'; const OPERATORS = { [InfraWaffleMapRuleOperator.gte]: '>=', diff --git a/x-pack/plugins/infra/public/components/waffle/view_switcher.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/view_switcher.tsx similarity index 100% rename from x-pack/plugins/infra/public/components/waffle/view_switcher.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/view_switcher.tsx diff --git a/x-pack/plugins/infra/public/components/waffle/waffle_accounts_controls.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/waffle_accounts_controls.tsx similarity index 94% rename from x-pack/plugins/infra/public/components/waffle/waffle_accounts_controls.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/waffle_accounts_controls.tsx index 56c3a205b05d48..a8b0cf21bce85e 100644 --- a/x-pack/plugins/infra/public/components/waffle/waffle_accounts_controls.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/waffle_accounts_controls.tsx @@ -14,7 +14,7 @@ import { import React, { useCallback, useState, useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import { InventoryCloudAccount } from '../../../common/http_api/inventory_meta_api'; +import { InventoryCloudAccount } from '../../../../../../common/http_api/inventory_meta_api'; interface Props { accountId: string; @@ -24,7 +24,7 @@ interface Props { export const WaffleAccountsControls = (props: Props) => { const { accountId, options } = props; - const [isOpen, setIsOpen] = useState(); + const [isOpen, setIsOpen] = useState(false); const showPopover = useCallback(() => { setIsOpen(true); diff --git a/x-pack/plugins/infra/public/components/waffle/waffle_group_by_controls.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/waffle_group_by_controls.tsx similarity index 95% rename from x-pack/plugins/infra/public/components/waffle/waffle_group_by_controls.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/waffle_group_by_controls.tsx index 1a3cef591bc077..bc763d2cf93785 100644 --- a/x-pack/plugins/infra/public/components/waffle/waffle_group_by_controls.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/waffle_group_by_controls.tsx @@ -17,11 +17,11 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import React from 'react'; import { IFieldType } from 'src/plugins/data/public'; -import { InfraGroupByOptions } from '../../lib/lib'; +import { InfraGroupByOptions } from '../../../../../lib/lib'; import { CustomFieldPanel } from './custom_field_panel'; -import { euiStyled } from '../../../../observability/public'; -import { InventoryItemType } from '../../../common/inventory_models/types'; -import { SnapshotGroupBy } from '../../../common/http_api/snapshot_api'; +import { euiStyled } from '../../../../../../../observability/public'; +import { InventoryItemType } from '../../../../../../common/inventory_models/types'; +import { SnapshotGroupBy } from '../../../../../../common/http_api/snapshot_api'; interface Props { options: Array<{ text: string; field: string; toolTipContent?: string }>; diff --git a/x-pack/plugins/infra/public/components/waffle/waffle_inventory_switcher.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/waffle_inventory_switcher.tsx similarity index 94% rename from x-pack/plugins/infra/public/components/waffle/waffle_inventory_switcher.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/waffle_inventory_switcher.tsx index 21da10a0a76502..23e06823f407f4 100644 --- a/x-pack/plugins/infra/public/components/waffle/waffle_inventory_switcher.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/waffle_inventory_switcher.tsx @@ -14,9 +14,9 @@ import { import React, { useCallback, useState, useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import { findInventoryModel } from '../../../common/inventory_models'; -import { InventoryItemType } from '../../../common/inventory_models/types'; -import { useWaffleOptionsContext } from '../../pages/inventory_view/hooks/use_waffle_options'; +import { findInventoryModel } from '../../../../../../common/inventory_models'; +import { InventoryItemType } from '../../../../../../common/inventory_models/types'; +import { useWaffleOptionsContext } from '../../hooks/use_waffle_options'; const getDisplayNameForType = (type: InventoryItemType) => { const inventoryModel = findInventoryModel(type); diff --git a/x-pack/plugins/infra/public/components/waffle/waffle_region_controls.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/waffle_region_controls.tsx similarity index 97% rename from x-pack/plugins/infra/public/components/waffle/waffle_region_controls.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/waffle_region_controls.tsx index 52377bf4b8296e..671e44f42ef6a5 100644 --- a/x-pack/plugins/infra/public/components/waffle/waffle_region_controls.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/waffle_region_controls.tsx @@ -23,7 +23,7 @@ interface Props { export const WaffleRegionControls = (props: Props) => { const { region, options } = props; - const [isOpen, setIsOpen] = useState(); + const [isOpen, setIsOpen] = useState(false); const showPopover = useCallback(() => { setIsOpen(true); diff --git a/x-pack/plugins/infra/public/components/waffle/waffle_time_controls.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/waffle_time_controls.tsx similarity index 95% rename from x-pack/plugins/infra/public/components/waffle/waffle_time_controls.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/waffle_time_controls.tsx index 458bb674afadef..7f190f21484d93 100644 --- a/x-pack/plugins/infra/public/components/waffle/waffle_time_controls.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/waffle_time_controls.tsx @@ -8,7 +8,7 @@ import { EuiButtonEmpty, EuiDatePicker, EuiFormControlLayout } from '@elastic/eu import { FormattedMessage } from '@kbn/i18n/react'; import moment, { Moment } from 'moment'; import React, { useCallback } from 'react'; -import { useWaffleTimeContext } from '../../pages/inventory_view/hooks/use_waffle_time'; +import { useWaffleTimeContext } from '../../hooks/use_waffle_time'; export const WaffleTimeControls = () => { const { diff --git a/x-pack/plugins/infra/public/containers/inventory_metadata/use_inventory_meta.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_inventory_meta.ts similarity index 79% rename from x-pack/plugins/infra/public/containers/inventory_metadata/use_inventory_meta.ts rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_inventory_meta.ts index 0ed1f3e35449b4..b038491690a137 100644 --- a/x-pack/plugins/infra/public/containers/inventory_metadata/use_inventory_meta.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_inventory_meta.ts @@ -7,13 +7,13 @@ import { fold } from 'fp-ts/lib/Either'; import { identity } from 'fp-ts/lib/function'; import { pipe } from 'fp-ts/lib/pipeable'; import { useEffect } from 'react'; -import { throwErrors, createPlainError } from '../../../common/runtime_types'; -import { useHTTPRequest } from '../../hooks/use_http_request'; +import { throwErrors, createPlainError } from '../../../../../common/runtime_types'; +import { useHTTPRequest } from '../../../../hooks/use_http_request'; import { InventoryMetaResponseRT, InventoryMetaResponse, -} from '../../../common/http_api/inventory_meta_api'; -import { InventoryItemType } from '../../../common/inventory_models/types'; +} from '../../../../../common/http_api/inventory_meta_api'; +import { InventoryItemType } from '../../../../../common/inventory_models/types'; export function useInventoryMeta(sourceId: string, nodeType: InventoryItemType) { const decodeResponse = (response: any) => { diff --git a/x-pack/plugins/infra/public/containers/waffle/use_snaphot.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_snaphot.ts similarity index 83% rename from x-pack/plugins/infra/public/containers/waffle/use_snaphot.ts rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_snaphot.ts index 31f02f46caedac..3ec63d7b2de286 100644 --- a/x-pack/plugins/infra/public/containers/waffle/use_snaphot.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_snaphot.ts @@ -8,14 +8,17 @@ import { useEffect } from 'react'; import { fold } from 'fp-ts/lib/Either'; import { identity } from 'fp-ts/lib/function'; import { pipe } from 'fp-ts/lib/pipeable'; -import { throwErrors, createPlainError } from '../../../common/runtime_types'; -import { useHTTPRequest } from '../../hooks/use_http_request'; +import { throwErrors, createPlainError } from '../../../../../common/runtime_types'; +import { useHTTPRequest } from '../../../../hooks/use_http_request'; import { SnapshotNodeResponseRT, SnapshotNodeResponse, SnapshotGroupBy, -} from '../../../common/http_api/snapshot_api'; -import { InventoryItemType, SnapshotMetricType } from '../../../common/inventory_models/types'; +} from '../../../../../common/http_api/snapshot_api'; +import { + InventoryItemType, + SnapshotMetricType, +} from '../../../../../common/inventory_models/types'; export function useSnapshot( filterQuery: string | null | undefined, diff --git a/x-pack/plugins/infra/public/pages/inventory_view/hooks/use_waffle_filters.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.ts similarity index 90% rename from x-pack/plugins/infra/public/pages/inventory_view/hooks/use_waffle_filters.ts rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.ts index 02c079dcaddc40..f6cbb59779039a 100644 --- a/x-pack/plugins/infra/public/pages/inventory_view/hooks/use_waffle_filters.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.ts @@ -10,10 +10,10 @@ import { pipe } from 'fp-ts/lib/pipeable'; import { fold } from 'fp-ts/lib/Either'; import { constant, identity } from 'fp-ts/lib/function'; import createContainter from 'constate'; -import { useUrlState } from '../../../utils/use_url_state'; -import { useSourceContext } from '../../../containers/source'; -import { convertKueryToElasticSearchQuery } from '../../../utils/kuery'; -import { esKuery } from '../../../../../../../src/plugins/data/public'; +import { useUrlState } from '../../../../utils/use_url_state'; +import { useSourceContext } from '../../../../containers/source'; +import { convertKueryToElasticSearchQuery } from '../../../../utils/kuery'; +import { esKuery } from '../../../../../../../../src/plugins/data/public'; const validateKuery = (expression: string) => { try { diff --git a/x-pack/plugins/infra/public/pages/inventory_view/hooks/use_waffle_options.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.ts similarity index 95% rename from x-pack/plugins/infra/public/pages/inventory_view/hooks/use_waffle_options.ts rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.ts index 2853917d5f6838..32bfe6e085b4e4 100644 --- a/x-pack/plugins/infra/public/pages/inventory_view/hooks/use_waffle_options.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.ts @@ -17,9 +17,9 @@ import { SnapshotMetricInputRT, SnapshotGroupByRT, SnapshotCustomMetricInputRT, -} from '../../../../common/http_api/snapshot_api'; -import { useUrlState } from '../../../utils/use_url_state'; -import { InventoryItemType, ItemTypeRT } from '../../../../common/inventory_models/types'; +} from '../../../../../common/http_api/snapshot_api'; +import { useUrlState } from '../../../../utils/use_url_state'; +import { InventoryItemType, ItemTypeRT } from '../../../../../common/inventory_models/types'; export const DEFAULT_WAFFLE_OPTIONS_STATE: WaffleOptionsState = { metric: { type: 'cpu' }, diff --git a/x-pack/plugins/infra/public/pages/inventory_view/hooks/use_waffle_time.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_time.ts similarity index 97% rename from x-pack/plugins/infra/public/pages/inventory_view/hooks/use_waffle_time.ts rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_time.ts index 051b5e598cb757..db3abd37b58dd8 100644 --- a/x-pack/plugins/infra/public/pages/inventory_view/hooks/use_waffle_time.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_time.ts @@ -9,7 +9,7 @@ import { pipe } from 'fp-ts/lib/pipeable'; import { fold } from 'fp-ts/lib/Either'; import { constant, identity } from 'fp-ts/lib/function'; import createContainer from 'constate'; -import { useUrlState } from '../../../utils/use_url_state'; +import { useUrlState } from '../../../../utils/use_url_state'; export const DEFAULT_WAFFLE_TIME_STATE: WaffleTimeState = { currentTime: Date.now(), diff --git a/x-pack/plugins/infra/public/pages/inventory_view/hooks/use_waffle_view_state.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_view_state.ts similarity index 100% rename from x-pack/plugins/infra/public/pages/inventory_view/hooks/use_waffle_view_state.ts rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_view_state.ts diff --git a/x-pack/plugins/infra/public/pages/infrastructure/snapshot/index.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/index.tsx similarity index 98% rename from x-pack/plugins/infra/public/pages/infrastructure/snapshot/index.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/index.tsx index 48cc56388c0f24..e473aea7a1f0bc 100644 --- a/x-pack/plugins/infra/public/pages/infrastructure/snapshot/index.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/index.tsx @@ -20,7 +20,7 @@ import { ViewSourceConfigurationButton } from '../../../components/source_config import { Source } from '../../../containers/source'; import { useTrackPageview } from '../../../../../observability/public'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; -import { Layout } from '../../../components/inventory/layout'; +import { Layout } from './components/layout'; import { useLinkProps } from '../../../hooks/use_link_props'; export const SnapshotPage = () => { diff --git a/x-pack/plugins/infra/public/components/waffle/lib/apply_wafflemap_layout.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/apply_wafflemap_layout.ts similarity index 94% rename from x-pack/plugins/infra/public/components/waffle/lib/apply_wafflemap_layout.ts rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/apply_wafflemap_layout.ts index 5f3c06fcfbba77..68600ac5d2ce49 100644 --- a/x-pack/plugins/infra/public/components/waffle/lib/apply_wafflemap_layout.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/apply_wafflemap_layout.ts @@ -4,11 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ import { first, sortBy } from 'lodash'; -import { - isWaffleMapGroupWithGroups, - isWaffleMapGroupWithNodes, -} from '../../../containers/waffle/type_guards'; -import { InfraWaffleMapGroup } from '../../../lib/lib'; +import { isWaffleMapGroupWithGroups, isWaffleMapGroupWithNodes } from './type_guards'; +import { InfraWaffleMapGroup } from '../../../../lib/lib'; import { sizeOfSquares } from './size_of_squares'; export function getColumns(n: number, w = 1, h = 1) { diff --git a/x-pack/plugins/infra/public/components/waffle/lib/color_from_value.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/color_from_value.ts similarity index 98% rename from x-pack/plugins/infra/public/components/waffle/lib/color_from_value.ts rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/color_from_value.ts index c082686bb9d63a..334865306ee88e 100644 --- a/x-pack/plugins/infra/public/components/waffle/lib/color_from_value.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/color_from_value.ts @@ -12,7 +12,7 @@ import { InfraWaffleMapLegend, InfraWaffleMapRuleOperator, InfraWaffleMapStepLegend, -} from '../../../lib/lib'; +} from '../../../../lib/lib'; import { isInfraWaffleMapGradientLegend, isInfraWaffleMapStepLegend } from './type_guards'; const OPERATOR_TO_FN = { diff --git a/x-pack/plugins/infra/public/components/waffle/lib/create_uptime_link.test.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/create_uptime_link.test.ts similarity index 96% rename from x-pack/plugins/infra/public/components/waffle/lib/create_uptime_link.test.ts rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/create_uptime_link.test.ts index 902969c83ba393..5f760cf2f591e2 100644 --- a/x-pack/plugins/infra/public/components/waffle/lib/create_uptime_link.test.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/create_uptime_link.test.ts @@ -5,8 +5,8 @@ */ import { createUptimeLink } from './create_uptime_link'; -import { InfraWaffleMapOptions, InfraFormatterType } from '../../../lib/lib'; -import { SnapshotMetricType } from '../../../../common/inventory_models/types'; +import { InfraWaffleMapOptions, InfraFormatterType } from '../../../../lib/lib'; +import { SnapshotMetricType } from '../../../../../common/inventory_models/types'; const options: InfraWaffleMapOptions = { fields: { diff --git a/x-pack/plugins/infra/public/components/waffle/lib/create_uptime_link.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/create_uptime_link.ts similarity index 83% rename from x-pack/plugins/infra/public/components/waffle/lib/create_uptime_link.ts rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/create_uptime_link.ts index 72b46f4fb5c7b7..6c089ee8d22f46 100644 --- a/x-pack/plugins/infra/public/components/waffle/lib/create_uptime_link.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/create_uptime_link.ts @@ -5,9 +5,9 @@ */ import { get } from 'lodash'; -import { InfraWaffleMapNode, InfraWaffleMapOptions } from '../../../lib/lib'; -import { InventoryItemType } from '../../../../common/inventory_models/types'; -import { LinkDescriptor } from '../../../hooks/use_link_props'; +import { InfraWaffleMapNode, InfraWaffleMapOptions } from '../../../../lib/lib'; +import { InventoryItemType } from '../../../../../common/inventory_models/types'; +import { LinkDescriptor } from '../../../../hooks/use_link_props'; export const createUptimeLink = ( options: InfraWaffleMapOptions, diff --git a/x-pack/plugins/infra/public/components/waffle/lib/field_to_display_name.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/field_to_display_name.ts similarity index 100% rename from x-pack/plugins/infra/public/components/waffle/lib/field_to_display_name.ts rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/field_to_display_name.ts diff --git a/x-pack/plugins/infra/public/containers/waffle/nodes_to_wafflemap.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/nodes_to_wafflemap.ts similarity index 97% rename from x-pack/plugins/infra/public/containers/waffle/nodes_to_wafflemap.ts rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/nodes_to_wafflemap.ts index d2511ba7e669e6..469b54b2d9d684 100644 --- a/x-pack/plugins/infra/public/containers/waffle/nodes_to_wafflemap.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/nodes_to_wafflemap.ts @@ -11,9 +11,9 @@ import { InfraWaffleMapGroupOfGroups, InfraWaffleMapGroupOfNodes, InfraWaffleMapNode, -} from '../../lib/lib'; +} from '../../../../lib/lib'; import { isWaffleMapGroupWithGroups, isWaffleMapGroupWithNodes } from './type_guards'; -import { SnapshotNodePath, SnapshotNode } from '../../../common/http_api/snapshot_api'; +import { SnapshotNodePath, SnapshotNode } from '../../../../../common/http_api/snapshot_api'; export function createId(path: SnapshotNodePath[]) { return path.map(p => p.value).join('/'); diff --git a/x-pack/plugins/infra/public/components/waffle/lib/size_of_squares.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/size_of_squares.ts similarity index 100% rename from x-pack/plugins/infra/public/components/waffle/lib/size_of_squares.ts rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/size_of_squares.ts diff --git a/x-pack/plugins/infra/public/containers/waffle/type_guards.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/type_guards.ts similarity index 55% rename from x-pack/plugins/infra/public/containers/waffle/type_guards.ts rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/type_guards.ts index 3e21e3a56a6c6a..62d02022d4c939 100644 --- a/x-pack/plugins/infra/public/containers/waffle/type_guards.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/type_guards.ts @@ -4,7 +4,22 @@ * you may not use this file except in compliance with the Elastic License. */ -import { InfraWaffleMapGroupOfGroups, InfraWaffleMapGroupOfNodes } from '../../lib/lib'; +import { + InfraWaffleMapGroupOfGroups, + InfraWaffleMapGroupOfNodes, + InfraWaffleMapGradientLegend, + InfraWaffleMapStepLegend, +} from '../../../../lib/lib'; + +export function isInfraWaffleMapStepLegend(subject: any): subject is InfraWaffleMapStepLegend { + return subject.type && subject.type === 'step'; +} + +export function isInfraWaffleMapGradientLegend( + subject: any +): subject is InfraWaffleMapGradientLegend { + return subject.type && subject.type === 'gradient'; +} export function isWaffleMapGroupWithNodes(subject: any): subject is InfraWaffleMapGroupOfNodes { return subject && subject.nodes != null && Array.isArray(subject.nodes); diff --git a/x-pack/plugins/infra/public/pages/infrastructure/snapshot/toolbar.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/toolbar.tsx similarity index 75% rename from x-pack/plugins/infra/public/pages/infrastructure/snapshot/toolbar.tsx rename to x-pack/plugins/infra/public/pages/metrics/inventory_view/toolbar.tsx index ccdaa5e8dc7857..d6a87a0197f5f7 100644 --- a/x-pack/plugins/infra/public/pages/infrastructure/snapshot/toolbar.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/toolbar.tsx @@ -8,9 +8,9 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React from 'react'; import { Toolbar } from '../../../components/eui/toolbar'; -import { WaffleTimeControls } from '../../../components/waffle/waffle_time_controls'; -import { WaffleInventorySwitcher } from '../../../components/waffle/waffle_inventory_switcher'; -import { SearchBar } from '../../inventory_view/compontents/search_bar'; +import { WaffleTimeControls } from './components/waffle/waffle_time_controls'; +import { WaffleInventorySwitcher } from './components/waffle/waffle_inventory_switcher'; +import { SearchBar } from './components/search_bar'; export const SnapshotToolbar = () => ( diff --git a/x-pack/plugins/infra/public/pages/metrics/components/chart_section_vis.tsx b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/chart_section_vis.tsx similarity index 94% rename from x-pack/plugins/infra/public/pages/metrics/components/chart_section_vis.tsx rename to x-pack/plugins/infra/public/pages/metrics/metric_detail/components/chart_section_vis.tsx index 290f0eda452ce2..588a0d84918c6c 100644 --- a/x-pack/plugins/infra/public/pages/metrics/components/chart_section_vis.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/chart_section_vis.tsx @@ -8,7 +8,7 @@ import moment from 'moment'; import { i18n } from '@kbn/i18n'; import { Axis, Chart, niceTimeFormatter, Position, Settings, TooltipValue } from '@elastic/charts'; import { EuiPageContentBody } from '@elastic/eui'; -import { getChartTheme } from '../../../components/metrics_explorer/helpers/get_chart_theme'; +import { getChartTheme } from '../../metrics_explorer/components/helpers/get_chart_theme'; import { SeriesChart } from './series_chart'; import { getFormatter, @@ -19,8 +19,8 @@ import { seriesHasLessThen2DataPoints, } from './helpers'; import { ErrorMessage } from './error_message'; -import { useKibanaUiSetting } from '../../../utils/use_kibana_ui_setting'; -import { useUiSetting } from '../../../../../../../src/plugins/kibana_react/public'; +import { useKibanaUiSetting } from '../../../../utils/use_kibana_ui_setting'; +import { useUiSetting } from '../../../../../../../../src/plugins/kibana_react/public'; import { VisSectionProps } from '../types'; export const ChartSectionVis = ({ diff --git a/x-pack/plugins/infra/public/pages/metrics/components/error_message.tsx b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/error_message.tsx similarity index 100% rename from x-pack/plugins/infra/public/pages/metrics/components/error_message.tsx rename to x-pack/plugins/infra/public/pages/metrics/metric_detail/components/error_message.tsx diff --git a/x-pack/plugins/infra/public/pages/metrics/components/gauges_section_vis.tsx b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/gauges_section_vis.tsx similarity index 92% rename from x-pack/plugins/infra/public/pages/metrics/components/gauges_section_vis.tsx rename to x-pack/plugins/infra/public/pages/metrics/metric_detail/components/gauges_section_vis.tsx index e069b52be8be70..0aab676b7d6c54 100644 --- a/x-pack/plugins/infra/public/pages/metrics/components/gauges_section_vis.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/gauges_section_vis.tsx @@ -16,9 +16,9 @@ import { import { get, last, max } from 'lodash'; import React, { ReactText } from 'react'; -import { euiStyled } from '../../../../../observability/public'; -import { createFormatter } from '../../../utils/formatters'; -import { InventoryFormatterType } from '../../../../common/inventory_models/types'; +import { euiStyled } from '../../../../../../observability/public'; +import { createFormatter } from '../../../../utils/formatters'; +import { InventoryFormatterType } from '../../../../../common/inventory_models/types'; import { SeriesOverrides, VisSectionProps } from '../types'; import { getChartName } from './helpers'; diff --git a/x-pack/plugins/infra/public/pages/metrics/components/helpers.ts b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/helpers.ts similarity index 91% rename from x-pack/plugins/infra/public/pages/metrics/components/helpers.ts rename to x-pack/plugins/infra/public/pages/metrics/metric_detail/components/helpers.ts index 4449196f2fb537..bb4ad326609520 100644 --- a/x-pack/plugins/infra/public/pages/metrics/components/helpers.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/helpers.ts @@ -7,15 +7,15 @@ import { ReactText } from 'react'; import Color from 'color'; import { get, first, last, min, max } from 'lodash'; -import { createFormatter } from '../../../utils/formatters'; -import { InfraDataSeries } from '../../../graphql/types'; +import { createFormatter } from '../../../../utils/formatters'; +import { InfraDataSeries } from '../../../../graphql/types'; import { InventoryVisTypeRT, InventoryFormatterType, InventoryVisType, -} from '../../../../common/inventory_models/types'; +} from '../../../../../common/inventory_models/types'; import { SeriesOverrides } from '../types'; -import { NodeDetailsMetricData } from '../../../../common/http_api/node_details_api'; +import { NodeDetailsMetricData } from '../../../../../common/http_api/node_details_api'; /** * Returns a formatter diff --git a/x-pack/plugins/infra/public/pages/metrics/components/invalid_node.tsx b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/invalid_node.tsx similarity index 90% rename from x-pack/plugins/infra/public/pages/metrics/components/invalid_node.tsx rename to x-pack/plugins/infra/public/pages/metrics/metric_detail/components/invalid_node.tsx index b089e2237c2e57..6d83017a3f6892 100644 --- a/x-pack/plugins/infra/public/pages/metrics/components/invalid_node.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/invalid_node.tsx @@ -7,9 +7,9 @@ import { EuiButton, EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import React from 'react'; -import { euiStyled } from '../../../../../observability/public'; -import { ViewSourceConfigurationButton } from '../../../components/source_configuration'; -import { useLinkProps } from '../../../hooks/use_link_props'; +import { euiStyled } from '../../../../../../observability/public'; +import { ViewSourceConfigurationButton } from '../../../../components/source_configuration'; +import { useLinkProps } from '../../../../hooks/use_link_props'; interface InvalidNodeErrorProps { nodeName: string; diff --git a/x-pack/plugins/infra/public/pages/metrics/components/layout_content.tsx b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/layout_content.tsx similarity index 84% rename from x-pack/plugins/infra/public/pages/metrics/components/layout_content.tsx rename to x-pack/plugins/infra/public/pages/metrics/metric_detail/components/layout_content.tsx index 4e10f245acdccc..46201025175492 100644 --- a/x-pack/plugins/infra/public/pages/metrics/components/layout_content.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/layout_content.tsx @@ -5,7 +5,7 @@ */ import { EuiPageContent } from '@elastic/eui'; -import { euiStyled } from '../../../../../observability/public'; +import { euiStyled } from '../../../../../../observability/public'; export const LayoutContent = euiStyled(EuiPageContent)` position: relative; diff --git a/x-pack/plugins/infra/public/pages/metrics/components/metadata_details.tsx b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/metadata_details.tsx similarity index 97% rename from x-pack/plugins/infra/public/pages/metrics/components/metadata_details.tsx rename to x-pack/plugins/infra/public/pages/metrics/metric_detail/components/metadata_details.tsx index 3bf492d398f2cf..7ca69dd56251d3 100644 --- a/x-pack/plugins/infra/public/pages/metrics/components/metadata_details.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/metadata_details.tsx @@ -8,8 +8,8 @@ import React, { useContext, useState, useCallback, useMemo } from 'react'; import { EuiButtonIcon, EuiFlexGrid, EuiFlexItem, EuiTitle, EuiText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { get } from 'lodash'; -import { InfraMetadata } from '../../../../common/http_api'; -import { euiStyled } from '../../../../../observability/public'; +import { InfraMetadata } from '../../../../../common/http_api'; +import { euiStyled } from '../../../../../../observability/public'; import { MetadataContext } from '../containers/metadata_context'; interface FieldDef { diff --git a/x-pack/plugins/infra/public/pages/metrics/components/node_details_page.tsx b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/node_details_page.tsx similarity index 90% rename from x-pack/plugins/infra/public/pages/metrics/components/node_details_page.tsx rename to x-pack/plugins/infra/public/pages/metrics/metric_detail/components/node_details_page.tsx index dd2a5f2bdb39e6..0d0bc8c82397e8 100644 --- a/x-pack/plugins/infra/public/pages/metrics/components/node_details_page.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/node_details_page.tsx @@ -13,19 +13,19 @@ import { EuiHideFor, EuiTitle, } from '@elastic/eui'; -import { InfraTimerangeInput } from '../../../../common/http_api/snapshot_api'; -import { InventoryMetric, InventoryItemType } from '../../../../common/inventory_models/types'; -import { useNodeDetails } from '../../../containers/node_details/use_node_details'; +import { InfraTimerangeInput } from '../../../../../common/http_api/snapshot_api'; +import { InventoryMetric, InventoryItemType } from '../../../../../common/inventory_models/types'; +import { useNodeDetails } from '../hooks/use_node_details'; import { MetricsSideNav } from './side_nav'; -import { AutoSizer } from '../../../components/auto_sizer'; +import { AutoSizer } from '../../../../components/auto_sizer'; import { MetricsTimeControls } from './time_controls'; import { SideNavContext, NavItem } from '../lib/side_nav_context'; import { PageBody } from './page_body'; -import { euiStyled } from '../../../../../observability/public'; +import { euiStyled } from '../../../../../../observability/public'; import { MetricsTimeInput } from '../hooks/use_metrics_time'; -import { InfraMetadata } from '../../../../common/http_api/metadata_api'; +import { InfraMetadata } from '../../../../../common/http_api/metadata_api'; import { PageError } from './page_error'; -import { MetadataContext } from '../../../pages/metrics/containers/metadata_context'; +import { MetadataContext } from '../containers/metadata_context'; interface Props { name: string; diff --git a/x-pack/plugins/infra/public/pages/metrics/components/page_body.tsx b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/page_body.tsx similarity index 82% rename from x-pack/plugins/infra/public/pages/metrics/components/page_body.tsx rename to x-pack/plugins/infra/public/pages/metrics/metric_detail/components/page_body.tsx index e651d6b92d9811..68166a6e53bfda 100644 --- a/x-pack/plugins/infra/public/pages/metrics/components/page_body.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/page_body.tsx @@ -6,13 +6,13 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -import { findLayout } from '../../../../common/inventory_models/layouts'; -import { InventoryItemType } from '../../../../common/inventory_models/types'; +import { findLayout } from '../../../../../common/inventory_models/layouts'; +import { InventoryItemType } from '../../../../../common/inventory_models/types'; import { MetricsTimeInput } from '../hooks/use_metrics_time'; -import { InfraLoadingPanel } from '../../../components/loading'; -import { NoData } from '../../../components/empty_states'; -import { NodeDetailsMetricData } from '../../../../common/http_api/node_details_api'; +import { InfraLoadingPanel } from '../../../../components/loading'; +import { NoData } from '../../../../components/empty_states'; +import { NodeDetailsMetricData } from '../../../../../common/http_api/node_details_api'; interface Props { loading: boolean; diff --git a/x-pack/plugins/infra/public/pages/metrics/components/page_error.tsx b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/page_error.tsx similarity index 90% rename from x-pack/plugins/infra/public/pages/metrics/components/page_error.tsx rename to x-pack/plugins/infra/public/pages/metrics/metric_detail/components/page_error.tsx index e54cdcd151f6fc..bda2a5941e0230 100644 --- a/x-pack/plugins/infra/public/pages/metrics/components/page_error.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/page_error.tsx @@ -10,8 +10,8 @@ import { i18n } from '@kbn/i18n'; import { IHttpFetchError } from 'src/core/public'; import { InvalidNodeError } from './invalid_node'; // import { InfraMetricsErrorCodes } from '../../../../common/errors'; -import { DocumentTitle } from '../../../components/document_title'; -import { ErrorPageBody } from '../../error'; +import { DocumentTitle } from '../../../../components/document_title'; +import { ErrorPageBody } from '../../../error'; interface Props { name: string; diff --git a/x-pack/plugins/infra/public/pages/metrics/components/section.tsx b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/section.tsx similarity index 100% rename from x-pack/plugins/infra/public/pages/metrics/components/section.tsx rename to x-pack/plugins/infra/public/pages/metrics/metric_detail/components/section.tsx diff --git a/x-pack/plugins/infra/public/pages/metrics/components/series_chart.tsx b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/series_chart.tsx similarity index 93% rename from x-pack/plugins/infra/public/pages/metrics/components/series_chart.tsx rename to x-pack/plugins/infra/public/pages/metrics/metric_detail/components/series_chart.tsx index 849a5b89221650..0d7716ad3cc669 100644 --- a/x-pack/plugins/infra/public/pages/metrics/components/series_chart.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/series_chart.tsx @@ -13,8 +13,8 @@ import { BarSeriesStyle, AreaSeriesStyle, } from '@elastic/charts'; -import { InfraDataSeries } from '../../../graphql/types'; -import { InventoryVisType } from '../../../../common/inventory_models/types'; +import { InfraDataSeries } from '../../../../graphql/types'; +import { InventoryVisType } from '../../../../../common/inventory_models/types'; interface Props { id: string; diff --git a/x-pack/plugins/infra/public/pages/metrics/components/side_nav.tsx b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/side_nav.tsx similarity index 95% rename from x-pack/plugins/infra/public/pages/metrics/components/side_nav.tsx rename to x-pack/plugins/infra/public/pages/metrics/metric_detail/components/side_nav.tsx index 94f97c7f45e61f..1cba3366acbbbf 100644 --- a/x-pack/plugins/infra/public/pages/metrics/components/side_nav.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/side_nav.tsx @@ -6,7 +6,7 @@ import { EuiHideFor, EuiPageSideBar, EuiShowFor, EuiSideNav } from '@elastic/eui'; import React, { useState, useCallback } from 'react'; -import { euiStyled } from '../../../../../observability/public'; +import { euiStyled } from '../../../../../../observability/public'; import { NavItem } from '../lib/side_nav_context'; interface Props { diff --git a/x-pack/plugins/infra/public/pages/metrics/components/sub_section.tsx b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/sub_section.tsx similarity index 94% rename from x-pack/plugins/infra/public/pages/metrics/components/sub_section.tsx rename to x-pack/plugins/infra/public/pages/metrics/metric_detail/components/sub_section.tsx index 325d5102931354..7b269adc96638b 100644 --- a/x-pack/plugins/infra/public/pages/metrics/components/sub_section.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/sub_section.tsx @@ -6,7 +6,7 @@ import React, { isValidElement, cloneElement, FunctionComponent, Children, useMemo } from 'react'; import { EuiTitle } from '@elastic/eui'; -import { InventoryMetric } from '../../../../common/inventory_models/types'; +import { InventoryMetric } from '../../../../../common/inventory_models/types'; import { LayoutProps } from '../types'; type SubSectionProps = LayoutProps & { diff --git a/x-pack/plugins/infra/public/pages/metrics/components/time_controls.test.tsx b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/time_controls.test.tsx similarity index 96% rename from x-pack/plugins/infra/public/pages/metrics/components/time_controls.test.tsx rename to x-pack/plugins/infra/public/pages/metrics/metric_detail/components/time_controls.test.tsx index 02ba506e8abe14..83f5187f8a46c0 100644 --- a/x-pack/plugins/infra/public/pages/metrics/components/time_controls.test.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/time_controls.test.tsx @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -jest.mock('../../../utils/use_kibana_ui_setting', () => ({ +jest.mock('../../../../utils/use_kibana_ui_setting', () => ({ _esModule: true, useKibanaUiSetting: jest.fn(() => [ [ diff --git a/x-pack/plugins/infra/public/pages/metrics/components/time_controls.tsx b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/time_controls.tsx similarity index 91% rename from x-pack/plugins/infra/public/pages/metrics/components/time_controls.tsx rename to x-pack/plugins/infra/public/pages/metrics/metric_detail/components/time_controls.tsx index cdbdc9bb7ecdb5..ef6486eac0fdb1 100644 --- a/x-pack/plugins/infra/public/pages/metrics/components/time_controls.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/time_controls.tsx @@ -6,10 +6,10 @@ import { EuiSuperDatePicker, OnRefreshChangeProps, OnTimeChangeProps } from '@elastic/eui'; import React, { useCallback } from 'react'; -import { euiStyled } from '../../../../../observability/public'; +import { euiStyled } from '../../../../../../observability/public'; import { MetricsTimeInput } from '../hooks/use_metrics_time'; -import { useKibanaUiSetting } from '../../../utils/use_kibana_ui_setting'; -import { mapKibanaQuickRangesToDatePickerRanges } from '../../../utils/map_timepicker_quickranges_to_datepicker_ranges'; +import { useKibanaUiSetting } from '../../../../utils/use_kibana_ui_setting'; +import { mapKibanaQuickRangesToDatePickerRanges } from '../../../../utils/map_timepicker_quickranges_to_datepicker_ranges'; interface MetricsTimeControlsProps { currentTimeRange: MetricsTimeInput; diff --git a/x-pack/plugins/infra/public/pages/metrics/containers/metadata_context.ts b/x-pack/plugins/infra/public/pages/metrics/metric_detail/containers/metadata_context.ts similarity index 84% rename from x-pack/plugins/infra/public/pages/metrics/containers/metadata_context.ts rename to x-pack/plugins/infra/public/pages/metrics/metric_detail/containers/metadata_context.ts index 4ecf7fa15548cb..b8995d27d4dbe9 100644 --- a/x-pack/plugins/infra/public/pages/metrics/containers/metadata_context.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/containers/metadata_context.ts @@ -5,5 +5,5 @@ */ import React from 'react'; -import { InfraMetadata } from '../../../../common/http_api'; +import { InfraMetadata } from '../../../../../common/http_api'; export const MetadataContext = React.createContext(null); diff --git a/x-pack/plugins/infra/public/pages/metrics/hooks/metrics_time.test.tsx b/x-pack/plugins/infra/public/pages/metrics/metric_detail/hooks/metrics_time.test.tsx similarity index 100% rename from x-pack/plugins/infra/public/pages/metrics/hooks/metrics_time.test.tsx rename to x-pack/plugins/infra/public/pages/metrics/metric_detail/hooks/metrics_time.test.tsx diff --git a/x-pack/plugins/infra/public/containers/metadata/use_metadata.ts b/x-pack/plugins/infra/public/pages/metrics/metric_detail/hooks/use_metadata.ts similarity index 76% rename from x-pack/plugins/infra/public/containers/metadata/use_metadata.ts rename to x-pack/plugins/infra/public/pages/metrics/metric_detail/hooks/use_metadata.ts index 1ba016195bef40..d2a20d449d89ac 100644 --- a/x-pack/plugins/infra/public/containers/metadata/use_metadata.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/hooks/use_metadata.ts @@ -8,12 +8,12 @@ import { useEffect } from 'react'; import { fold } from 'fp-ts/lib/Either'; import { identity } from 'fp-ts/lib/function'; import { pipe } from 'fp-ts/lib/pipeable'; -import { InfraMetadata, InfraMetadataRT } from '../../../common/http_api/metadata_api'; -import { useHTTPRequest } from '../../hooks/use_http_request'; -import { throwErrors, createPlainError } from '../../../common/runtime_types'; -import { InventoryMetric, InventoryItemType } from '../../../common/inventory_models/types'; -import { getFilteredMetrics } from './lib/get_filtered_metrics'; -import { MetricsTimeInput } from '../../pages/metrics/hooks/use_metrics_time'; +import { InfraMetadata, InfraMetadataRT } from '../../../../../common/http_api/metadata_api'; +import { useHTTPRequest } from '../../../../hooks/use_http_request'; +import { throwErrors, createPlainError } from '../../../../../common/runtime_types'; +import { InventoryMetric, InventoryItemType } from '../../../../../common/inventory_models/types'; +import { getFilteredMetrics } from '../lib/get_filtered_metrics'; +import { MetricsTimeInput } from './use_metrics_time'; export function useMetadata( nodeId: string, diff --git a/x-pack/plugins/infra/public/pages/metrics/hooks/use_metrics_time.ts b/x-pack/plugins/infra/public/pages/metrics/metric_detail/hooks/use_metrics_time.ts similarity index 96% rename from x-pack/plugins/infra/public/pages/metrics/hooks/use_metrics_time.ts rename to x-pack/plugins/infra/public/pages/metrics/metric_detail/hooks/use_metrics_time.ts index 2ed86863535ff7..98803ef2e69c6a 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hooks/use_metrics_time.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/hooks/use_metrics_time.ts @@ -12,8 +12,8 @@ import * as rt from 'io-ts'; import { pipe } from 'fp-ts/lib/pipeable'; import { fold } from 'fp-ts/lib/Either'; import { constant, identity } from 'fp-ts/lib/function'; -import { useUrlState } from '../../../utils/use_url_state'; -import { replaceStateKeyInQueryString } from '../../../utils/url_state'; +import { useUrlState } from '../../../../utils/use_url_state'; +import { replaceStateKeyInQueryString } from '../../../../utils/url_state'; const parseRange = (range: MetricsTimeInput) => { const parsedFrom = dateMath.parse(range.from.toString()); diff --git a/x-pack/plugins/infra/public/containers/node_details/use_node_details.ts b/x-pack/plugins/infra/public/pages/metrics/metric_detail/hooks/use_node_details.ts similarity index 75% rename from x-pack/plugins/infra/public/containers/node_details/use_node_details.ts rename to x-pack/plugins/infra/public/pages/metrics/metric_detail/hooks/use_node_details.ts index 189c48ba1a70c4..3bb6c98c8eac06 100644 --- a/x-pack/plugins/infra/public/containers/node_details/use_node_details.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/hooks/use_node_details.ts @@ -6,14 +6,14 @@ import { fold } from 'fp-ts/lib/Either'; import { identity } from 'fp-ts/lib/function'; import { pipe } from 'fp-ts/lib/pipeable'; -import { throwErrors, createPlainError } from '../../../common/runtime_types'; -import { useHTTPRequest } from '../../hooks/use_http_request'; +import { throwErrors, createPlainError } from '../../../../../common/runtime_types'; +import { useHTTPRequest } from '../../../../hooks/use_http_request'; import { NodeDetailsMetricDataResponseRT, NodeDetailsMetricDataResponse, -} from '../../../common/http_api/node_details_api'; -import { InventoryMetric, InventoryItemType } from '../../../common/inventory_models/types'; -import { InfraTimerangeInput } from '../../../common/http_api/snapshot_api'; +} from '../../../../../common/http_api/node_details_api'; +import { InventoryMetric, InventoryItemType } from '../../../../../common/inventory_models/types'; +import { InfraTimerangeInput } from '../../../../../common/http_api/snapshot_api'; export function useNodeDetails( metrics: InventoryMetric[], diff --git a/x-pack/plugins/infra/public/pages/metrics/metric_detail/index.tsx b/x-pack/plugins/infra/public/pages/metrics/metric_detail/index.tsx new file mode 100644 index 00000000000000..197a735f7fd1f2 --- /dev/null +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/index.tsx @@ -0,0 +1,140 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { i18n } from '@kbn/i18n'; +import React, { useContext, useState } from 'react'; +import { euiStyled, EuiTheme, withTheme } from '../../../../../observability/public'; +import { DocumentTitle } from '../../../components/document_title'; +import { Header } from '../../../components/header'; +import { ColumnarPage, PageContent } from '../../../components/page'; +import { withMetricPageProviders } from './page_providers'; +import { useMetadata } from './hooks/use_metadata'; +import { Source } from '../../../containers/source'; +import { InfraLoadingPanel } from '../../../components/loading'; +import { findInventoryModel } from '../../../../common/inventory_models'; +import { NavItem } from './lib/side_nav_context'; +import { NodeDetailsPage } from './components/node_details_page'; +import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; +import { InventoryItemType } from '../../../../common/inventory_models/types'; +import { useMetricsTimeContext } from './hooks/use_metrics_time'; +import { useLinkProps } from '../../../hooks/use_link_props'; + +const DetailPageContent = euiStyled(PageContent)` + overflow: auto; + background-color: ${props => props.theme.eui.euiColorLightestShade}; +`; + +interface Props { + theme: EuiTheme; + match: { + params: { + type: string; + node: string; + }; + }; +} + +export const MetricDetail = withMetricPageProviders( + withTheme(({ match }: Props) => { + const uiCapabilities = useKibana().services.application?.capabilities; + const nodeId = match.params.node; + const nodeType = match.params.type as InventoryItemType; + const inventoryModel = findInventoryModel(nodeType); + const { sourceId } = useContext(Source.Context); + const { + timeRange, + parsedTimeRange, + setTimeRange, + refreshInterval, + setRefreshInterval, + isAutoReloading, + setAutoReload, + triggerRefresh, + } = useMetricsTimeContext(); + const { + name, + filteredRequiredMetrics, + loading: metadataLoading, + cloudId, + metadata, + } = useMetadata(nodeId, nodeType, inventoryModel.requiredMetrics, sourceId, parsedTimeRange); + + const [sideNav, setSideNav] = useState([]); + + const addNavItem = React.useCallback( + (item: NavItem) => { + if (!sideNav.some(n => n.id === item.id)) { + setSideNav([item, ...sideNav]); + } + }, + [sideNav] + ); + + const metricsLinkProps = useLinkProps({ + app: 'metrics', + pathname: '/', + }); + + const breadcrumbs = [ + { + ...metricsLinkProps, + text: i18n.translate('xpack.infra.header.infrastructureTitle', { + defaultMessage: 'Metrics', + }), + }, + { text: name }, + ]; + + if (metadataLoading && !filteredRequiredMetrics.length) { + return ( + + ); + } + + return ( + +
+ + + {metadata ? ( + + ) : null} + + + ); + }) +); diff --git a/x-pack/plugins/infra/public/containers/metadata/lib/get_filtered_metrics.ts b/x-pack/plugins/infra/public/pages/metrics/metric_detail/lib/get_filtered_metrics.ts similarity index 78% rename from x-pack/plugins/infra/public/containers/metadata/lib/get_filtered_metrics.ts rename to x-pack/plugins/infra/public/pages/metrics/metric_detail/lib/get_filtered_metrics.ts index b485c90700145a..57ff182f01963d 100644 --- a/x-pack/plugins/infra/public/containers/metadata/lib/get_filtered_metrics.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/lib/get_filtered_metrics.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { InfraMetadataFeature } from '../../../../common/http_api/metadata_api'; -import { InventoryMetric } from '../../../../common/inventory_models/types'; -import { metrics } from '../../../../common/inventory_models/metrics'; +import { InfraMetadataFeature } from '../../../../../common/http_api/metadata_api'; +import { InventoryMetric } from '../../../../../common/inventory_models/types'; +import { metrics } from '../../../../../common/inventory_models/metrics'; export const getFilteredMetrics = ( requiredMetrics: InventoryMetric[], diff --git a/x-pack/plugins/infra/public/pages/metrics/lib/side_nav_context.ts b/x-pack/plugins/infra/public/pages/metrics/metric_detail/lib/side_nav_context.ts similarity index 100% rename from x-pack/plugins/infra/public/pages/metrics/lib/side_nav_context.ts rename to x-pack/plugins/infra/public/pages/metrics/metric_detail/lib/side_nav_context.ts diff --git a/x-pack/plugins/infra/public/pages/metrics/page_providers.tsx b/x-pack/plugins/infra/public/pages/metrics/metric_detail/page_providers.tsx similarity index 91% rename from x-pack/plugins/infra/public/pages/metrics/page_providers.tsx rename to x-pack/plugins/infra/public/pages/metrics/metric_detail/page_providers.tsx index d3f10adec06ed7..597977d9d2735d 100644 --- a/x-pack/plugins/infra/public/pages/metrics/page_providers.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/page_providers.tsx @@ -6,7 +6,7 @@ import React from 'react'; -import { Source } from '../../containers/source'; +import { Source } from '../../../containers/source'; import { MetricsTimeProvider } from './hooks/use_metrics_time'; export const withMetricPageProviders = (Component: React.ComponentType) => ( diff --git a/x-pack/plugins/infra/public/pages/metrics/types.ts b/x-pack/plugins/infra/public/pages/metrics/metric_detail/types.ts similarity index 86% rename from x-pack/plugins/infra/public/pages/metrics/types.ts rename to x-pack/plugins/infra/public/pages/metrics/metric_detail/types.ts index 2cc261df289772..3ec57e23a425d2 100644 --- a/x-pack/plugins/infra/public/pages/metrics/types.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/types.ts @@ -5,10 +5,10 @@ */ import rt from 'io-ts'; -import { EuiTheme } from '../../../../observability/public'; -import { InventoryFormatterTypeRT } from '../../../common/inventory_models/types'; +import { EuiTheme } from '../../../../../observability/public'; +import { InventoryFormatterTypeRT } from '../../../../common/inventory_models/types'; import { MetricsTimeInput } from './hooks/use_metrics_time'; -import { NodeDetailsMetricData } from '../../../common/http_api/node_details_api'; +import { NodeDetailsMetricData } from '../../../../common/http_api/node_details_api'; export interface LayoutProps { metrics?: NodeDetailsMetricData[]; diff --git a/x-pack/plugins/infra/public/components/metrics_explorer/aggregation.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/aggregation.tsx similarity index 89% rename from x-pack/plugins/infra/public/components/metrics_explorer/aggregation.tsx rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/aggregation.tsx index 76fa519ab37567..0c0f7b33b3a4a0 100644 --- a/x-pack/plugins/infra/public/components/metrics_explorer/aggregation.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/aggregation.tsx @@ -8,12 +8,12 @@ import { EuiSelect } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React, { useCallback } from 'react'; -import { MetricsExplorerAggregation } from '../../../common/http_api/metrics_explorer'; -import { MetricsExplorerOptions } from '../../containers/metrics_explorer/use_metrics_explorer_options'; +import { MetricsExplorerAggregation } from '../../../../../common/http_api/metrics_explorer'; +import { MetricsExplorerOptions } from '../hooks/use_metrics_explorer_options'; import { metricsExplorerAggregationRT, METRIC_EXPLORER_AGGREGATIONS, -} from '../../../common/http_api/metrics_explorer'; +} from '../../../../../common/http_api/metrics_explorer'; interface Props { options: MetricsExplorerOptions; diff --git a/x-pack/plugins/infra/public/components/metrics_explorer/chart.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart.tsx similarity index 92% rename from x-pack/plugins/infra/public/components/metrics_explorer/chart.tsx rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart.tsx index c01452c6e2baf2..471406c396b715 100644 --- a/x-pack/plugins/infra/public/components/metrics_explorer/chart.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart.tsx @@ -9,24 +9,24 @@ import { EuiTitle, EuiToolTip, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { Axis, Chart, niceTimeFormatter, Position, Settings, TooltipValue } from '@elastic/charts'; import { first, last } from 'lodash'; import moment from 'moment'; -import { MetricsExplorerSeries } from '../../../common/http_api/metrics_explorer'; +import { MetricsExplorerSeries } from '../../../../../common/http_api/metrics_explorer'; import { MetricsExplorerOptions, MetricsExplorerTimeOptions, MetricsExplorerYAxisMode, MetricsExplorerChartOptions, -} from '../../containers/metrics_explorer/use_metrics_explorer_options'; -import { euiStyled } from '../../../../observability/public'; +} from '../hooks/use_metrics_explorer_options'; +import { euiStyled } from '../../../../../../observability/public'; import { createFormatterForMetric } from './helpers/create_formatter_for_metric'; import { MetricExplorerSeriesChart } from './series_chart'; import { MetricsExplorerChartContextMenu } from './chart_context_menu'; -import { SourceQuery } from '../../graphql/types'; +import { SourceQuery } from '../../../../graphql/types'; import { MetricsExplorerEmptyChart } from './empty_chart'; import { MetricsExplorerNoMetrics } from './no_metrics'; import { getChartTheme } from './helpers/get_chart_theme'; -import { useKibanaUiSetting } from '../../utils/use_kibana_ui_setting'; +import { useKibanaUiSetting } from '../../../../utils/use_kibana_ui_setting'; import { calculateDomain } from './helpers/calculate_domain'; -import { useKibana, useUiSetting } from '../../../../../../src/plugins/kibana_react/public'; +import { useKibana, useUiSetting } from '../../../../../../../../src/plugins/kibana_react/public'; interface Props { title?: string | null; diff --git a/x-pack/plugins/infra/public/components/metrics_explorer/chart_context_menu.test.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart_context_menu.test.tsx similarity index 96% rename from x-pack/plugins/infra/public/components/metrics_explorer/chart_context_menu.test.tsx rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart_context_menu.test.tsx index 8ffef269a42ea1..5c0abb8fd845f2 100644 --- a/x-pack/plugins/infra/public/components/metrics_explorer/chart_context_menu.test.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart_context_menu.test.tsx @@ -7,9 +7,14 @@ import React from 'react'; import { MetricsExplorerChartContextMenu, createNodeDetailLink, Props } from './chart_context_menu'; import { ReactWrapper, mount } from 'enzyme'; -import { options, source, timeRange, chartOptions } from '../../utils/fixtures/metrics_explorer'; +import { + options, + source, + timeRange, + chartOptions, +} from '../../../../utils/fixtures/metrics_explorer'; import { Capabilities } from 'src/core/public'; -import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; +import { KibanaContextProvider } from '../../../../../../../../src/plugins/kibana_react/public'; import { coreMock } from 'src/core/public/mocks'; const coreStartMock = coreMock.createStart(); diff --git a/x-pack/plugins/infra/public/components/metrics_explorer/chart_context_menu.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart_context_menu.tsx similarity index 91% rename from x-pack/plugins/infra/public/components/metrics_explorer/chart_context_menu.tsx rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart_context_menu.tsx index 75a04cbe9799e5..31086a21ca13f8 100644 --- a/x-pack/plugins/infra/public/components/metrics_explorer/chart_context_menu.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart_context_menu.tsx @@ -14,18 +14,18 @@ import { } from '@elastic/eui'; import DateMath from '@elastic/datemath'; import { Capabilities } from 'src/core/public'; -import { MetricsExplorerSeries } from '../../../common/http_api/metrics_explorer'; +import { AlertFlyout } from '../../../../components/alerting/metrics/alert_flyout'; +import { MetricsExplorerSeries } from '../../../../../common/http_api/metrics_explorer'; import { MetricsExplorerOptions, MetricsExplorerTimeOptions, MetricsExplorerChartOptions, -} from '../../containers/metrics_explorer/use_metrics_explorer_options'; +} from '../hooks/use_metrics_explorer_options'; import { createTSVBLink } from './helpers/create_tsvb_link'; -import { getNodeDetailUrl } from '../../pages/link_to/redirect_to_node_detail'; -import { SourceConfiguration } from '../../utils/source_configuration'; -import { InventoryItemType } from '../../../common/inventory_models/types'; -import { AlertFlyout } from '../alerting/metrics/alert_flyout'; -import { useLinkProps } from '../../hooks/use_link_props'; +import { getNodeDetailUrl } from '../../../link_to/redirect_to_node_detail'; +import { SourceConfiguration } from '../../../../utils/source_configuration'; +import { InventoryItemType } from '../../../../../common/inventory_models/types'; +import { useLinkProps } from '../../../../hooks/use_link_props'; export interface Props { options: MetricsExplorerOptions; diff --git a/x-pack/plugins/infra/public/components/metrics_explorer/chart_options.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart_options.tsx similarity index 98% rename from x-pack/plugins/infra/public/components/metrics_explorer/chart_options.tsx rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart_options.tsx index 657c4cea30f3ab..ba28075ededb6e 100644 --- a/x-pack/plugins/infra/public/components/metrics_explorer/chart_options.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart_options.tsx @@ -19,7 +19,7 @@ import { MetricsExplorerChartOptions as ChartOptions, MetricsExplorerYAxisMode, MetricsExplorerChartType, -} from '../../containers/metrics_explorer/use_metrics_explorer_options'; +} from '../hooks/use_metrics_explorer_options'; interface Props { chartOptions: ChartOptions; diff --git a/x-pack/plugins/infra/public/components/metrics_explorer/charts.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/charts.tsx similarity index 92% rename from x-pack/plugins/infra/public/components/metrics_explorer/charts.tsx rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/charts.tsx index 3b639ee5e953a1..1e216a4227f9aa 100644 --- a/x-pack/plugins/infra/public/components/metrics_explorer/charts.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/charts.tsx @@ -8,16 +8,16 @@ import { EuiButton, EuiFlexGrid, EuiFlexItem, EuiText, EuiHorizontalRule } from import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import React from 'react'; -import { MetricsExplorerResponse } from '../../../common/http_api/metrics_explorer'; +import { MetricsExplorerResponse } from '../../../../../common/http_api/metrics_explorer'; import { MetricsExplorerOptions, MetricsExplorerTimeOptions, MetricsExplorerChartOptions, -} from '../../containers/metrics_explorer/use_metrics_explorer_options'; -import { InfraLoadingPanel } from '../loading'; -import { NoData } from '../empty_states/no_data'; +} from '../hooks/use_metrics_explorer_options'; +import { InfraLoadingPanel } from '../../../../components/loading'; +import { NoData } from '../../../../components/empty_states/no_data'; import { MetricsExplorerChart } from './chart'; -import { SourceQuery } from '../../graphql/types'; +import { SourceQuery } from '../../../../graphql/types'; interface Props { loading: boolean; diff --git a/x-pack/plugins/infra/public/components/metrics_explorer/empty_chart.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/empty_chart.tsx similarity index 100% rename from x-pack/plugins/infra/public/components/metrics_explorer/empty_chart.tsx rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/empty_chart.tsx diff --git a/x-pack/plugins/infra/public/components/metrics_explorer/group_by.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/group_by.tsx similarity index 72% rename from x-pack/plugins/infra/public/components/metrics_explorer/group_by.tsx rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/group_by.tsx index 750894fd0188bc..bfe8ddb2e08291 100644 --- a/x-pack/plugins/infra/public/components/metrics_explorer/group_by.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/group_by.tsx @@ -9,8 +9,7 @@ import { i18n } from '@kbn/i18n'; import React, { useCallback } from 'react'; import { IFieldType } from 'src/plugins/data/public'; -import { MetricsExplorerOptions } from '../../containers/metrics_explorer/use_metrics_explorer_options'; -import { isDisplayable } from '../../utils/is_displayable'; +import { MetricsExplorerOptions } from '../hooks/use_metrics_explorer_options'; interface Props { options: MetricsExplorerOptions; @@ -27,18 +26,6 @@ export const MetricsExplorerGroupBy = ({ options, onChange, fields }: Props) => [onChange] ); - const metricPrefixes = options.metrics - .map( - metric => - (metric.field && - metric.field - .split(/\./) - .slice(0, 2) - .join('.')) || - null - ) - .filter(metric => metric) as string[]; - return ( singleSelection={true} selectedOptions={(options.groupBy && [{ label: options.groupBy }]) || []} options={fields - .filter(f => isDisplayable(f, metricPrefixes) && f.aggregatable && f.type === 'string') + .filter(f => f.aggregatable && f.type === 'string') .map(f => ({ label: f.name }))} onChange={handleChange} isClearable={true} diff --git a/x-pack/plugins/infra/public/components/metrics_explorer/helpers/calculate_domain.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/calculate_domain.ts similarity index 87% rename from x-pack/plugins/infra/public/components/metrics_explorer/helpers/calculate_domain.ts rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/calculate_domain.ts index 90569854b833b3..811486d355f2e5 100644 --- a/x-pack/plugins/infra/public/components/metrics_explorer/helpers/calculate_domain.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/calculate_domain.ts @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ import { min, max, sum, isNumber } from 'lodash'; -import { MetricsExplorerSeries } from '../../../../common/http_api/metrics_explorer'; -import { MetricsExplorerOptionsMetric } from '../../../containers/metrics_explorer/use_metrics_explorer_options'; +import { MetricsExplorerSeries } from '../../../../../../common/http_api/metrics_explorer'; +import { MetricsExplorerOptionsMetric } from '../../hooks/use_metrics_explorer_options'; const getMin = (values: Array) => { const minValue = min(values); diff --git a/x-pack/plugins/infra/public/components/metrics_explorer/helpers/calculate_domian.test.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/calculate_domian.test.ts similarity index 85% rename from x-pack/plugins/infra/public/components/metrics_explorer/helpers/calculate_domian.test.ts rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/calculate_domian.test.ts index 4b45534d41db82..f94c6b6156ae4b 100644 --- a/x-pack/plugins/infra/public/components/metrics_explorer/helpers/calculate_domian.test.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/calculate_domian.test.ts @@ -5,9 +5,9 @@ */ import { calculateDomain } from './calculate_domain'; -import { MetricsExplorerSeries } from '../../../../common/http_api/metrics_explorer'; -import { MetricsExplorerOptionsMetric } from '../../../containers/metrics_explorer/use_metrics_explorer_options'; -import { MetricsExplorerColor } from '../../../../common/color_palette'; +import { MetricsExplorerSeries } from '../../../../../../common/http_api/metrics_explorer'; +import { MetricsExplorerOptionsMetric } from '../../hooks/use_metrics_explorer_options'; +import { MetricsExplorerColor } from '../../../../../../common/color_palette'; describe('calculateDomain()', () => { const series: MetricsExplorerSeries = { id: 'test-01', diff --git a/x-pack/plugins/infra/public/components/metrics_explorer/helpers/create_formatter_for_metric.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_formatter_for_metric.ts similarity index 76% rename from x-pack/plugins/infra/public/components/metrics_explorer/helpers/create_formatter_for_metric.ts rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_formatter_for_metric.ts index 33ec2ce2715a3c..d07a6b45f02bef 100644 --- a/x-pack/plugins/infra/public/components/metrics_explorer/helpers/create_formatter_for_metric.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_formatter_for_metric.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { MetricsExplorerMetric } from '../../../../common/http_api/metrics_explorer'; -import { createFormatter } from '../../../utils/formatters'; -import { InfraFormatterType } from '../../../lib/lib'; +import { MetricsExplorerMetric } from '../../../../../../common/http_api/metrics_explorer'; +import { createFormatter } from '../../../../../utils/formatters'; +import { InfraFormatterType } from '../../../../../lib/lib'; import { metricToFormat } from './metric_to_format'; export const createFormatterForMetric = (metric?: MetricsExplorerMetric) => { if (metric && metric.field) { diff --git a/x-pack/plugins/infra/public/components/metrics_explorer/helpers/create_formatter_for_metrics.test.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_formatter_for_metrics.test.ts similarity index 94% rename from x-pack/plugins/infra/public/components/metrics_explorer/helpers/create_formatter_for_metrics.test.ts rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_formatter_for_metrics.test.ts index ec41e90e441a44..e039d5d4b3eeb4 100644 --- a/x-pack/plugins/infra/public/components/metrics_explorer/helpers/create_formatter_for_metrics.test.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_formatter_for_metrics.test.ts @@ -5,7 +5,7 @@ */ import { createFormatterForMetric } from './create_formatter_for_metric'; -import { MetricsExplorerMetric } from '../../../../common/http_api/metrics_explorer'; +import { MetricsExplorerMetric } from '../../../../../../common/http_api/metrics_explorer'; describe('createFormatterForMetric()', () => { it('should just work for count', () => { diff --git a/x-pack/plugins/infra/public/components/metrics_explorer/helpers/create_metric_label.test.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_metric_label.test.ts similarity index 88% rename from x-pack/plugins/infra/public/components/metrics_explorer/helpers/create_metric_label.test.ts rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_metric_label.test.ts index cbf6904d246c70..367c472f414e42 100644 --- a/x-pack/plugins/infra/public/components/metrics_explorer/helpers/create_metric_label.test.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_metric_label.test.ts @@ -5,7 +5,7 @@ */ import { createMetricLabel } from './create_metric_label'; -import { MetricsExplorerMetric } from '../../../../common/http_api/metrics_explorer'; +import { MetricsExplorerMetric } from '../../../../../../common/http_api/metrics_explorer'; describe('createMetricLabel()', () => { it('should work with metrics with fields', () => { diff --git a/x-pack/plugins/infra/public/components/metrics_explorer/helpers/create_metric_label.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_metric_label.ts similarity index 80% rename from x-pack/plugins/infra/public/components/metrics_explorer/helpers/create_metric_label.ts rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_metric_label.ts index b6453a81317b13..1607302a6259a5 100644 --- a/x-pack/plugins/infra/public/components/metrics_explorer/helpers/create_metric_label.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_metric_label.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { MetricsExplorerMetric } from '../../../../common/http_api/metrics_explorer'; +import { MetricsExplorerMetric } from '../../../../../../common/http_api/metrics_explorer'; export const createMetricLabel = (metric: MetricsExplorerMetric) => { return `${metric.aggregation}(${metric.field || ''})`; diff --git a/x-pack/plugins/infra/public/components/metrics_explorer/helpers/create_tsvb_link.test.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_tsvb_link.test.ts similarity index 97% rename from x-pack/plugins/infra/public/components/metrics_explorer/helpers/create_tsvb_link.test.ts rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_tsvb_link.test.ts index 05637642b8dd9e..47bb4c8c57716d 100644 --- a/x-pack/plugins/infra/public/components/metrics_explorer/helpers/create_tsvb_link.test.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_tsvb_link.test.ts @@ -5,14 +5,19 @@ */ import { createTSVBLink, createFilterFromOptions } from './create_tsvb_link'; -import { source, options, timeRange, chartOptions } from '../../../utils/fixtures/metrics_explorer'; +import { + source, + options, + timeRange, + chartOptions, +} from '../../../../../utils/fixtures/metrics_explorer'; import uuid from 'uuid'; import { OutputBuffer } from 'uuid/interfaces'; import { MetricsExplorerYAxisMode, MetricsExplorerChartType, -} from '../../../containers/metrics_explorer/use_metrics_explorer_options'; -import { MetricsExplorerOptions } from '../../../containers/metrics_explorer/use_metrics_explorer_options'; +} from '../../hooks/use_metrics_explorer_options'; +import { MetricsExplorerOptions } from '../../hooks/use_metrics_explorer_options'; jest.mock('uuid'); const mockedUuid = uuid as jest.Mocked; diff --git a/x-pack/plugins/infra/public/components/metrics_explorer/helpers/create_tsvb_link.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_tsvb_link.ts similarity index 91% rename from x-pack/plugins/infra/public/components/metrics_explorer/helpers/create_tsvb_link.ts rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_tsvb_link.ts index 20706f563ec637..559422584f579a 100644 --- a/x-pack/plugins/infra/public/components/metrics_explorer/helpers/create_tsvb_link.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_tsvb_link.ts @@ -7,8 +7,8 @@ import { encode } from 'rison-node'; import uuid from 'uuid'; import { set } from 'lodash'; -import { colorTransformer, MetricsExplorerColor } from '../../../../common/color_palette'; -import { MetricsExplorerSeries } from '../../../../common/http_api/metrics_explorer'; +import { colorTransformer, MetricsExplorerColor } from '../../../../../../common/color_palette'; +import { MetricsExplorerSeries } from '../../../../../../common/http_api/metrics_explorer'; import { MetricsExplorerOptions, MetricsExplorerOptionsMetric, @@ -16,12 +16,12 @@ import { MetricsExplorerChartOptions, MetricsExplorerYAxisMode, MetricsExplorerChartType, -} from '../../../containers/metrics_explorer/use_metrics_explorer_options'; +} from '../../hooks/use_metrics_explorer_options'; import { metricToFormat } from './metric_to_format'; -import { InfraFormatterType } from '../../../lib/lib'; -import { SourceQuery } from '../../../graphql/types'; +import { InfraFormatterType } from '../../../../../lib/lib'; +import { SourceQuery } from '../../../../../graphql/types'; import { createMetricLabel } from './create_metric_label'; -import { LinkDescriptor } from '../../../hooks/use_link_props'; +import { LinkDescriptor } from '../../../../../hooks/use_link_props'; export const metricsExplorerMetricToTSVBMetric = (metric: MetricsExplorerOptionsMetric) => { if (metric.aggregation === 'rate') { diff --git a/x-pack/plugins/infra/public/components/metrics_explorer/helpers/get_chart_theme.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/get_chart_theme.ts similarity index 100% rename from x-pack/plugins/infra/public/components/metrics_explorer/helpers/get_chart_theme.ts rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/get_chart_theme.ts diff --git a/x-pack/plugins/infra/public/components/metrics_explorer/helpers/metric_to_format.test.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/metric_to_format.test.ts similarity index 90% rename from x-pack/plugins/infra/public/components/metrics_explorer/helpers/metric_to_format.test.ts rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/metric_to_format.test.ts index 4cb27b4fb65c3e..6b27627a9fb5b2 100644 --- a/x-pack/plugins/infra/public/components/metrics_explorer/helpers/metric_to_format.test.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/metric_to_format.test.ts @@ -5,8 +5,8 @@ */ import { metricToFormat } from './metric_to_format'; -import { MetricsExplorerMetric } from '../../../../common/http_api/metrics_explorer'; -import { InfraFormatterType } from '../../../lib/lib'; +import { MetricsExplorerMetric } from '../../../../../../common/http_api/metrics_explorer'; +import { InfraFormatterType } from '../../../../../lib/lib'; describe('metricToFormat()', () => { it('should just work for numeric metrics', () => { const metric: MetricsExplorerMetric = { aggregation: 'avg', field: 'system.load.1' }; diff --git a/x-pack/plugins/infra/public/components/metrics_explorer/helpers/metric_to_format.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/metric_to_format.ts similarity index 82% rename from x-pack/plugins/infra/public/components/metrics_explorer/helpers/metric_to_format.ts rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/metric_to_format.ts index 63272c86a5dc79..1dbbf97a32217b 100644 --- a/x-pack/plugins/infra/public/components/metrics_explorer/helpers/metric_to_format.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/metric_to_format.ts @@ -5,8 +5,8 @@ */ import { last } from 'lodash'; -import { MetricsExplorerMetric } from '../../../../common/http_api/metrics_explorer'; -import { InfraFormatterType } from '../../../lib/lib'; +import { MetricsExplorerMetric } from '../../../../../../common/http_api/metrics_explorer'; +import { InfraFormatterType } from '../../../../../lib/lib'; export const metricToFormat = (metric?: MetricsExplorerMetric) => { if (metric && metric.field) { const suffix = last(metric.field.split(/\./)); diff --git a/x-pack/plugins/infra/public/components/metrics_explorer/kuery_bar.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx similarity index 84% rename from x-pack/plugins/infra/public/components/metrics_explorer/kuery_bar.tsx rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx index dcc160d05b6ad9..e9826e1ff39552 100644 --- a/x-pack/plugins/infra/public/components/metrics_explorer/kuery_bar.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx @@ -7,10 +7,9 @@ import { i18n } from '@kbn/i18n'; import React, { useEffect, useState } from 'react'; -import { WithKueryAutocompletion } from '../../containers/with_kuery_autocompletion'; -import { AutocompleteField } from '../autocomplete_field'; -import { isDisplayable } from '../../utils/is_displayable'; -import { esKuery, IIndexPattern } from '../../../../../../src/plugins/data/public'; +import { WithKueryAutocompletion } from '../../../../containers/with_kuery_autocompletion'; +import { AutocompleteField } from '../../../../components/autocomplete_field'; +import { esKuery, IIndexPattern } from '../../../../../../../../src/plugins/data/public'; interface Props { derivedIndexPattern: IIndexPattern; @@ -51,7 +50,7 @@ export const MetricsExplorerKueryBar = ({ const filteredDerivedIndexPattern = { ...derivedIndexPattern, - fields: derivedIndexPattern.fields.filter(field => isDisplayable(field)), + fields: derivedIndexPattern.fields, }; const defaultPlaceholder = i18n.translate( diff --git a/x-pack/plugins/infra/public/components/metrics_explorer/metrics.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/metrics.tsx similarity index 85% rename from x-pack/plugins/infra/public/components/metrics_explorer/metrics.tsx rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/metrics.tsx index 79d4122733c551..612735e2ba772e 100644 --- a/x-pack/plugins/infra/public/components/metrics_explorer/metrics.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/metrics.tsx @@ -9,10 +9,9 @@ import { i18n } from '@kbn/i18n'; import React, { useCallback, useState } from 'react'; import { IFieldType } from 'src/plugins/data/public'; -import { colorTransformer, MetricsExplorerColor } from '../../../common/color_palette'; -import { MetricsExplorerMetric } from '../../../common/http_api/metrics_explorer'; -import { MetricsExplorerOptions } from '../../containers/metrics_explorer/use_metrics_explorer_options'; -import { isDisplayable } from '../../utils/is_displayable'; +import { colorTransformer, MetricsExplorerColor } from '../../../../../common/color_palette'; +import { MetricsExplorerMetric } from '../../../../../common/http_api/metrics_explorer'; +import { MetricsExplorerOptions } from '../hooks/use_metrics_explorer_options'; interface Props { autoFocus?: boolean; @@ -54,9 +53,7 @@ export const MetricsExplorerMetrics = ({ options, onChange, fields, autoFocus = [onChange, options.aggregation, colors] ); - const comboOptions = fields - .filter(field => isDisplayable(field)) - .map(field => ({ label: field.name, value: field.name })); + const comboOptions = fields.map(field => ({ label: field.name, value: field.name })); const selectedOptions = options.metrics .filter(m => m.aggregation !== 'count') .map(metric => ({ diff --git a/x-pack/plugins/infra/public/components/metrics_explorer/no_metrics.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/no_metrics.tsx similarity index 100% rename from x-pack/plugins/infra/public/components/metrics_explorer/no_metrics.tsx rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/no_metrics.tsx diff --git a/x-pack/plugins/infra/public/components/metrics_explorer/series_chart.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/series_chart.tsx similarity index 93% rename from x-pack/plugins/infra/public/components/metrics_explorer/series_chart.tsx rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/series_chart.tsx index ed7a994dd2bbec..ad7ce83539526a 100644 --- a/x-pack/plugins/infra/public/components/metrics_explorer/series_chart.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/series_chart.tsx @@ -13,13 +13,13 @@ import { AreaSeriesStyle, BarSeriesStyle, } from '@elastic/charts'; -import { MetricsExplorerSeries } from '../../../common/http_api/metrics_explorer'; -import { colorTransformer, MetricsExplorerColor } from '../../../common/color_palette'; +import { MetricsExplorerSeries } from '../../../../../common/http_api/metrics_explorer'; +import { colorTransformer, MetricsExplorerColor } from '../../../../../common/color_palette'; import { createMetricLabel } from './helpers/create_metric_label'; import { MetricsExplorerOptionsMetric, MetricsExplorerChartType, -} from '../../containers/metrics_explorer/use_metrics_explorer_options'; +} from '../hooks/use_metrics_explorer_options'; interface Props { metric: MetricsExplorerOptionsMetric; diff --git a/x-pack/plugins/infra/public/components/metrics_explorer/toolbar.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/toolbar.tsx similarity index 88% rename from x-pack/plugins/infra/public/components/metrics_explorer/toolbar.tsx rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/toolbar.tsx index 0fbb0b6acad176..81971bd31a9739 100644 --- a/x-pack/plugins/infra/public/components/metrics_explorer/toolbar.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/toolbar.tsx @@ -11,23 +11,23 @@ import { IIndexPattern } from 'src/plugins/data/public'; import { MetricsExplorerMetric, MetricsExplorerAggregation, -} from '../../../common/http_api/metrics_explorer'; +} from '../../../../../common/http_api/metrics_explorer'; import { MetricsExplorerOptions, MetricsExplorerTimeOptions, MetricsExplorerChartOptions, -} from '../../containers/metrics_explorer/use_metrics_explorer_options'; -import { Toolbar } from '../eui/toolbar'; +} from '../hooks/use_metrics_explorer_options'; +import { Toolbar } from '../../../../components/eui/toolbar'; import { MetricsExplorerKueryBar } from './kuery_bar'; import { MetricsExplorerMetrics } from './metrics'; import { MetricsExplorerGroupBy } from './group_by'; import { MetricsExplorerAggregationPicker } from './aggregation'; import { MetricsExplorerChartOptions as MetricsExplorerChartOptionsComponent } from './chart_options'; -import { SavedViewsToolbarControls } from '../saved_views/toolbar_control'; -import { MetricExplorerViewState } from '../../pages/infrastructure/metrics_explorer/use_metric_explorer_state'; -import { metricsExplorerViewSavedObjectType } from '../../../common/saved_objects/metrics_explorer_view'; -import { useKibanaUiSetting } from '../../utils/use_kibana_ui_setting'; -import { mapKibanaQuickRangesToDatePickerRanges } from '../../utils/map_timepicker_quickranges_to_datepicker_ranges'; +import { SavedViewsToolbarControls } from '../../../../components/saved_views/toolbar_control'; +import { MetricExplorerViewState } from '../hooks/use_metric_explorer_state'; +import { metricsExplorerViewSavedObjectType } from '../../../../../common/saved_objects/metrics_explorer_view'; +import { useKibanaUiSetting } from '../../../../utils/use_kibana_ui_setting'; +import { mapKibanaQuickRangesToDatePickerRanges } from '../../../../utils/map_timepicker_quickranges_to_datepicker_ranges'; interface Props { derivedIndexPattern: IIndexPattern; diff --git a/x-pack/plugins/infra/public/pages/infrastructure/metrics_explorer/use_metric_explorer_state.test.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.test.tsx similarity index 96% rename from x-pack/plugins/infra/public/pages/infrastructure/metrics_explorer/use_metric_explorer_state.test.tsx rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.test.tsx index 874ac0987023bd..f0734f76cfacd9 100644 --- a/x-pack/plugins/infra/public/pages/infrastructure/metrics_explorer/use_metric_explorer_state.test.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.test.tsx @@ -6,14 +6,14 @@ import { renderHook, act } from '@testing-library/react-hooks'; import { useMetricsExplorerState } from './use_metric_explorer_state'; -import { MetricsExplorerOptionsContainer } from '../../../containers/metrics_explorer/use_metrics_explorer_options'; +import { MetricsExplorerOptionsContainer } from './use_metrics_explorer_options'; import React from 'react'; import { source, derivedIndexPattern, resp, createSeries, -} from '../../../utils/fixtures/metrics_explorer'; +} from '../../../../utils/fixtures/metrics_explorer'; const renderUseMetricsExplorerStateHook = () => renderHook(props => useMetricsExplorerState(props.source, props.derivedIndexPattern), { @@ -27,7 +27,7 @@ const renderUseMetricsExplorerStateHook = () => const mockedUseMetricsExplorerData = jest.fn(); -jest.mock('../../../containers/metrics_explorer/use_metrics_explorer_data', () => { +jest.mock('./use_metrics_explorer_data', () => { return { useMetricsExplorerData: () => { return mockedUseMetricsExplorerData(); diff --git a/x-pack/plugins/infra/public/pages/infrastructure/metrics_explorer/use_metric_explorer_state.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.ts similarity index 92% rename from x-pack/plugins/infra/public/pages/infrastructure/metrics_explorer/use_metric_explorer_state.ts rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.ts index 88e6d9d800661d..8a9ed901de0b06 100644 --- a/x-pack/plugins/infra/public/pages/infrastructure/metrics_explorer/use_metric_explorer_state.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.ts @@ -9,15 +9,15 @@ import { IIndexPattern } from 'src/plugins/data/public'; import { MetricsExplorerMetric, MetricsExplorerAggregation, -} from '../../../../common/http_api/metrics_explorer'; -import { useMetricsExplorerData } from '../../../containers/metrics_explorer/use_metrics_explorer_data'; +} from '../../../../../common/http_api/metrics_explorer'; +import { useMetricsExplorerData } from './use_metrics_explorer_data'; import { MetricsExplorerOptionsContainer, MetricsExplorerChartOptions, MetricsExplorerTimeOptions, MetricsExplorerOptions, -} from '../../../containers/metrics_explorer/use_metrics_explorer_options'; -import { SourceQuery } from '../../../graphql/types'; +} from './use_metrics_explorer_options'; +import { SourceQuery } from '../../../../graphql/types'; export interface MetricExplorerViewState { chartOptions: MetricsExplorerChartOptions; diff --git a/x-pack/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_data.test.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.test.tsx similarity index 96% rename from x-pack/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_data.test.tsx rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.test.tsx index bbc8778545b4a0..94edab54fb71e9 100644 --- a/x-pack/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_data.test.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { useMetricsExplorerData } from './use_metrics_explorer_data'; import { renderHook } from '@testing-library/react-hooks'; -import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; +import { KibanaContextProvider } from '../../../../../../../../src/plugins/kibana_react/public'; import { options, @@ -17,7 +17,7 @@ import { timeRange, resp, createSeries, -} from '../../utils/fixtures/metrics_explorer'; +} from '../../../../utils/fixtures/metrics_explorer'; const mockedFetch = jest.fn(); @@ -54,7 +54,7 @@ const renderUseMetricsExplorerDataHook = () => { ); }; -jest.mock('../../utils/kuery', () => { +jest.mock('../../../../utils/kuery', () => { return { convertKueryToElasticSearchQuery: (query: string) => query, }; diff --git a/x-pack/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_data.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.ts similarity index 91% rename from x-pack/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_data.ts rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.ts index b32496fbf30a11..93aacb586a5cde 100644 --- a/x-pack/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_data.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.ts @@ -8,15 +8,15 @@ import DateMath from '@elastic/datemath'; import { isEqual } from 'lodash'; import { useEffect, useState } from 'react'; import { IIndexPattern } from 'src/plugins/data/public'; -import { SourceQuery } from '../../../common/graphql/types'; +import { SourceQuery } from '../../../../../common/graphql/types'; import { MetricsExplorerResponse, metricsExplorerResponseRT, -} from '../../../common/http_api/metrics_explorer'; -import { convertKueryToElasticSearchQuery } from '../../utils/kuery'; +} from '../../../../../common/http_api/metrics_explorer'; +import { convertKueryToElasticSearchQuery } from '../../../../utils/kuery'; import { MetricsExplorerOptions, MetricsExplorerTimeOptions } from './use_metrics_explorer_options'; -import { useKibana } from '../../../../../../src/plugins/kibana_react/public'; -import { decodeOrThrow } from '../../../common/runtime_types'; +import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public'; +import { decodeOrThrow } from '../../../../../common/runtime_types'; function isSameOptions(current: MetricsExplorerOptions, next: MetricsExplorerOptions) { return isEqual(current, next); diff --git a/x-pack/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_options.test.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.test.tsx similarity index 100% rename from x-pack/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_options.test.tsx rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.test.tsx diff --git a/x-pack/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_options.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.ts similarity index 96% rename from x-pack/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_options.ts rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.ts index 2b802af8e8c15f..9d124a6af80123 100644 --- a/x-pack/plugins/infra/public/containers/metrics_explorer/use_metrics_explorer_options.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.ts @@ -6,11 +6,11 @@ import createContainer from 'constate'; import { useState, useEffect, Dispatch, SetStateAction } from 'react'; -import { MetricsExplorerColor } from '../../../common/color_palette'; +import { MetricsExplorerColor } from '../../../../../common/color_palette'; import { MetricsExplorerAggregation, MetricsExplorerMetric, -} from '../../../common/http_api/metrics_explorer'; +} from '../../../../../common/http_api/metrics_explorer'; export type MetricsExplorerOptionsMetric = MetricsExplorerMetric & { color?: MetricsExplorerColor; diff --git a/x-pack/plugins/infra/public/pages/infrastructure/metrics_explorer/index.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/index.tsx similarity index 92% rename from x-pack/plugins/infra/public/pages/infrastructure/metrics_explorer/index.tsx rename to x-pack/plugins/infra/public/pages/metrics/metrics_explorer/index.tsx index 0999cea59731ca..a213671e9436eb 100644 --- a/x-pack/plugins/infra/public/pages/infrastructure/metrics_explorer/index.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/index.tsx @@ -9,11 +9,11 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; import { IIndexPattern } from 'src/plugins/data/public'; import { DocumentTitle } from '../../../components/document_title'; -import { MetricsExplorerCharts } from '../../../components/metrics_explorer/charts'; -import { MetricsExplorerToolbar } from '../../../components/metrics_explorer/toolbar'; +import { MetricsExplorerCharts } from './components/charts'; +import { MetricsExplorerToolbar } from './components/toolbar'; import { SourceQuery } from '../../../../common/graphql/types'; import { NoData } from '../../../components/empty_states'; -import { useMetricsExplorerState } from './use_metric_explorer_state'; +import { useMetricsExplorerState } from './hooks/use_metric_explorer_state'; import { useTrackPageview } from '../../../../../observability/public'; interface MetricsExplorerPageProps { diff --git a/x-pack/plugins/infra/public/pages/infrastructure/settings.tsx b/x-pack/plugins/infra/public/pages/metrics/settings.tsx similarity index 100% rename from x-pack/plugins/infra/public/pages/infrastructure/settings.tsx rename to x-pack/plugins/infra/public/pages/metrics/settings.tsx diff --git a/x-pack/plugins/infra/public/routers/metrics_router.tsx b/x-pack/plugins/infra/public/routers/metrics_router.tsx index 7cb9de65e72917..0e427150a46cc6 100644 --- a/x-pack/plugins/infra/public/routers/metrics_router.tsx +++ b/x-pack/plugins/infra/public/routers/metrics_router.tsx @@ -8,12 +8,12 @@ import React from 'react'; import { Route, Router, Switch } from 'react-router-dom'; import { NotFoundPage } from '../pages/404'; -import { InfrastructurePage } from '../pages/infrastructure'; -import { LinkToMetricsPage } from '../pages/link_to'; -import { MetricDetail } from '../pages/metrics'; +import { InfrastructurePage } from '../pages/metrics'; +import { MetricDetail } from '../pages/metrics/metric_detail'; import { RedirectWithQueryParams } from '../utils/redirect_with_query_params'; import { useKibana } from '../../../../../src/plugins/kibana_react/public'; import { AppRouter } from './index'; +import { LinkToMetricsPage } from '../pages/link_to'; export const MetricsRouter: AppRouter = ({ history }) => { const uiCapabilities = useKibana().services.application?.capabilities; diff --git a/x-pack/plugins/infra/public/utils/fixtures/metrics_explorer.ts b/x-pack/plugins/infra/public/utils/fixtures/metrics_explorer.ts index e39d6f785d53e2..15159ad45c7f33 100644 --- a/x-pack/plugins/infra/public/utils/fixtures/metrics_explorer.ts +++ b/x-pack/plugins/infra/public/utils/fixtures/metrics_explorer.ts @@ -14,7 +14,7 @@ import { MetricsExplorerChartType, MetricsExplorerYAxisMode, MetricsExplorerChartOptions, -} from '../../containers/metrics_explorer/use_metrics_explorer_options'; +} from '../../pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options'; export const options: MetricsExplorerOptions = { limit: 3, diff --git a/x-pack/plugins/infra/server/infra_server.ts b/x-pack/plugins/infra/server/infra_server.ts index fb9dd172bf6ede..88b78dfd3e41c3 100644 --- a/x-pack/plugins/infra/server/infra_server.ts +++ b/x-pack/plugins/infra/server/infra_server.ts @@ -29,6 +29,7 @@ import { initLogEntriesItemRoute, } from './routes/log_entries'; import { initInventoryMetaRoute } from './routes/inventory_metadata'; +import { initSourceRoute } from './routes/source'; export const initInfraServer = (libs: InfraBackendLibs) => { const schema = makeExecutableSchema({ @@ -48,6 +49,7 @@ export const initInfraServer = (libs: InfraBackendLibs) => { initGetLogEntryRateRoute(libs); initSnapshotRoute(libs); initNodeDetailsRoute(libs); + initSourceRoute(libs); initValidateLogAnalysisIndicesRoute(libs); initLogEntriesRoute(libs); initLogEntriesHighlightsRoute(libs); diff --git a/x-pack/plugins/infra/server/lib/sources/defaults.ts b/x-pack/plugins/infra/server/lib/sources/defaults.ts index b9ead0d169ee60..6b00f59cca1f41 100644 --- a/x-pack/plugins/infra/server/lib/sources/defaults.ts +++ b/x-pack/plugins/infra/server/lib/sources/defaults.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { InfraSourceConfiguration } from './types'; +import { InfraSourceConfiguration } from '../../../common/http_api/source_api'; export const defaultSourceConfiguration: InfraSourceConfiguration = { name: 'Default', diff --git a/x-pack/plugins/infra/server/lib/sources/index.ts b/x-pack/plugins/infra/server/lib/sources/index.ts index 6837f953ea18ae..9dcbe02bd064bc 100644 --- a/x-pack/plugins/infra/server/lib/sources/index.ts +++ b/x-pack/plugins/infra/server/lib/sources/index.ts @@ -7,4 +7,4 @@ export * from './defaults'; export * from './saved_object_mappings'; export * from './sources'; -export * from './types'; +export * from '../../../common/http_api/source_api'; diff --git a/x-pack/plugins/infra/server/lib/sources/saved_object_mappings.ts b/x-pack/plugins/infra/server/lib/sources/saved_object_mappings.ts index 973a790eeedafd..e5b230373b7ec1 100644 --- a/x-pack/plugins/infra/server/lib/sources/saved_object_mappings.ts +++ b/x-pack/plugins/infra/server/lib/sources/saved_object_mappings.ts @@ -5,7 +5,7 @@ */ import { ElasticsearchMappingOf } from '../../utils/typed_elasticsearch_mappings'; -import { InfraSavedSourceConfiguration } from './types'; +import { InfraSavedSourceConfiguration } from '../../../common/http_api/source_api'; export const infraSourceConfigurationSavedObjectType = 'infrastructure-ui-source'; diff --git a/x-pack/plugins/infra/server/lib/sources/sources.ts b/x-pack/plugins/infra/server/lib/sources/sources.ts index c7ff6c96382043..99e062aa49ccf3 100644 --- a/x-pack/plugins/infra/server/lib/sources/sources.ts +++ b/x-pack/plugins/infra/server/lib/sources/sources.ts @@ -20,7 +20,8 @@ import { pickSavedSourceConfiguration, SourceConfigurationSavedObjectRuntimeType, StaticSourceConfigurationRuntimeType, -} from './types'; + InfraSource, +} from '../../../common/http_api/source_api'; import { InfraConfig } from '../../../server'; interface Libs { @@ -35,7 +36,10 @@ export class InfraSources { this.libs = libs; } - public async getSourceConfiguration(requestContext: RequestHandlerContext, sourceId: string) { + public async getSourceConfiguration( + requestContext: RequestHandlerContext, + sourceId: string + ): Promise { const staticDefaultSourceConfiguration = await this.getStaticDefaultSourceConfiguration(); const savedSourceConfiguration = await this.getInternalSourceConfiguration(sourceId) diff --git a/x-pack/plugins/infra/server/lib/sources/types.ts b/x-pack/plugins/infra/server/lib/sources/types.ts deleted file mode 100644 index 1f850635cf35a2..00000000000000 --- a/x-pack/plugins/infra/server/lib/sources/types.ts +++ /dev/null @@ -1,149 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -/* eslint-disable @typescript-eslint/no-empty-interface */ - -import * as runtimeTypes from 'io-ts'; -import moment from 'moment'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { chain } from 'fp-ts/lib/Either'; - -export const TimestampFromString = new runtimeTypes.Type( - 'TimestampFromString', - (input): input is number => typeof input === 'number', - (input, context) => - pipe( - runtimeTypes.string.validate(input, context), - chain(stringInput => { - const momentValue = moment(stringInput); - return momentValue.isValid() - ? runtimeTypes.success(momentValue.valueOf()) - : runtimeTypes.failure(stringInput, context); - }) - ), - output => new Date(output).toISOString() -); - -/** - * Stored source configuration as read from and written to saved objects - */ - -const SavedSourceConfigurationFieldsRuntimeType = runtimeTypes.partial({ - container: runtimeTypes.string, - host: runtimeTypes.string, - pod: runtimeTypes.string, - tiebreaker: runtimeTypes.string, - timestamp: runtimeTypes.string, -}); - -export const SavedSourceConfigurationTimestampColumnRuntimeType = runtimeTypes.type({ - timestampColumn: runtimeTypes.type({ - id: runtimeTypes.string, - }), -}); - -export const SavedSourceConfigurationMessageColumnRuntimeType = runtimeTypes.type({ - messageColumn: runtimeTypes.type({ - id: runtimeTypes.string, - }), -}); - -export const SavedSourceConfigurationFieldColumnRuntimeType = runtimeTypes.type({ - fieldColumn: runtimeTypes.type({ - id: runtimeTypes.string, - field: runtimeTypes.string, - }), -}); - -export const SavedSourceConfigurationColumnRuntimeType = runtimeTypes.union([ - SavedSourceConfigurationTimestampColumnRuntimeType, - SavedSourceConfigurationMessageColumnRuntimeType, - SavedSourceConfigurationFieldColumnRuntimeType, -]); - -export const SavedSourceConfigurationRuntimeType = runtimeTypes.partial({ - name: runtimeTypes.string, - description: runtimeTypes.string, - metricAlias: runtimeTypes.string, - logAlias: runtimeTypes.string, - fields: SavedSourceConfigurationFieldsRuntimeType, - logColumns: runtimeTypes.array(SavedSourceConfigurationColumnRuntimeType), -}); - -export interface InfraSavedSourceConfiguration - extends runtimeTypes.TypeOf {} - -export const pickSavedSourceConfiguration = ( - value: InfraSourceConfiguration -): InfraSavedSourceConfiguration => { - const { name, description, metricAlias, logAlias, fields, logColumns } = value; - const { container, host, pod, tiebreaker, timestamp } = fields; - - return { - name, - description, - metricAlias, - logAlias, - fields: { container, host, pod, tiebreaker, timestamp }, - logColumns, - }; -}; - -/** - * Static source configuration as read from the configuration file - */ - -const StaticSourceConfigurationFieldsRuntimeType = runtimeTypes.partial({ - ...SavedSourceConfigurationFieldsRuntimeType.props, - message: runtimeTypes.array(runtimeTypes.string), -}); - -export const StaticSourceConfigurationRuntimeType = runtimeTypes.partial({ - name: runtimeTypes.string, - description: runtimeTypes.string, - metricAlias: runtimeTypes.string, - logAlias: runtimeTypes.string, - fields: StaticSourceConfigurationFieldsRuntimeType, - logColumns: runtimeTypes.array(SavedSourceConfigurationColumnRuntimeType), -}); - -export interface InfraStaticSourceConfiguration - extends runtimeTypes.TypeOf {} - -/** - * Full source configuration type after all cleanup has been done at the edges - */ - -const SourceConfigurationFieldsRuntimeType = runtimeTypes.type({ - ...StaticSourceConfigurationFieldsRuntimeType.props, -}); - -export const SourceConfigurationRuntimeType = runtimeTypes.type({ - ...SavedSourceConfigurationRuntimeType.props, - fields: SourceConfigurationFieldsRuntimeType, - logColumns: runtimeTypes.array(SavedSourceConfigurationColumnRuntimeType), -}); - -export interface InfraSourceConfiguration - extends runtimeTypes.TypeOf {} - -/** - * Saved object type with metadata - */ - -export const SourceConfigurationSavedObjectRuntimeType = runtimeTypes.intersection([ - runtimeTypes.type({ - id: runtimeTypes.string, - attributes: SavedSourceConfigurationRuntimeType, - }), - runtimeTypes.partial({ - version: runtimeTypes.string, - updated_at: TimestampFromString, - }), -]); - -export interface SourceConfigurationSavedObject - extends runtimeTypes.TypeOf {} diff --git a/x-pack/plugins/infra/server/plugin.ts b/x-pack/plugins/infra/server/plugin.ts index 64fc496f3597e1..e3804078604cc5 100644 --- a/x-pack/plugins/infra/server/plugin.ts +++ b/x-pack/plugins/infra/server/plugin.ts @@ -26,7 +26,7 @@ import { InfraSources } from './lib/sources'; import { InfraServerPluginDeps } from './lib/adapters/framework'; import { METRICS_FEATURE, LOGS_FEATURE } from './features'; import { UsageCollector } from './usage/usage_collector'; -import { InfraStaticSourceConfiguration } from './lib/sources/types'; +import { InfraStaticSourceConfiguration } from '../common/http_api/source_api'; import { registerAlertTypes } from './lib/alerting'; export const config = { diff --git a/x-pack/plugins/infra/server/routes/source/index.ts b/x-pack/plugins/infra/server/routes/source/index.ts new file mode 100644 index 00000000000000..2f29320d7bb81d --- /dev/null +++ b/x-pack/plugins/infra/server/routes/source/index.ts @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { schema } from '@kbn/config-schema'; +import { SourceResponseRuntimeType } from '../../../common/http_api/source_api'; +import { InfraBackendLibs } from '../../lib/infra_types'; +import { InfraIndexType } from '../../graphql/types'; + +const typeToInfraIndexType = (value: string | undefined) => { + switch (value) { + case 'metrics': + return InfraIndexType.METRICS; + case 'logs': + return InfraIndexType.LOGS; + default: + return InfraIndexType.ANY; + } +}; + +export const initSourceRoute = (libs: InfraBackendLibs) => { + const { framework } = libs; + + framework.registerRoute( + { + method: 'get', + path: '/api/metrics/source/{sourceId}/{type?}', + validate: { + params: schema.object({ + sourceId: schema.string(), + type: schema.string(), + }), + }, + }, + async (requestContext, request, response) => { + try { + const { type, sourceId } = request.params; + + const source = await libs.sources.getSourceConfiguration(requestContext, sourceId); + if (!source) { + return response.notFound(); + } + + const status = { + logIndicesExist: await libs.sourceStatus.hasLogIndices(requestContext, sourceId), + metricIndicesExist: await libs.sourceStatus.hasMetricIndices(requestContext, sourceId), + indexFields: await libs.fields.getFields( + requestContext, + sourceId, + typeToInfraIndexType(type) + ), + }; + + return response.ok({ + body: SourceResponseRuntimeType.encode({ source, status }), + }); + } catch (error) { + return response.internalError({ + body: error.message, + }); + } + } + ); +}; diff --git a/x-pack/plugins/ingest_manager/common/services/datasource_to_agent_datasource.test.ts b/x-pack/plugins/ingest_manager/common/services/datasource_to_agent_datasource.test.ts index 3496ea782ee997..17509571f19853 100644 --- a/x-pack/plugins/ingest_manager/common/services/datasource_to_agent_datasource.test.ts +++ b/x-pack/plugins/ingest_manager/common/services/datasource_to_agent_datasource.test.ts @@ -3,11 +3,11 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { NewDatasource, DatasourceInput } from '../types'; +import { Datasource, NewDatasource, DatasourceInput } from '../types'; import { storedDatasourceToAgentDatasource } from './datasource_to_agent_datasource'; describe('Ingest Manager - storedDatasourceToAgentDatasource', () => { - const mockDatasource: NewDatasource = { + const mockNewDatasource: NewDatasource = { name: 'mock-datasource', description: '', config_id: '', @@ -17,6 +17,12 @@ describe('Ingest Manager - storedDatasourceToAgentDatasource', () => { inputs: [], }; + const mockDatasource: Datasource = { + ...mockNewDatasource, + id: 'some-uuid', + revision: 1, + }; + const mockInput: DatasourceInput = { type: 'test-logs', enabled: true, @@ -70,7 +76,8 @@ describe('Ingest Manager - storedDatasourceToAgentDatasource', () => { it('returns agent datasource config for datasource with no inputs', () => { expect(storedDatasourceToAgentDatasource(mockDatasource)).toEqual({ - id: 'mock-datasource', + id: 'some-uuid', + name: 'mock-datasource', namespace: 'default', enabled: true, use_output: 'default', @@ -87,7 +94,8 @@ describe('Ingest Manager - storedDatasourceToAgentDatasource', () => { }, }) ).toEqual({ - id: 'mock-datasource', + id: 'some-uuid', + name: 'mock-datasource', namespace: 'default', enabled: true, use_output: 'default', @@ -99,9 +107,21 @@ describe('Ingest Manager - storedDatasourceToAgentDatasource', () => { }); }); + it('uses name for id when id is not provided in case of new datasource', () => { + expect(storedDatasourceToAgentDatasource(mockNewDatasource)).toEqual({ + id: 'mock-datasource', + name: 'mock-datasource', + namespace: 'default', + enabled: true, + use_output: 'default', + inputs: [], + }); + }); + it('returns agent datasource config with flattened input and package stream', () => { expect(storedDatasourceToAgentDatasource({ ...mockDatasource, inputs: [mockInput] })).toEqual({ - id: 'mock-datasource', + id: 'some-uuid', + name: 'mock-datasource', namespace: 'default', enabled: true, use_output: 'default', @@ -140,7 +160,8 @@ describe('Ingest Manager - storedDatasourceToAgentDatasource', () => { ], }) ).toEqual({ - id: 'mock-datasource', + id: 'some-uuid', + name: 'mock-datasource', namespace: 'default', enabled: true, use_output: 'default', @@ -169,7 +190,8 @@ describe('Ingest Manager - storedDatasourceToAgentDatasource', () => { inputs: [{ ...mockInput, enabled: false }], }) ).toEqual({ - id: 'mock-datasource', + id: 'some-uuid', + name: 'mock-datasource', namespace: 'default', enabled: true, use_output: 'default', diff --git a/x-pack/plugins/ingest_manager/common/services/datasource_to_agent_datasource.ts b/x-pack/plugins/ingest_manager/common/services/datasource_to_agent_datasource.ts index b509878b7f9452..9e09d3fa3153a0 100644 --- a/x-pack/plugins/ingest_manager/common/services/datasource_to_agent_datasource.ts +++ b/x-pack/plugins/ingest_manager/common/services/datasource_to_agent_datasource.ts @@ -12,7 +12,8 @@ export const storedDatasourceToAgentDatasource = ( const { name, namespace, enabled, package: pkg, inputs } = datasource; const fullDatasource: FullAgentConfigDatasource = { - id: name, + id: 'id' in datasource ? datasource.id : name, + name, namespace, enabled, use_output: DEFAULT_OUTPUT.name, // TODO: hardcoded to default output for now diff --git a/x-pack/plugins/ingest_manager/common/types/models/agent_config.ts b/x-pack/plugins/ingest_manager/common/types/models/agent_config.ts index 002c3784446a8e..2372caee512af6 100644 --- a/x-pack/plugins/ingest_manager/common/types/models/agent_config.ts +++ b/x-pack/plugins/ingest_manager/common/types/models/agent_config.ts @@ -34,8 +34,10 @@ export interface AgentConfig extends NewAgentConfig, SavedObjectAttributes { revision: number; } -export type FullAgentConfigDatasource = Pick & { - id: string; +export type FullAgentConfigDatasource = Pick< + Datasource, + 'id' | 'name' | 'namespace' | 'enabled' +> & { package?: Pick; use_output: string; inputs: Array< diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/header.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/header.tsx index 1aab6d901a9926..ceb87fb048ae3c 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/header.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/header.tsx @@ -31,7 +31,7 @@ const Tabs = styled(EuiTabs)` `; export interface HeaderProps { - restrictHeaderWidth?: number; + maxWidth?: number; leftColumn?: JSX.Element; rightColumn?: JSX.Element; rightColumnGrow?: EuiFlexItemProps['grow']; @@ -52,10 +52,10 @@ export const Header: React.FC = ({ rightColumn, rightColumnGrow, tabs, - restrictHeaderWidth, + maxWidth, }) => ( - + = ({ restrictWidth, children, ...rest }) => ( +export const WithHeaderLayout: React.FC = ({ + restrictWidth, + restrictHeaderWidth, + children, + ...rest +}) => ( -
+
diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/layout.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/layout.tsx index 73a7ba8ec119d9..39d882f7fdf65e 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/layout.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/layout.tsx @@ -18,16 +18,14 @@ import { import { WithHeaderLayout } from '../../../../layouts'; import { AgentConfig, PackageInfo } from '../../../../types'; import { PackageIcon } from '../../../../components/package_icon'; -import { CreateDatasourceFrom, CreateDatasourceStep } from '../types'; +import { CreateDatasourceFrom } from '../types'; export const CreateDatasourcePageLayout: React.FunctionComponent<{ from: CreateDatasourceFrom; - basePath: string; cancelUrl: string; - maxStep: CreateDatasourceStep | ''; agentConfig?: AgentConfig; packageInfo?: PackageInfo; -}> = ({ from, basePath, cancelUrl, maxStep, agentConfig, packageInfo, children }) => { +}> = ({ from, cancelUrl, agentConfig, packageInfo, children }) => { const leftColumn = ( diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/index.tsx index 1ad579d591b211..3c79fe17fdbb51 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/index.tsx @@ -28,12 +28,11 @@ import { } from '../../../hooks'; import { useLinks as useEPMLinks } from '../../epm/hooks'; import { CreateDatasourcePageLayout, ConfirmCreateDatasourceModal } from './components'; -import { CreateDatasourceFrom, CreateDatasourceStep } from './types'; +import { CreateDatasourceFrom } from './types'; import { DatasourceValidationResults, validateDatasource, validationHasErrors } from './services'; import { StepSelectPackage } from './step_select_package'; import { StepSelectConfig } from './step_select_config'; import { StepConfigureDatasource } from './step_configure_datasource'; - import { StepDefineDatasource } from './step_define_datasource'; export const CreateDatasourcePage: React.FunctionComponent = () => { @@ -43,11 +42,9 @@ export const CreateDatasourcePage: React.FunctionComponent = () => { } = useConfig(); const { params: { configId, pkgkey }, - url: basePath, } = useRouteMatch(); const history = useHistory(); const from: CreateDatasourceFrom = configId ? 'config' : 'package'; - const [maxStep, setMaxStep] = useState(''); // Agent config and package info states const [agentConfig, setAgentConfig] = useState(); @@ -91,7 +88,6 @@ export const CreateDatasourcePage: React.FunctionComponent = () => { } else { setFormState('INVALID'); setPackageInfo(undefined); - setMaxStep(''); } // eslint-disable-next-line no-console @@ -105,7 +101,6 @@ export const CreateDatasourcePage: React.FunctionComponent = () => { } else { setFormState('INVALID'); setAgentConfig(undefined); - setMaxStep(''); } // eslint-disable-next-line no-console @@ -189,9 +184,7 @@ export const CreateDatasourcePage: React.FunctionComponent = () => { const layoutProps = { from, - basePath, cancelUrl, - maxStep, agentConfig, packageInfo, }; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/types.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/types.ts index bd05be2d8a558d..85cc758fc4c464 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/types.ts +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/types.ts @@ -5,4 +5,3 @@ */ export type CreateDatasourceFrom = 'package' | 'config'; -export type CreateDatasourceStep = 'selectConfig' | 'selectPackage' | 'configure' | 'review'; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/details_page/components/yaml/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/details_page/components/yaml/index.tsx index 56b109a9bc062f..ad27c590d5eaae 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/details_page/components/yaml/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/details_page/components/yaml/index.tsx @@ -27,7 +27,9 @@ import { Loading } from '../../../../../components'; const CONFIG_KEYS_ORDER = [ 'id', + 'name', 'revision', + 'type', 'outputs', 'datasources', 'enabled', @@ -52,7 +54,7 @@ export const ConfigYamlView = memo<{ config: AgentConfig }>(({ config }) => { return ( - + {dump(fullConfigRequest.data.item, { sortKeys: (keyA: string, keyB: string) => { const indexA = CONFIG_KEYS_ORDER.indexOf(keyA); diff --git a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx index cbdc0617e8568b..772ee13168d026 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx @@ -140,6 +140,7 @@ function DatatableComponent(props: DatatableProps & { formatFactory: FormatFacto { const col = firstTable.columns.find(c => c.id === field); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/_expression_renderer.scss b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/_expression_renderer.scss index d43a857e05639c..9519544ece575c 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/_expression_renderer.scss +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/_expression_renderer.scss @@ -1,9 +1,10 @@ .lnsExpressionRenderer { + @include euiScrollBar; position: relative; width: 100%; height: 100%; display: flex; - overflow-x: hidden; + overflow: auto; .lnsExpressionRenderer__component { position: static; // Let the progress indicator position itself against the outer parent diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/_workspace_panel_wrapper.scss b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/_workspace_panel_wrapper.scss index 3ef387eca1e8b1..4ba19cb4ab05b9 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/_workspace_panel_wrapper.scss +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/_workspace_panel_wrapper.scss @@ -29,7 +29,7 @@ display: flex; align-items: center; justify-content: center; - overflow-x: hidden; + overflow: hidden; } } } diff --git a/x-pack/plugins/logstash/kibana.json b/x-pack/plugins/logstash/kibana.json index bcc926535d3c28..97dbf58865a882 100644 --- a/x-pack/plugins/logstash/kibana.json +++ b/x-pack/plugins/logstash/kibana.json @@ -4,9 +4,13 @@ "kibanaVersion": "kibana", "configPath": ["xpack", "logstash"], "requiredPlugins": [ - "licensing" + "licensing", + "management" + ], + "optionalPlugins": [ + "home", + "security" ], - "optionalPlugins": ["security"], "server": true, - "ui": false + "ui": true } diff --git a/x-pack/legacy/plugins/logstash/public/sections/breadcrumbs.js b/x-pack/plugins/logstash/public/application/breadcrumbs.js similarity index 80% rename from x-pack/legacy/plugins/logstash/public/sections/breadcrumbs.js rename to x-pack/plugins/logstash/public/application/breadcrumbs.js index 3121a58ff6a74f..322b9860b37854 100644 --- a/x-pack/legacy/plugins/logstash/public/sections/breadcrumbs.js +++ b/x-pack/plugins/logstash/public/application/breadcrumbs.js @@ -5,11 +5,9 @@ */ import { i18n } from '@kbn/i18n'; -import { MANAGEMENT_BREADCRUMB } from 'ui/management'; export function getPipelineListBreadcrumbs() { return [ - MANAGEMENT_BREADCRUMB, { text: i18n.translate('xpack.logstash.pipelines.listBreadcrumb', { defaultMessage: 'Pipelines', @@ -19,12 +17,11 @@ export function getPipelineListBreadcrumbs() { ]; } -export function getPipelineEditBreadcrumbs($route) { - const { pipeline } = $route.current.locals; +export function getPipelineEditBreadcrumbs(pipelineId) { return [ ...getPipelineListBreadcrumbs(), { - text: pipeline.id, + text: pipelineId, }, ]; } diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_editor/__snapshots__/confirm_delete_pipeline_modal.test.js.snap b/x-pack/plugins/logstash/public/application/components/pipeline_editor/__snapshots__/confirm_delete_pipeline_modal.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_editor/__snapshots__/confirm_delete_pipeline_modal.test.js.snap rename to x-pack/plugins/logstash/public/application/components/pipeline_editor/__snapshots__/confirm_delete_pipeline_modal.test.js.snap diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_editor/__snapshots__/flex_item_setting.test.js.snap b/x-pack/plugins/logstash/public/application/components/pipeline_editor/__snapshots__/flex_item_setting.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_editor/__snapshots__/flex_item_setting.test.js.snap rename to x-pack/plugins/logstash/public/application/components/pipeline_editor/__snapshots__/flex_item_setting.test.js.snap diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_editor/__snapshots__/form_label_with_icon_tip.test.js.snap b/x-pack/plugins/logstash/public/application/components/pipeline_editor/__snapshots__/form_label_with_icon_tip.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_editor/__snapshots__/form_label_with_icon_tip.test.js.snap rename to x-pack/plugins/logstash/public/application/components/pipeline_editor/__snapshots__/form_label_with_icon_tip.test.js.snap diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_editor/__snapshots__/pipeline_editor.test.js.snap b/x-pack/plugins/logstash/public/application/components/pipeline_editor/__snapshots__/pipeline_editor.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_editor/__snapshots__/pipeline_editor.test.js.snap rename to x-pack/plugins/logstash/public/application/components/pipeline_editor/__snapshots__/pipeline_editor.test.js.snap diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_editor/confirm_delete_pipeline_modal.js b/x-pack/plugins/logstash/public/application/components/pipeline_editor/confirm_delete_pipeline_modal.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_editor/confirm_delete_pipeline_modal.js rename to x-pack/plugins/logstash/public/application/components/pipeline_editor/confirm_delete_pipeline_modal.js diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_editor/confirm_delete_pipeline_modal.test.js b/x-pack/plugins/logstash/public/application/components/pipeline_editor/confirm_delete_pipeline_modal.test.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_editor/confirm_delete_pipeline_modal.test.js rename to x-pack/plugins/logstash/public/application/components/pipeline_editor/confirm_delete_pipeline_modal.test.js diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_editor/constants.js b/x-pack/plugins/logstash/public/application/components/pipeline_editor/constants.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_editor/constants.js rename to x-pack/plugins/logstash/public/application/components/pipeline_editor/constants.js diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_editor/flex_item_setting.js b/x-pack/plugins/logstash/public/application/components/pipeline_editor/flex_item_setting.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_editor/flex_item_setting.js rename to x-pack/plugins/logstash/public/application/components/pipeline_editor/flex_item_setting.js diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_editor/flex_item_setting.test.js b/x-pack/plugins/logstash/public/application/components/pipeline_editor/flex_item_setting.test.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_editor/flex_item_setting.test.js rename to x-pack/plugins/logstash/public/application/components/pipeline_editor/flex_item_setting.test.js diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_editor/form_label_with_icon_tip.js b/x-pack/plugins/logstash/public/application/components/pipeline_editor/form_label_with_icon_tip.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_editor/form_label_with_icon_tip.js rename to x-pack/plugins/logstash/public/application/components/pipeline_editor/form_label_with_icon_tip.js diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_editor/form_label_with_icon_tip.test.js b/x-pack/plugins/logstash/public/application/components/pipeline_editor/form_label_with_icon_tip.test.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_editor/form_label_with_icon_tip.test.js rename to x-pack/plugins/logstash/public/application/components/pipeline_editor/form_label_with_icon_tip.test.js diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_editor/index.js b/x-pack/plugins/logstash/public/application/components/pipeline_editor/index.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_editor/index.js rename to x-pack/plugins/logstash/public/application/components/pipeline_editor/index.js diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_editor/pipeline_editor.js b/x-pack/plugins/logstash/public/application/components/pipeline_editor/pipeline_editor.js similarity index 97% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_editor/pipeline_editor.js rename to x-pack/plugins/logstash/public/application/components/pipeline_editor/pipeline_editor.js index 5e430ccbd8cebc..e45820d56cc03d 100644 --- a/x-pack/legacy/plugins/logstash/public/components/pipeline_editor/pipeline_editor.js +++ b/x-pack/plugins/logstash/public/application/components/pipeline_editor/pipeline_editor.js @@ -13,7 +13,7 @@ import 'brace/mode/plain_text'; import 'brace/theme/github'; import { isEmpty } from 'lodash'; -import { TOOLTIPS } from '../../../../../../plugins/logstash/common/constants/tooltips'; +import { TOOLTIPS } from '../../../../common/constants/tooltips'; import { EuiButton, EuiButtonEmpty, @@ -40,7 +40,6 @@ class PipelineEditorUi extends React.Component { const { pipeline: { id, description, pipeline, settings }, - username, } = this.props; const pipelineWorkersSet = typeof settings['pipeline.workers'] === 'number'; @@ -60,7 +59,6 @@ class PipelineEditorUi extends React.Component { 'queue.max_bytes': settings['queue.max_bytes.number'] + settings['queue.max_bytes.units'], 'queue.type': settings['queue.type'], }, - username, }, pipelineIdErrors: [], pipelineIdPattern: /^[A-Za-z\_][A-Za-z0-9\-\_]*$/, @@ -236,15 +234,7 @@ class PipelineEditorUi extends React.Component { }; getPipelineHeadingText = () => { - const { - routeService: { - current: { - params: { clone, id }, - }, - }, - isNewPipeline, - intl, - } = this.props; + const { clone, id, isNewPipeline, intl } = this.props; if (!!clone && id) { return intl.formatMessage( @@ -502,6 +492,8 @@ class PipelineEditorUi extends React.Component { } PipelineEditorUi.propTypes = { + id: PropTypes.string, + clone: PropTypes.bool.isRequired, close: PropTypes.func.isRequired, isNewPipeline: PropTypes.bool.isRequired, licenseService: PropTypes.shape({ @@ -527,20 +519,11 @@ PipelineEditorUi.propTypes = { deletePipeline: PropTypes.func.isRequired, savePipeline: PropTypes.func.isRequired, }).isRequired, - routeService: PropTypes.shape({ - current: PropTypes.shape({ - params: PropTypes.shape({ - clone: PropTypes.oneOf([true, undefined]), - id: PropTypes.string, - }), - }), - }).isRequired, toastNotifications: PropTypes.shape({ addWarning: PropTypes.func.isRequired, addSuccess: PropTypes.func.isRequired, addError: PropTypes.func.isRequired, }).isRequired, - username: PropTypes.string, }; export const PipelineEditor = injectI18n(PipelineEditorUi); diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_editor/pipeline_editor.test.js b/x-pack/plugins/logstash/public/application/components/pipeline_editor/pipeline_editor.test.js similarity index 96% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_editor/pipeline_editor.test.js rename to x-pack/plugins/logstash/public/application/components/pipeline_editor/pipeline_editor.test.js index 2d7ed5f257fbda..bb5961ce36120c 100644 --- a/x-pack/legacy/plugins/logstash/public/components/pipeline_editor/pipeline_editor.test.js +++ b/x-pack/plugins/logstash/public/application/components/pipeline_editor/pipeline_editor.test.js @@ -17,7 +17,6 @@ describe('PipelineEditor component', () => { let open; let pipeline; let pipelineService; - let routeService; let toastNotifications; let username; @@ -47,14 +46,6 @@ describe('PipelineEditor component', () => { deletePipeline: jest.fn(), savePipeline: jest.fn(), }; - routeService = { - current: { - params: { - clone: undefined, - id: undefined, - }, - }, - }; toastNotifications = { addWarning: jest.fn(), addSuccess: jest.fn(), @@ -62,13 +53,14 @@ describe('PipelineEditor component', () => { }; username = 'elastic'; props = { + clone: false, + id: 'pipelineId', close, isNewPipeline, licenseService, open, pipeline, pipelineService, - routeService, toastNotifications, username, }; @@ -79,10 +71,8 @@ describe('PipelineEditor component', () => { }); it('matches snapshot for clone pipeline', () => { - routeService.current.params = { - clone: true, - id: 'pipelineToClone', - }; + props.clone = true; + props.id = 'pipelineToClone'; expect(shallowWithIntl()).toMatchSnapshot(); }); diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_list/__snapshots__/add_role_alert.test.js.snap b/x-pack/plugins/logstash/public/application/components/pipeline_list/__snapshots__/add_role_alert.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_list/__snapshots__/add_role_alert.test.js.snap rename to x-pack/plugins/logstash/public/application/components/pipeline_list/__snapshots__/add_role_alert.test.js.snap diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_list/__snapshots__/alert_call_out.test.js.snap b/x-pack/plugins/logstash/public/application/components/pipeline_list/__snapshots__/alert_call_out.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_list/__snapshots__/alert_call_out.test.js.snap rename to x-pack/plugins/logstash/public/application/components/pipeline_list/__snapshots__/alert_call_out.test.js.snap diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_list/__snapshots__/confirm_delete_modal.test.js.snap b/x-pack/plugins/logstash/public/application/components/pipeline_list/__snapshots__/confirm_delete_modal.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_list/__snapshots__/confirm_delete_modal.test.js.snap rename to x-pack/plugins/logstash/public/application/components/pipeline_list/__snapshots__/confirm_delete_modal.test.js.snap diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_list/__snapshots__/enable_monitoring_alert.test.js.snap b/x-pack/plugins/logstash/public/application/components/pipeline_list/__snapshots__/enable_monitoring_alert.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_list/__snapshots__/enable_monitoring_alert.test.js.snap rename to x-pack/plugins/logstash/public/application/components/pipeline_list/__snapshots__/enable_monitoring_alert.test.js.snap diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_list/__snapshots__/info_alerts.test.js.snap b/x-pack/plugins/logstash/public/application/components/pipeline_list/__snapshots__/info_alerts.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_list/__snapshots__/info_alerts.test.js.snap rename to x-pack/plugins/logstash/public/application/components/pipeline_list/__snapshots__/info_alerts.test.js.snap diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_list/__snapshots__/pipelines_table.test.js.snap b/x-pack/plugins/logstash/public/application/components/pipeline_list/__snapshots__/pipelines_table.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_list/__snapshots__/pipelines_table.test.js.snap rename to x-pack/plugins/logstash/public/application/components/pipeline_list/__snapshots__/pipelines_table.test.js.snap diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_list/add_role_alert.js b/x-pack/plugins/logstash/public/application/components/pipeline_list/add_role_alert.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_list/add_role_alert.js rename to x-pack/plugins/logstash/public/application/components/pipeline_list/add_role_alert.js diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_list/add_role_alert.test.js b/x-pack/plugins/logstash/public/application/components/pipeline_list/add_role_alert.test.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_list/add_role_alert.test.js rename to x-pack/plugins/logstash/public/application/components/pipeline_list/add_role_alert.test.js diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_list/alert_call_out.js b/x-pack/plugins/logstash/public/application/components/pipeline_list/alert_call_out.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_list/alert_call_out.js rename to x-pack/plugins/logstash/public/application/components/pipeline_list/alert_call_out.js diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_list/alert_call_out.test.js b/x-pack/plugins/logstash/public/application/components/pipeline_list/alert_call_out.test.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_list/alert_call_out.test.js rename to x-pack/plugins/logstash/public/application/components/pipeline_list/alert_call_out.test.js diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_list/confirm_delete_modal.js b/x-pack/plugins/logstash/public/application/components/pipeline_list/confirm_delete_modal.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_list/confirm_delete_modal.js rename to x-pack/plugins/logstash/public/application/components/pipeline_list/confirm_delete_modal.js diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_list/confirm_delete_modal.test.js b/x-pack/plugins/logstash/public/application/components/pipeline_list/confirm_delete_modal.test.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_list/confirm_delete_modal.test.js rename to x-pack/plugins/logstash/public/application/components/pipeline_list/confirm_delete_modal.test.js diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_list/constants.js b/x-pack/plugins/logstash/public/application/components/pipeline_list/constants.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_list/constants.js rename to x-pack/plugins/logstash/public/application/components/pipeline_list/constants.js diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_list/enable_monitoring_alert.js b/x-pack/plugins/logstash/public/application/components/pipeline_list/enable_monitoring_alert.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_list/enable_monitoring_alert.js rename to x-pack/plugins/logstash/public/application/components/pipeline_list/enable_monitoring_alert.js diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_list/enable_monitoring_alert.test.js b/x-pack/plugins/logstash/public/application/components/pipeline_list/enable_monitoring_alert.test.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_list/enable_monitoring_alert.test.js rename to x-pack/plugins/logstash/public/application/components/pipeline_list/enable_monitoring_alert.test.js diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_list/index.js b/x-pack/plugins/logstash/public/application/components/pipeline_list/index.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_list/index.js rename to x-pack/plugins/logstash/public/application/components/pipeline_list/index.js diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_list/info_alerts.js b/x-pack/plugins/logstash/public/application/components/pipeline_list/info_alerts.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_list/info_alerts.js rename to x-pack/plugins/logstash/public/application/components/pipeline_list/info_alerts.js diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_list/info_alerts.test.js b/x-pack/plugins/logstash/public/application/components/pipeline_list/info_alerts.test.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_list/info_alerts.test.js rename to x-pack/plugins/logstash/public/application/components/pipeline_list/info_alerts.test.js diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_list/pipeline_list.js b/x-pack/plugins/logstash/public/application/components/pipeline_list/pipeline_list.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_list/pipeline_list.js rename to x-pack/plugins/logstash/public/application/components/pipeline_list/pipeline_list.js diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_list/pipeline_list.test.js b/x-pack/plugins/logstash/public/application/components/pipeline_list/pipeline_list.test.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_list/pipeline_list.test.js rename to x-pack/plugins/logstash/public/application/components/pipeline_list/pipeline_list.test.js diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_list/pipelines_table.js b/x-pack/plugins/logstash/public/application/components/pipeline_list/pipelines_table.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_list/pipelines_table.js rename to x-pack/plugins/logstash/public/application/components/pipeline_list/pipelines_table.js diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_list/pipelines_table.test.js b/x-pack/plugins/logstash/public/application/components/pipeline_list/pipelines_table.test.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/pipeline_list/pipelines_table.test.js rename to x-pack/plugins/logstash/public/application/components/pipeline_list/pipelines_table.test.js diff --git a/x-pack/legacy/plugins/logstash/public/components/upgrade_failure/__snapshots__/upgrade_failure.test.js.snap b/x-pack/plugins/logstash/public/application/components/upgrade_failure/__snapshots__/upgrade_failure.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/upgrade_failure/__snapshots__/upgrade_failure.test.js.snap rename to x-pack/plugins/logstash/public/application/components/upgrade_failure/__snapshots__/upgrade_failure.test.js.snap diff --git a/x-pack/legacy/plugins/logstash/public/components/upgrade_failure/__snapshots__/upgrade_failure_actions.test.js.snap b/x-pack/plugins/logstash/public/application/components/upgrade_failure/__snapshots__/upgrade_failure_actions.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/upgrade_failure/__snapshots__/upgrade_failure_actions.test.js.snap rename to x-pack/plugins/logstash/public/application/components/upgrade_failure/__snapshots__/upgrade_failure_actions.test.js.snap diff --git a/x-pack/legacy/plugins/logstash/public/components/upgrade_failure/__snapshots__/upgrade_failure_title.test.js.snap b/x-pack/plugins/logstash/public/application/components/upgrade_failure/__snapshots__/upgrade_failure_title.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/upgrade_failure/__snapshots__/upgrade_failure_title.test.js.snap rename to x-pack/plugins/logstash/public/application/components/upgrade_failure/__snapshots__/upgrade_failure_title.test.js.snap diff --git a/x-pack/legacy/plugins/logstash/public/components/upgrade_failure/constants.js b/x-pack/plugins/logstash/public/application/components/upgrade_failure/constants.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/upgrade_failure/constants.js rename to x-pack/plugins/logstash/public/application/components/upgrade_failure/constants.js diff --git a/x-pack/legacy/plugins/logstash/public/components/upgrade_failure/index.js b/x-pack/plugins/logstash/public/application/components/upgrade_failure/index.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/upgrade_failure/index.js rename to x-pack/plugins/logstash/public/application/components/upgrade_failure/index.js diff --git a/x-pack/legacy/plugins/logstash/public/components/upgrade_failure/upgrade_failure.js b/x-pack/plugins/logstash/public/application/components/upgrade_failure/upgrade_failure.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/upgrade_failure/upgrade_failure.js rename to x-pack/plugins/logstash/public/application/components/upgrade_failure/upgrade_failure.js diff --git a/x-pack/legacy/plugins/logstash/public/components/upgrade_failure/upgrade_failure.test.js b/x-pack/plugins/logstash/public/application/components/upgrade_failure/upgrade_failure.test.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/upgrade_failure/upgrade_failure.test.js rename to x-pack/plugins/logstash/public/application/components/upgrade_failure/upgrade_failure.test.js diff --git a/x-pack/legacy/plugins/logstash/public/components/upgrade_failure/upgrade_failure_actions.js b/x-pack/plugins/logstash/public/application/components/upgrade_failure/upgrade_failure_actions.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/upgrade_failure/upgrade_failure_actions.js rename to x-pack/plugins/logstash/public/application/components/upgrade_failure/upgrade_failure_actions.js diff --git a/x-pack/legacy/plugins/logstash/public/components/upgrade_failure/upgrade_failure_actions.test.js b/x-pack/plugins/logstash/public/application/components/upgrade_failure/upgrade_failure_actions.test.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/upgrade_failure/upgrade_failure_actions.test.js rename to x-pack/plugins/logstash/public/application/components/upgrade_failure/upgrade_failure_actions.test.js diff --git a/x-pack/legacy/plugins/logstash/public/components/upgrade_failure/upgrade_failure_title.js b/x-pack/plugins/logstash/public/application/components/upgrade_failure/upgrade_failure_title.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/upgrade_failure/upgrade_failure_title.js rename to x-pack/plugins/logstash/public/application/components/upgrade_failure/upgrade_failure_title.js diff --git a/x-pack/legacy/plugins/logstash/public/components/upgrade_failure/upgrade_failure_title.test.js b/x-pack/plugins/logstash/public/application/components/upgrade_failure/upgrade_failure_title.test.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/components/upgrade_failure/upgrade_failure_title.test.js rename to x-pack/plugins/logstash/public/application/components/upgrade_failure/upgrade_failure_title.test.js diff --git a/x-pack/plugins/logstash/public/application/index.tsx b/x-pack/plugins/logstash/public/application/index.tsx new file mode 100644 index 00000000000000..438038d6c885e0 --- /dev/null +++ b/x-pack/plugins/logstash/public/application/index.tsx @@ -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; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import ReactDOM from 'react-dom'; +import { HashRouter, Route, Switch, Redirect } from 'react-router-dom'; +import { Observable } from 'rxjs'; +import { first } from 'rxjs/operators'; + +import { CoreStart } from 'src/core/public'; +import { ManagementAppMountParams } from '../../../../../src/plugins/management/public'; +import { + ClusterService, + MonitoringService, + PipelineService, + PipelinesService, + UpgradeService, + // @ts-ignore +} from '../services'; +// @ts-ignore +import { PipelineList } from './components/pipeline_list'; +import { PipelineEditView } from './pipeline_edit_view'; +// @ts-ignore +import { Pipeline } from '../models/pipeline'; +// @ts-ignore +import * as Breadcrumbs from './breadcrumbs'; + +export const renderApp = async ( + core: CoreStart, + { basePath, element, setBreadcrumbs }: ManagementAppMountParams, + licenseService$: Observable +) => { + const logstashLicenseService = await licenseService$.pipe(first()).toPromise(); + const clusterService = new ClusterService(core.http); + const monitoringService = new MonitoringService( + core.http, + // When monitoring is migrated this should be fetched from monitoring's plugin contract + core.injectedMetadata.getInjectedVar('monitoringUiEnabled'), + clusterService + ); + const pipelinesService = new PipelinesService(core.http, monitoringService); + const pipelineService = new PipelineService(core.http, pipelinesService); + const upgradeService = new UpgradeService(core.http); + + ReactDOM.render( + + + + { + setBreadcrumbs(Breadcrumbs.getPipelineListBreadcrumbs()); + return ( + history.push(`/pipeline/${id}/edit`)} + clonePipeline={(id: string) => history.push(`/pipeline/${id}/edit?clone`)} + createPipeline={() => history.push(`/pipeline/new-pipeline`)} + pipelinesService={pipelinesService} + toastNotifications={core.notifications.toasts} + /> + ); + }} + /> + ( + + )} + /> + } + /> + ( + + )} + /> + + + , + element + ); + + return () => { + ReactDOM.unmountComponentAtNode(element); + }; +}; diff --git a/x-pack/plugins/logstash/public/application/pipeline_edit_view.tsx b/x-pack/plugins/logstash/public/application/pipeline_edit_view.tsx new file mode 100644 index 00000000000000..c1b465febcd9ba --- /dev/null +++ b/x-pack/plugins/logstash/public/application/pipeline_edit_view.tsx @@ -0,0 +1,153 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useState, useLayoutEffect, useCallback } from 'react'; +import { usePromise } from 'react-use'; +import { History } from 'history'; + +import { i18n } from '@kbn/i18n'; +import { ToastsStart } from 'src/core/public'; + +// @ts-ignore +import { UpgradeFailure } from './components/upgrade_failure'; +// @ts-ignore +import { PipelineEditor } from './components/pipeline_editor'; +// @ts-ignore +import { Pipeline } from '../models/pipeline'; +import { ManagementAppMountParams } from '../../../../../src/plugins/management/public'; +// @ts-ignore +import * as Breadcrumbs from './breadcrumbs'; + +const usePipeline = ( + pipelineService: any, + logstashLicenseService: any, + toasts: ToastsStart, + shouldClone: boolean, + id?: string +) => { + const mounted = usePromise(); + const [pipeline, setPipeline] = useState(null); + + useLayoutEffect(() => { + (async () => { + if (!id) { + return setPipeline(new Pipeline()); + } + + try { + const result = await mounted(pipelineService.loadPipeline(id) as Promise); + setPipeline(shouldClone ? result.clone : result); + } catch (e) { + await logstashLicenseService.checkValidity(); + if (e.status !== 403) { + toasts.addDanger( + i18n.translate('xpack.logstash.couldNotLoadPipelineErrorNotification', { + defaultMessage: `Couldn't load pipeline. Error: '{errStatusText}'.`, + values: { + errStatusText: e.statusText, + }, + }) + ); + } + } + })(); + }, [pipelineService, id, mounted, shouldClone, logstashLicenseService, toasts]); + + return pipeline; +}; + +const useIsUpgraded = (upgradeService: any) => { + const [isUpgraded, setIsUpgraded] = useState(null); + const mounted = usePromise(); + + useLayoutEffect(() => { + mounted(upgradeService.executeUpgrade() as Promise).then(result => + setIsUpgraded(result) + ); + }, [mounted, upgradeService]); + + return isUpgraded; +}; + +interface EditProps { + pipelineService: any; + logstashLicenseService: any; + upgradeService: any; + toasts: ToastsStart; + history: History; + setBreadcrumbs: ManagementAppMountParams['setBreadcrumbs']; + + // URL params + id?: string; +} + +export const PipelineEditView: React.FC = ({ + pipelineService, + logstashLicenseService, + upgradeService, + toasts, + history, + setBreadcrumbs, + id, +}) => { + const params = new URLSearchParams(history.location.search); + const shouldRetry = params.get('retry') === 'true'; + const shouldClone = params.get('clone') === ''; + + const pipeline = usePipeline(pipelineService, logstashLicenseService, toasts, shouldClone, id); + const isUpgraded = useIsUpgraded(upgradeService); + + const onRetry = useCallback(() => { + const newParams = new URLSearchParams(history.location.search); + newParams.set('retry', 'true'); + history.replace({ search: newParams.toString() }); + }, [history]); + const close = useCallback(() => { + history.push('/'); + }, [history]); + const open = useCallback( + (newId: string) => { + history.push(`/pipeline/${newId}/edit`); + }, + [history] + ); + + if (!pipeline || isUpgraded === null) { + return null; + } + + const isNewPipeline = !pipeline.id; + setBreadcrumbs( + isNewPipeline + ? Breadcrumbs.getPipelineCreateBreadcrumbs() + : Breadcrumbs.getPipelineEditBreadcrumbs(pipeline.id) + ); + + if (!isUpgraded) { + return ( + + ); + } + + return ( + + ); +}; diff --git a/x-pack/plugins/logstash/public/index.ts b/x-pack/plugins/logstash/public/index.ts new file mode 100644 index 00000000000000..26a1ca4e8c6c43 --- /dev/null +++ b/x-pack/plugins/logstash/public/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { LogstashPlugin } from './plugin'; + +export const plugin = () => new LogstashPlugin(); diff --git a/x-pack/legacy/plugins/logstash/public/lib/get_search_value/get_search_value.js b/x-pack/plugins/logstash/public/lib/get_search_value/get_search_value.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/lib/get_search_value/get_search_value.js rename to x-pack/plugins/logstash/public/lib/get_search_value/get_search_value.js diff --git a/x-pack/legacy/plugins/logstash/public/lib/get_search_value/index.js b/x-pack/plugins/logstash/public/lib/get_search_value/index.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/lib/get_search_value/index.js rename to x-pack/plugins/logstash/public/lib/get_search_value/index.js diff --git a/x-pack/legacy/plugins/logstash/public/models/cluster/cluster.js b/x-pack/plugins/logstash/public/models/cluster/cluster.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/models/cluster/cluster.js rename to x-pack/plugins/logstash/public/models/cluster/cluster.js diff --git a/x-pack/legacy/plugins/logstash/public/models/cluster/index.js b/x-pack/plugins/logstash/public/models/cluster/index.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/models/cluster/index.js rename to x-pack/plugins/logstash/public/models/cluster/index.js diff --git a/x-pack/legacy/plugins/logstash/public/models/pipeline/index.js b/x-pack/plugins/logstash/public/models/pipeline/index.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/models/pipeline/index.js rename to x-pack/plugins/logstash/public/models/pipeline/index.js diff --git a/x-pack/legacy/plugins/logstash/public/models/pipeline/pipeline.js b/x-pack/plugins/logstash/public/models/pipeline/pipeline.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/models/pipeline/pipeline.js rename to x-pack/plugins/logstash/public/models/pipeline/pipeline.js diff --git a/x-pack/legacy/plugins/logstash/public/models/pipeline_list_item/index.js b/x-pack/plugins/logstash/public/models/pipeline_list_item/index.js similarity index 100% rename from x-pack/legacy/plugins/logstash/public/models/pipeline_list_item/index.js rename to x-pack/plugins/logstash/public/models/pipeline_list_item/index.js diff --git a/x-pack/legacy/plugins/logstash/public/models/pipeline_list_item/pipeline_list_item.js b/x-pack/plugins/logstash/public/models/pipeline_list_item/pipeline_list_item.js similarity index 83% rename from x-pack/legacy/plugins/logstash/public/models/pipeline_list_item/pipeline_list_item.js rename to x-pack/plugins/logstash/public/models/pipeline_list_item/pipeline_list_item.js index 06d01a05bac278..3a304e467e0c0d 100755 --- a/x-pack/legacy/plugins/logstash/public/models/pipeline_list_item/pipeline_list_item.js +++ b/x-pack/plugins/logstash/public/models/pipeline_list_item/pipeline_list_item.js @@ -5,10 +5,10 @@ */ import { pick, capitalize } from 'lodash'; +import moment from 'moment'; -import { getSearchValue } from 'plugins/logstash/lib/get_search_value'; -import { getMoment } from 'plugins/logstash/../common/lib/get_moment'; -import { PIPELINE } from '../../../../../../plugins/logstash/common/constants'; +import { getSearchValue } from '../../lib/get_search_value'; +import { PIPELINE } from '../../../common/constants'; /** * Represents the model for listing pipelines in the UI @@ -25,7 +25,7 @@ export class PipelineListItem { this.username = props.username; if (props.lastModified) { - this.lastModified = getMoment(props.lastModified); + this.lastModified = getMomentDate(props.lastModified); this.lastModifiedHumanized = capitalize(this.lastModified.fromNow()); } } @@ -51,3 +51,11 @@ export class PipelineListItem { return new PipelineListItem(props); } } + +function getMomentDate(date) { + if (!date) { + return null; + } + + return moment(date); +} diff --git a/x-pack/plugins/logstash/public/plugin.ts b/x-pack/plugins/logstash/public/plugin.ts new file mode 100644 index 00000000000000..91d1a39d3970cf --- /dev/null +++ b/x-pack/plugins/logstash/public/plugin.ts @@ -0,0 +1,92 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import { Subscription } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { once } from 'lodash'; + +import { CoreSetup, CoreStart, Plugin } from 'src/core/public'; +import { + HomePublicPluginSetup, + FeatureCatalogueCategory, +} from '../../../../src/plugins/home/public'; +import { LicensingPluginSetup } from '../../licensing/public'; +import { ManagementSetup } from '../../../../src/plugins/management/public'; + +// @ts-ignore +import { LogstashLicenseService } from './services'; + +interface SetupDeps { + licensing: LicensingPluginSetup; + management: ManagementSetup; + + home?: HomePublicPluginSetup; +} + +export class LogstashPlugin implements Plugin { + private licenseSubscription?: Subscription; + + public setup(core: CoreSetup, plugins: SetupDeps) { + const logstashLicense$ = plugins.licensing.license$.pipe( + map(license => new LogstashLicenseService(license)) + ); + const section = plugins.management.sections.register({ + id: 'logstash', + title: 'Logstash', + order: 30, + euiIconType: 'logoLogstash', + }); + const managementApp = section.registerApp({ + id: 'pipelines', + title: i18n.translate('xpack.logstash.managementSection.pipelinesTitle', { + defaultMessage: 'Pipelines', + }), + order: 10, + mount: async params => { + const [coreStart] = await core.getStartServices(); + const { renderApp } = await import('./application'); + + return renderApp(coreStart, params, logstashLicense$); + }, + }); + + this.licenseSubscription = logstashLicense$.subscribe((license: any) => { + if (license.enableLinks) { + managementApp.enable(); + } else { + managementApp.disable(); + } + + if (plugins.home && license.enableLinks) { + // Ensure that we don't register the feature more than once + once(() => { + plugins.home!.featureCatalogue.register({ + id: 'management_logstash', + title: i18n.translate('xpack.logstash.homeFeature.logstashPipelinesTitle', { + defaultMessage: 'Logstash Pipelines', + }), + description: i18n.translate('xpack.logstash.homeFeature.logstashPipelinesDescription', { + defaultMessage: 'Create, delete, update, and clone data ingestion pipelines.', + }), + icon: 'pipelineApp', + path: '/app/kibana#/management/logstash/pipelines', + showOnHomePage: true, + category: FeatureCatalogueCategory.ADMIN, + }); + }); + } + }); + } + + public start(core: CoreStart) {} + + public stop() { + if (this.licenseSubscription) { + this.licenseSubscription.unsubscribe(); + } + } +} diff --git a/x-pack/legacy/plugins/logstash/public/services/cluster/cluster_service.js b/x-pack/plugins/logstash/public/services/cluster/cluster_service.js similarity index 51% rename from x-pack/legacy/plugins/logstash/public/services/cluster/cluster_service.js rename to x-pack/plugins/logstash/public/services/cluster/cluster_service.js index e89c2fe7d11bf9..20f3b0d349c803 100755 --- a/x-pack/legacy/plugins/logstash/public/services/cluster/cluster_service.js +++ b/x-pack/plugins/logstash/public/services/cluster/cluster_service.js @@ -4,22 +4,20 @@ * you may not use this file except in compliance with the Elastic License. */ -import chrome from 'ui/chrome'; -import { ROUTES } from '../../../../../../plugins/logstash/common/constants'; -import { Cluster } from 'plugins/logstash/models/cluster'; +import { ROUTES } from '../../../common/constants'; +import { Cluster } from '../../models/cluster'; export class ClusterService { - constructor($http) { - this.$http = $http; - this.basePath = chrome.addBasePath(ROUTES.API_ROOT); + constructor(http) { + this.http = http; } loadCluster() { - return this.$http.get(`${this.basePath}/cluster`).then(response => { - if (!response.data) { + return this.http.get(`${ROUTES.API_ROOT}/cluster`).then(response => { + if (!response) { return; } - return Cluster.fromUpstreamJSON(response.data.cluster); + return Cluster.fromUpstreamJSON(response.cluster); }); } diff --git a/x-pack/legacy/plugins/logstash/public/sections/pipeline_edit/index.js b/x-pack/plugins/logstash/public/services/cluster/index.js similarity index 82% rename from x-pack/legacy/plugins/logstash/public/sections/pipeline_edit/index.js rename to x-pack/plugins/logstash/public/services/cluster/index.js index 4b699ed79cd26b..4417262d9f442e 100755 --- a/x-pack/legacy/plugins/logstash/public/sections/pipeline_edit/index.js +++ b/x-pack/plugins/logstash/public/services/cluster/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import './pipeline_edit_route'; +export { ClusterService } from './cluster_service'; diff --git a/x-pack/plugins/logstash/public/services/index.js b/x-pack/plugins/logstash/public/services/index.js new file mode 100644 index 00000000000000..a7e8aa5c6259f5 --- /dev/null +++ b/x-pack/plugins/logstash/public/services/index.js @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { ClusterService } from './cluster'; +export { LogstashLicenseService } from './license'; +export { MonitoringService } from './monitoring'; +export { PipelineService } from './pipeline'; +export { PipelinesService } from './pipelines'; +export { UpgradeService } from './upgrade'; diff --git a/x-pack/legacy/plugins/logstash/public/lib/update_management_sections/index.js b/x-pack/plugins/logstash/public/services/license/index.js similarity index 77% rename from x-pack/legacy/plugins/logstash/public/lib/update_management_sections/index.js rename to x-pack/plugins/logstash/public/services/license/index.js index 9d53d4dd61163c..64f39b1144cee3 100755 --- a/x-pack/legacy/plugins/logstash/public/lib/update_management_sections/index.js +++ b/x-pack/plugins/logstash/public/services/license/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { updateLogstashSections } from './update_logstash_sections'; +export { LogstashLicenseService } from './logstash_license_service'; diff --git a/x-pack/plugins/logstash/public/services/license/logstash_license_service.js b/x-pack/plugins/logstash/public/services/license/logstash_license_service.js new file mode 100755 index 00000000000000..b836b75b89cc70 --- /dev/null +++ b/x-pack/plugins/logstash/public/services/license/logstash_license_service.js @@ -0,0 +1,106 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; + +export class LogstashLicenseService { + constructor(license, navigateToApp, toasts) { + this.license = license; + this.navigateToApp = navigateToApp; + this.toasts = toasts; + } + + get enableLinks() { + return this.calculated.enableLinks; + } + + get isAvailable() { + return this.calculated.isAvailable; + } + + get isReadOnly() { + return this.calculated.isReadOnly; + } + + get message() { + return this.calculated.message; + } + + get isSecurityEnabled() { + return this.license.getFeature(`security`).isEnabled; + } + + /** + * Checks if the license is valid or the license can perform downgraded UI tasks. + * Rejects if the plugin is not available due to license. + */ + checkValidity() { + return new Promise((resolve, reject) => { + if (this.isAvailable) { + return resolve(); + } + + return reject(); + }); + } + + get calculated() { + if (!this.license) { + throw new Error(`No license available!`); + } + + if (!this.isSecurityEnabled) { + return { + isAvailable: false, + enableLinks: false, + isReadOnly: false, + message: i18n.translate('xpack.logstash.managementSection.enableSecurityDescription', { + defaultMessage: + 'Security must be enabled in order to use Logstash pipeline management features.' + + ' Please set xpack.security.enabled: true in your elasticsearch.yml.', + }), + }; + } + + if (!this.license.hasAtLeast('standard')) { + return { + isAvailable: false, + enableLinks: false, + isReadOnly: false, + message: i18n.translate( + 'xpack.logstash.managementSection.licenseDoesNotSupportDescription', + { + defaultMessage: + 'Your {licenseType} license does not support Logstash pipeline management features. Please upgrade your license.', + values: { licenseType: this.license.type }, + } + ), + }; + } + + if (!this.license.isActive) { + return { + isAvailable: true, + enableLinks: true, + isReadonly: true, + message: i18n.translate( + 'xpack.logstash.managementSection.pipelineCrudOperationsNotAllowedDescription', + { + defaultMessage: + 'You cannot edit, create, or delete your Logstash pipelines because your {licenseType} license has expired.', + values: { licenseType: this.license.type }, + } + ), + }; + } + + return { + isAvailable: true, + enableLinks: true, + isReadOnly: false, + }; + } +} diff --git a/x-pack/plugins/logstash/public/services/monitoring/index.js b/x-pack/plugins/logstash/public/services/monitoring/index.js new file mode 100755 index 00000000000000..bc0e8b6bc978a7 --- /dev/null +++ b/x-pack/plugins/logstash/public/services/monitoring/index.js @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { MonitoringService } from './monitoring_service'; diff --git a/x-pack/legacy/plugins/logstash/public/services/monitoring/monitoring_service.js b/x-pack/plugins/logstash/public/services/monitoring/monitoring_service.js similarity index 58% rename from x-pack/legacy/plugins/logstash/public/services/monitoring/monitoring_service.js rename to x-pack/plugins/logstash/public/services/monitoring/monitoring_service.js index 6103e730c21714..d551f4fba61d2e 100755 --- a/x-pack/legacy/plugins/logstash/public/services/monitoring/monitoring_service.js +++ b/x-pack/plugins/logstash/public/services/monitoring/monitoring_service.js @@ -5,17 +5,14 @@ */ import moment from 'moment'; -import chrome from 'ui/chrome'; -import { ROUTES, MONITORING } from '../../../../../../plugins/logstash/common/constants'; -import { PipelineListItem } from 'plugins/logstash/models/pipeline_list_item'; +import { ROUTES, MONITORING } from '../../../common/constants'; +import { PipelineListItem } from '../../models/pipeline_list_item'; export class MonitoringService { - constructor($http, Promise, monitoringUiEnabled, clusterService) { - this.$http = $http; - this.Promise = Promise; + constructor(http, monitoringUiEnabled, clusterService) { + this.http = http; this.monitoringUiEnabled = monitoringUiEnabled; this.clusterService = clusterService; - this.basePath = chrome.addBasePath(ROUTES.MONITORING_API_ROOT); } isMonitoringEnabled() { @@ -30,18 +27,18 @@ export class MonitoringService { return this.clusterService .loadCluster() .then(cluster => { - const url = `${this.basePath}/v1/clusters/${cluster.uuid}/logstash/pipeline_ids`; + const url = `${ROUTES.MONITORING_API_ROOT}/v1/clusters/${cluster.uuid}/logstash/pipeline_ids`; const now = moment.utc(); - const body = { + const body = JSON.stringify({ timeRange: { max: now.toISOString(), min: now.subtract(MONITORING.ACTIVE_PIPELINE_RANGE_S, 'seconds').toISOString(), }, - }; - return this.$http.post(url, body); + }); + return this.http.post(url, { body }); }) .then(response => - response.data.map(pipeline => PipelineListItem.fromUpstreamMonitoringJSON(pipeline)) + response.map(pipeline => PipelineListItem.fromUpstreamMonitoringJSON(pipeline)) ) .catch(() => []); } diff --git a/x-pack/legacy/plugins/logstash/public/sections/pipeline_edit/components/pipeline_edit/index.js b/x-pack/plugins/logstash/public/services/pipeline/index.js similarity index 81% rename from x-pack/legacy/plugins/logstash/public/sections/pipeline_edit/components/pipeline_edit/index.js rename to x-pack/plugins/logstash/public/services/pipeline/index.js index 5889bbdf96a93c..70d228b34860b9 100755 --- a/x-pack/legacy/plugins/logstash/public/sections/pipeline_edit/components/pipeline_edit/index.js +++ b/x-pack/plugins/logstash/public/services/pipeline/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import './pipeline_edit'; +export { PipelineService } from './pipeline_service'; diff --git a/x-pack/plugins/logstash/public/services/pipeline/pipeline_service.js b/x-pack/plugins/logstash/public/services/pipeline/pipeline_service.js new file mode 100755 index 00000000000000..7c3e18e745d821 --- /dev/null +++ b/x-pack/plugins/logstash/public/services/pipeline/pipeline_service.js @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ROUTES } from '../../../common/constants'; +import { Pipeline } from '../../models/pipeline'; + +export class PipelineService { + constructor(http, pipelinesService) { + this.http = http; + this.pipelinesService = pipelinesService; + } + + loadPipeline(id) { + return this.http.get(`${ROUTES.API_ROOT}/pipeline/${id}`).then(response => { + return Pipeline.fromUpstreamJSON(response); + }); + } + + savePipeline(pipelineModel) { + return this.http + .put(`${ROUTES.API_ROOT}/pipeline/${pipelineModel.id}`, { + body: JSON.stringify(pipelineModel.upstreamJSON), + }) + .catch(e => { + throw e.message; + }); + } + + deletePipeline(id) { + return this.http + .delete(`${ROUTES.API_ROOT}/pipeline/${id}`) + .then(() => this.pipelinesService.addToRecentlyDeleted(id)) + .catch(e => { + throw e.message; + }); + } +} diff --git a/x-pack/plugins/logstash/public/services/pipelines/index.js b/x-pack/plugins/logstash/public/services/pipelines/index.js new file mode 100755 index 00000000000000..a932dd4b951f4e --- /dev/null +++ b/x-pack/plugins/logstash/public/services/pipelines/index.js @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { PipelinesService } from './pipelines_service'; diff --git a/x-pack/plugins/logstash/public/services/pipelines/pipelines_service.js b/x-pack/plugins/logstash/public/services/pipelines/pipelines_service.js new file mode 100755 index 00000000000000..00610a23f27177 --- /dev/null +++ b/x-pack/plugins/logstash/public/services/pipelines/pipelines_service.js @@ -0,0 +1,128 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ROUTES, MONITORING } from '../../../common/constants'; +import { PipelineListItem } from '../../models/pipeline_list_item'; + +const RECENTLY_DELETED_PIPELINE_IDS_STORAGE_KEY = 'xpack.logstash.recentlyDeletedPipelines'; + +export class PipelinesService { + constructor(http, monitoringService) { + this.http = http; + this.monitoringService = monitoringService; + } + + getPipelineList() { + return Promise.all([this.getManagementPipelineList(), this.getMonitoringPipelineList()]).then( + ([managementPipelines, monitoringPipelines]) => { + const now = Date.now(); + + // Monitoring will report centrally-managed pipelines as well, including recently-deleted centrally-managed ones. + // If there's a recently-deleted pipeline we're keeping track of BUT monitoring doesn't report it, that means + // it's not running in Logstash any more. So we can stop tracking it as a recently-deleted pipeline. + const monitoringPipelineIds = monitoringPipelines.map(pipeline => pipeline.id); + this.getRecentlyDeleted().forEach(recentlyDeletedPipeline => { + // We don't want to stop tracking the recently-deleted pipeline until Monitoring has had some + // time to report on it. Otherwise, if we stop tracking first, *then* Monitoring reports it, we'll + // still end up showing it in the list until Monitoring stops reporting it. + if (now - recentlyDeletedPipeline.deletedOn < MONITORING.ACTIVE_PIPELINE_RANGE_S * 1000) { + return; + } + + // If Monitoring is still reporting the pipeline, don't stop tracking it yet + if (monitoringPipelineIds.includes(recentlyDeletedPipeline.id)) { + return; + } + + this.removeFromRecentlyDeleted(recentlyDeletedPipeline.id); + }); + + // Merge centrally-managed pipelines with pipelines reported by monitoring. Take care to dedupe + // while merging because monitoring will (rightly) report centrally-managed pipelines as well, + // including recently-deleted ones! + const managementPipelineIds = managementPipelines.map(pipeline => pipeline.id); + return managementPipelines.concat( + monitoringPipelines.filter( + monitoringPipeline => + !managementPipelineIds.includes(monitoringPipeline.id) && + !this.isRecentlyDeleted(monitoringPipeline.id) + ) + ); + } + ); + } + + getManagementPipelineList() { + return this.http.get(`${ROUTES.API_ROOT}/pipelines`).then(response => { + return response.pipelines.map(pipeline => PipelineListItem.fromUpstreamJSON(pipeline)); + }); + } + + getMonitoringPipelineList() { + return this.monitoringService.getPipelineList(); + } + + /** + * Delete a collection of pipelines + * + * @param pipelineIds Array of pipeline IDs + * @return Promise { numSuccesses, numErrors } + */ + deletePipelines(pipelineIds) { + const body = JSON.stringify({ + pipelineIds, + }); + return this.http.post(`${ROUTES.API_ROOT}/pipelines/delete`, { body }).then(response => { + this.addToRecentlyDeleted(...pipelineIds); + return response.results; + }); + } + + addToRecentlyDeleted(...pipelineIds) { + const recentlyDeletedPipelines = this.getRecentlyDeleted(); + const recentlyDeletedPipelineIds = recentlyDeletedPipelines.map(pipeline => pipeline.id); + pipelineIds.forEach(pipelineId => { + if (!recentlyDeletedPipelineIds.includes(pipelineId)) { + recentlyDeletedPipelines.push({ + id: pipelineId, + deletedOn: Date.now(), + }); + } + }); + this.setRecentlyDeleted(recentlyDeletedPipelines); + } + + removeFromRecentlyDeleted(...pipelineIds) { + const recentlyDeletedPipelinesToKeep = this.getRecentlyDeleted().filter( + recentlyDeletedPipeline => !pipelineIds.includes(recentlyDeletedPipeline.id) + ); + this.setRecentlyDeleted(recentlyDeletedPipelinesToKeep); + } + + isRecentlyDeleted(pipelineId) { + return this.getRecentlyDeleted() + .map(pipeline => pipeline.id) + .includes(pipelineId); + } + + getRecentlyDeleted() { + const recentlyDeletedPipelines = window.localStorage.getItem( + RECENTLY_DELETED_PIPELINE_IDS_STORAGE_KEY + ); + if (!recentlyDeletedPipelines) { + return []; + } + + return JSON.parse(recentlyDeletedPipelines); + } + + setRecentlyDeleted(recentlyDeletedPipelineIds) { + window.localStorage.setItem( + RECENTLY_DELETED_PIPELINE_IDS_STORAGE_KEY, + JSON.stringify(recentlyDeletedPipelineIds) + ); + } +} diff --git a/x-pack/legacy/plugins/logstash/public/sections/pipeline_edit/components/upgrade_failure/index.js b/x-pack/plugins/logstash/public/services/upgrade/index.js similarity index 82% rename from x-pack/legacy/plugins/logstash/public/sections/pipeline_edit/components/upgrade_failure/index.js rename to x-pack/plugins/logstash/public/services/upgrade/index.js index 3a9a6b860c51f1..1c835b11ae4233 100755 --- a/x-pack/legacy/plugins/logstash/public/sections/pipeline_edit/components/upgrade_failure/index.js +++ b/x-pack/plugins/logstash/public/services/upgrade/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -import './upgrade_failure'; +export { UpgradeService } from './upgrade_service'; diff --git a/x-pack/plugins/logstash/public/services/upgrade/upgrade_service.js b/x-pack/plugins/logstash/public/services/upgrade/upgrade_service.js new file mode 100755 index 00000000000000..7bd101ebee6b00 --- /dev/null +++ b/x-pack/plugins/logstash/public/services/upgrade/upgrade_service.js @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ROUTES } from '../../../common/constants'; + +export class UpgradeService { + constructor(http) { + this.http = http; + } + + executeUpgrade() { + return this.http + .post(`${ROUTES.API_ROOT}/upgrade`) + .then(response => response.is_upgraded) + .catch(e => { + throw e.message; + }); + } +} diff --git a/x-pack/plugins/logstash/server/routes/pipeline/save.ts b/x-pack/plugins/logstash/server/routes/pipeline/save.ts index 556c281944a856..e484d0e221b6d1 100644 --- a/x-pack/plugins/logstash/server/routes/pipeline/save.ts +++ b/x-pack/plugins/logstash/server/routes/pipeline/save.ts @@ -25,7 +25,6 @@ export function registerPipelineSaveRoute(router: IRouter, security?: SecurityPl id: schema.string(), description: schema.string(), pipeline: schema.string(), - username: schema.string(), settings: schema.maybe(schema.object({}, { unknowns: 'allow' })), }), }, diff --git a/x-pack/plugins/maps/common/constants.ts b/x-pack/plugins/maps/common/constants.ts index 160f9d8dbc83f6..a4006732224ce3 100644 --- a/x-pack/plugins/maps/common/constants.ts +++ b/x-pack/plugins/maps/common/constants.ts @@ -40,9 +40,10 @@ export function createMapPath(id: string) { export enum LAYER_TYPE { TILE = 'TILE', VECTOR = 'VECTOR', - VECTOR_TILE = 'VECTOR_TILE', + VECTOR_TILE = 'VECTOR_TILE', // for static display of mvt vector tiles with a mapbox stylesheet. Does not support any ad-hoc configurations. Used for consuming EMS vector tiles. HEATMAP = 'HEATMAP', BLENDED_VECTOR = 'BLENDED_VECTOR', + TILED_VECTOR = 'TILED_VECTOR', // similar to a regular vector-layer, but it consumes the data as .mvt tilea iso GeoJson. It supports similar ad-hoc configurations like a regular vector layer (E.g. using IVectorStyle), although there is some loss of functionality e.g. does not support term joining } export enum SORT_ORDER { @@ -61,6 +62,7 @@ export enum SOURCE_TYPES { KIBANA_TILEMAP = 'KIBANA_TILEMAP', REGIONMAP_FILE = 'REGIONMAP_FILE', GEOJSON_FILE = 'GEOJSON_FILE', + MVT_SINGLE_LAYER = 'MVT_SINGLE_LAYER', } export enum FIELD_ORIGIN { diff --git a/x-pack/plugins/maps/common/descriptor_types/data_request_descriptor_types.d.ts b/x-pack/plugins/maps/common/descriptor_types/data_request_descriptor_types.d.ts index 26044d28d53a32..e94dc6694b38d1 100644 --- a/x-pack/plugins/maps/common/descriptor_types/data_request_descriptor_types.d.ts +++ b/x-pack/plugins/maps/common/descriptor_types/data_request_descriptor_types.d.ts @@ -31,12 +31,12 @@ type ESGeoGridSourceSyncMeta = { requestType: RENDER_AS; }; -export type VectorSourceSyncMeta = ESSearchSourceSyncMeta | ESGeoGridSourceSyncMeta; +export type VectorSourceSyncMeta = ESSearchSourceSyncMeta | ESGeoGridSourceSyncMeta | null; export type VectorSourceRequestMeta = MapFilters & { applyGlobalQuery: boolean; fieldNames: string[]; - geogridPrecision: number; + geogridPrecision?: number; sourceQuery: MapQuery; sourceMeta: VectorSourceSyncMeta; }; diff --git a/x-pack/plugins/maps/common/descriptor_types/descriptor_types.d.ts b/x-pack/plugins/maps/common/descriptor_types/descriptor_types.d.ts index ff285877750c5c..f8175b0ed3f109 100644 --- a/x-pack/plugins/maps/common/descriptor_types/descriptor_types.d.ts +++ b/x-pack/plugins/maps/common/descriptor_types/descriptor_types.d.ts @@ -94,6 +94,18 @@ export type XYZTMSSourceDescriptor = AbstractSourceDescriptor & urlTemplate: string; }; +export type TiledSingleLayerVectorSourceDescriptor = AbstractSourceDescriptor & { + urlTemplate: string; + layerName: string; + + // These are the min/max zoom levels of the availability of the a particular layerName in the tileset at urlTemplate. + // These are _not_ the visible zoom-range of the data on a map. + // Tiled data can be displayed at higher levels of zoom than that they are stored in the tileset. + // e.g. EMS basemap data from level 14 is at most detailed resolution and can be displayed at higher levels + minSourceZoom: number; + maxSourceZoom: number; +}; + export type JoinDescriptor = { leftField: string; right: ESTermSourceDescriptor; @@ -107,7 +119,9 @@ export type SourceDescriptor = | ESTermSourceDescriptor | ESSearchSourceDescriptor | ESGeoGridSourceDescriptor - | EMSFileSourceDescriptor; + | EMSFileSourceDescriptor + | ESPewPewSourceDescriptor + | TiledSingleLayerVectorSourceDescriptor; export type LayerDescriptor = { __dataRequests?: DataRequestDescriptor[]; diff --git a/x-pack/legacy/plugins/maps/common/migrations/add_field_meta_options.js b/x-pack/plugins/maps/common/migrations/add_field_meta_options.js similarity index 100% rename from x-pack/legacy/plugins/maps/common/migrations/add_field_meta_options.js rename to x-pack/plugins/maps/common/migrations/add_field_meta_options.js diff --git a/x-pack/legacy/plugins/maps/common/migrations/add_field_meta_options.test.js b/x-pack/plugins/maps/common/migrations/add_field_meta_options.test.js similarity index 100% rename from x-pack/legacy/plugins/maps/common/migrations/add_field_meta_options.test.js rename to x-pack/plugins/maps/common/migrations/add_field_meta_options.test.js diff --git a/x-pack/legacy/plugins/maps/common/migrations/ems_raster_tile_to_ems_vector_tile.js b/x-pack/plugins/maps/common/migrations/ems_raster_tile_to_ems_vector_tile.js similarity index 100% rename from x-pack/legacy/plugins/maps/common/migrations/ems_raster_tile_to_ems_vector_tile.js rename to x-pack/plugins/maps/common/migrations/ems_raster_tile_to_ems_vector_tile.js diff --git a/x-pack/legacy/plugins/maps/common/migrations/ems_raster_tile_to_ems_vector_tile.test.js b/x-pack/plugins/maps/common/migrations/ems_raster_tile_to_ems_vector_tile.test.js similarity index 100% rename from x-pack/legacy/plugins/maps/common/migrations/ems_raster_tile_to_ems_vector_tile.test.js rename to x-pack/plugins/maps/common/migrations/ems_raster_tile_to_ems_vector_tile.test.js diff --git a/x-pack/legacy/plugins/maps/common/migrations/join_agg_key.test.ts b/x-pack/plugins/maps/common/migrations/join_agg_key.test.ts similarity index 100% rename from x-pack/legacy/plugins/maps/common/migrations/join_agg_key.test.ts rename to x-pack/plugins/maps/common/migrations/join_agg_key.test.ts diff --git a/x-pack/legacy/plugins/maps/common/migrations/join_agg_key.ts b/x-pack/plugins/maps/common/migrations/join_agg_key.ts similarity index 97% rename from x-pack/legacy/plugins/maps/common/migrations/join_agg_key.ts rename to x-pack/plugins/maps/common/migrations/join_agg_key.ts index 29661aedb550c5..97b9ee4692c253 100644 --- a/x-pack/legacy/plugins/maps/common/migrations/join_agg_key.ts +++ b/x-pack/plugins/maps/common/migrations/join_agg_key.ts @@ -20,7 +20,7 @@ import { LayerDescriptor, VectorLayerDescriptor, } from '../descriptor_types'; -import { MapSavedObjectAttributes } from '../../../../../plugins/maps/common/map_saved_object_type'; +import { MapSavedObjectAttributes } from '../map_saved_object_type'; const GROUP_BY_DELIMITER = '_groupby_'; diff --git a/x-pack/legacy/plugins/maps/common/migrations/migrate_symbol_style_descriptor.js b/x-pack/plugins/maps/common/migrations/migrate_symbol_style_descriptor.js similarity index 100% rename from x-pack/legacy/plugins/maps/common/migrations/migrate_symbol_style_descriptor.js rename to x-pack/plugins/maps/common/migrations/migrate_symbol_style_descriptor.js diff --git a/x-pack/legacy/plugins/maps/common/migrations/migrate_symbol_style_descriptor.test.js b/x-pack/plugins/maps/common/migrations/migrate_symbol_style_descriptor.test.js similarity index 100% rename from x-pack/legacy/plugins/maps/common/migrations/migrate_symbol_style_descriptor.test.js rename to x-pack/plugins/maps/common/migrations/migrate_symbol_style_descriptor.test.js diff --git a/x-pack/legacy/plugins/maps/common/migrations/move_apply_global_query.js b/x-pack/plugins/maps/common/migrations/move_apply_global_query.js similarity index 100% rename from x-pack/legacy/plugins/maps/common/migrations/move_apply_global_query.js rename to x-pack/plugins/maps/common/migrations/move_apply_global_query.js diff --git a/x-pack/legacy/plugins/maps/common/migrations/move_apply_global_query.test.js b/x-pack/plugins/maps/common/migrations/move_apply_global_query.test.js similarity index 100% rename from x-pack/legacy/plugins/maps/common/migrations/move_apply_global_query.test.js rename to x-pack/plugins/maps/common/migrations/move_apply_global_query.test.js diff --git a/x-pack/legacy/plugins/maps/common/migrations/references.js b/x-pack/plugins/maps/common/migrations/references.js similarity index 100% rename from x-pack/legacy/plugins/maps/common/migrations/references.js rename to x-pack/plugins/maps/common/migrations/references.js diff --git a/x-pack/legacy/plugins/maps/common/migrations/references.test.js b/x-pack/plugins/maps/common/migrations/references.test.js similarity index 100% rename from x-pack/legacy/plugins/maps/common/migrations/references.test.js rename to x-pack/plugins/maps/common/migrations/references.test.js diff --git a/x-pack/legacy/plugins/maps/common/migrations/scaling_type.test.ts b/x-pack/plugins/maps/common/migrations/scaling_type.test.ts similarity index 100% rename from x-pack/legacy/plugins/maps/common/migrations/scaling_type.test.ts rename to x-pack/plugins/maps/common/migrations/scaling_type.test.ts diff --git a/x-pack/legacy/plugins/maps/common/migrations/scaling_type.ts b/x-pack/plugins/maps/common/migrations/scaling_type.ts similarity index 93% rename from x-pack/legacy/plugins/maps/common/migrations/scaling_type.ts rename to x-pack/plugins/maps/common/migrations/scaling_type.ts index 551975fbacea52..98a06a764f4ec4 100644 --- a/x-pack/legacy/plugins/maps/common/migrations/scaling_type.ts +++ b/x-pack/plugins/maps/common/migrations/scaling_type.ts @@ -7,7 +7,7 @@ import _ from 'lodash'; import { SOURCE_TYPES, SCALING_TYPES } from '../constants'; import { LayerDescriptor, ESSearchSourceDescriptor } from '../descriptor_types'; -import { MapSavedObjectAttributes } from '../../../../../plugins/maps/common/map_saved_object_type'; +import { MapSavedObjectAttributes } from '../map_saved_object_type'; function isEsDocumentSource(layerDescriptor: LayerDescriptor) { const sourceType = _.get(layerDescriptor, 'sourceDescriptor.type'); diff --git a/x-pack/legacy/plugins/maps/common/migrations/top_hits_time_to_sort.js b/x-pack/plugins/maps/common/migrations/top_hits_time_to_sort.js similarity index 100% rename from x-pack/legacy/plugins/maps/common/migrations/top_hits_time_to_sort.js rename to x-pack/plugins/maps/common/migrations/top_hits_time_to_sort.js diff --git a/x-pack/legacy/plugins/maps/common/migrations/top_hits_time_to_sort.test.js b/x-pack/plugins/maps/common/migrations/top_hits_time_to_sort.test.js similarity index 100% rename from x-pack/legacy/plugins/maps/common/migrations/top_hits_time_to_sort.test.js rename to x-pack/plugins/maps/common/migrations/top_hits_time_to_sort.test.js diff --git a/x-pack/plugins/maps/kibana.json b/x-pack/plugins/maps/kibana.json index b2aec30c113eb6..00c5e70ad6b8de 100644 --- a/x-pack/plugins/maps/kibana.json +++ b/x-pack/plugins/maps/kibana.json @@ -3,6 +3,14 @@ "version": "8.0.0", "kibanaVersion": "kibana", "configPath": ["xpack", "maps"], - "requiredPlugins": ["inspector"], + "requiredPlugins": [ + "inspector", + "home", + "data", + "fileUpload", + "uiActions", + "navigation", + "visualizations" + ], "ui": true } diff --git a/x-pack/legacy/plugins/maps/public/_main.scss b/x-pack/plugins/maps/public/_main.scss similarity index 100% rename from x-pack/legacy/plugins/maps/public/_main.scss rename to x-pack/plugins/maps/public/_main.scss diff --git a/x-pack/legacy/plugins/maps/public/_mapbox_hacks.scss b/x-pack/plugins/maps/public/_mapbox_hacks.scss similarity index 100% rename from x-pack/legacy/plugins/maps/public/_mapbox_hacks.scss rename to x-pack/plugins/maps/public/_mapbox_hacks.scss diff --git a/x-pack/plugins/maps/public/actions/map_actions.js b/x-pack/plugins/maps/public/actions/map_actions.js index 13cb3d5f898601..572385d628b16a 100644 --- a/x-pack/plugins/maps/public/actions/map_actions.js +++ b/x-pack/plugins/maps/public/actions/map_actions.js @@ -4,6 +4,37 @@ * you may not use this file except in compliance with the Elastic License. */ +import _ from 'lodash'; +import turf from 'turf'; +import turfBooleanContains from '@turf/boolean-contains'; +import uuid from 'uuid/v4'; +import { + getLayerList, + getLayerListRaw, + getDataFilters, + getSelectedLayerId, + getMapReady, + getWaitingForMapReadyLayerListRaw, + getTransientLayerId, + getOpenTooltips, + getQuery, + getDataRequestDescriptor, +} from '../selectors/map_selectors'; + +import { FLYOUT_STATE } from '../reducers/ui'; +import { + cancelRequest, + registerCancelCallback, + unregisterCancelCallback, + getEventHandlers, +} from '../reducers/non_serializable_instances'; +import { updateFlyout } from './ui_actions'; +import { + FEATURE_ID_PROPERTY_NAME, + LAYER_TYPE, + SOURCE_DATA_ID_ORIGIN, +} from '../../common/constants'; + export const SET_SELECTED_LAYER = 'SET_SELECTED_LAYER'; export const SET_TRANSIENT_LAYER = 'SET_TRANSIENT_LAYER'; export const UPDATE_LAYER_ORDER = 'UPDATE_LAYER_ORDER'; @@ -45,3 +76,897 @@ export const HIDE_TOOLBAR_OVERLAY = 'HIDE_TOOLBAR_OVERLAY'; export const HIDE_LAYER_CONTROL = 'HIDE_LAYER_CONTROL'; export const HIDE_VIEW_CONTROL = 'HIDE_VIEW_CONTROL'; export const SET_WAITING_FOR_READY_HIDDEN_LAYERS = 'SET_WAITING_FOR_READY_HIDDEN_LAYERS'; + +function getLayerLoadingCallbacks(dispatch, getState, layerId) { + return { + startLoading: (dataId, requestToken, meta) => + dispatch(startDataLoad(layerId, dataId, requestToken, meta)), + stopLoading: (dataId, requestToken, data, meta) => + dispatch(endDataLoad(layerId, dataId, requestToken, data, meta)), + onLoadError: (dataId, requestToken, errorMessage) => + dispatch(onDataLoadError(layerId, dataId, requestToken, errorMessage)), + updateSourceData: newData => { + dispatch(updateSourceDataRequest(layerId, newData)); + }, + isRequestStillActive: (dataId, requestToken) => { + const dataRequest = getDataRequestDescriptor(getState(), layerId, dataId); + if (!dataRequest) { + return false; + } + return dataRequest.dataRequestToken === requestToken; + }, + registerCancelCallback: (requestToken, callback) => + dispatch(registerCancelCallback(requestToken, callback)), + }; +} + +function getLayerById(layerId, state) { + return getLayerList(state).find(layer => { + return layerId === layer.getId(); + }); +} + +async function syncDataForAllLayers(dispatch, getState, dataFilters) { + const state = getState(); + const layerList = getLayerList(state); + const syncs = layerList.map(layer => { + const loadingFunctions = getLayerLoadingCallbacks(dispatch, getState, layer.getId()); + return layer.syncData({ ...loadingFunctions, dataFilters }); + }); + await Promise.all(syncs); +} + +export function cancelAllInFlightRequests() { + return (dispatch, getState) => { + getLayerList(getState()).forEach(layer => { + dispatch(clearDataRequests(layer)); + }); + }; +} + +function clearDataRequests(layer) { + return dispatch => { + layer.getInFlightRequestTokens().forEach(requestToken => { + dispatch(cancelRequest(requestToken)); + }); + dispatch({ + type: UPDATE_LAYER_PROP, + id: layer.getId(), + propName: '__dataRequests', + newValue: [], + }); + }; +} + +export function setMapInitError(errorMessage) { + return { + type: SET_MAP_INIT_ERROR, + errorMessage, + }; +} + +export function trackCurrentLayerState(layerId) { + return { + type: TRACK_CURRENT_LAYER_STATE, + layerId: layerId, + }; +} + +export function rollbackToTrackedLayerStateForSelectedLayer() { + return async (dispatch, getState) => { + const layerId = getSelectedLayerId(getState()); + await dispatch({ + type: ROLLBACK_TO_TRACKED_LAYER_STATE, + layerId: layerId, + }); + + // Ensure updateStyleMeta is triggered + // syncDataForLayer may not trigger endDataLoad if no re-fetch is required + dispatch(updateStyleMeta(layerId)); + + dispatch(syncDataForLayer(layerId)); + }; +} + +export function removeTrackedLayerStateForSelectedLayer() { + return (dispatch, getState) => { + const layerId = getSelectedLayerId(getState()); + dispatch({ + type: REMOVE_TRACKED_LAYER_STATE, + layerId: layerId, + }); + }; +} + +export function replaceLayerList(newLayerList) { + return (dispatch, getState) => { + const isMapReady = getMapReady(getState()); + if (!isMapReady) { + dispatch({ + type: CLEAR_WAITING_FOR_MAP_READY_LAYER_LIST, + }); + } else { + getLayerListRaw(getState()).forEach(({ id }) => { + dispatch(removeLayerFromLayerList(id)); + }); + } + + newLayerList.forEach(layerDescriptor => { + dispatch(addLayer(layerDescriptor)); + }); + }; +} + +export function cloneLayer(layerId) { + return async (dispatch, getState) => { + const layer = getLayerById(layerId, getState()); + if (!layer) { + return; + } + + const clonedDescriptor = await layer.cloneDescriptor(); + dispatch(addLayer(clonedDescriptor)); + }; +} + +export function addLayer(layerDescriptor) { + return (dispatch, getState) => { + const isMapReady = getMapReady(getState()); + if (!isMapReady) { + dispatch({ + type: ADD_WAITING_FOR_MAP_READY_LAYER, + layer: layerDescriptor, + }); + return; + } + + dispatch({ + type: ADD_LAYER, + layer: layerDescriptor, + }); + dispatch(syncDataForLayer(layerDescriptor.id)); + }; +} + +// Do not use when rendering a map. Method exists to enable selectors for getLayerList when +// rendering is not needed. +export function addLayerWithoutDataSync(layerDescriptor) { + return { + type: ADD_LAYER, + layer: layerDescriptor, + }; +} + +function setLayerDataLoadErrorStatus(layerId, errorMessage) { + return dispatch => { + dispatch({ + type: SET_LAYER_ERROR_STATUS, + isInErrorState: errorMessage !== null, + layerId, + errorMessage, + }); + }; +} + +export function cleanTooltipStateForLayer(layerId, layerFeatures = []) { + return (dispatch, getState) => { + let featuresRemoved = false; + const openTooltips = getOpenTooltips(getState()) + .map(tooltipState => { + const nextFeatures = tooltipState.features.filter(tooltipFeature => { + if (tooltipFeature.layerId !== layerId) { + // feature from another layer, keep it + return true; + } + + // Keep feature if it is still in layer + return layerFeatures.some(layerFeature => { + return layerFeature.properties[FEATURE_ID_PROPERTY_NAME] === tooltipFeature.id; + }); + }); + + if (tooltipState.features.length !== nextFeatures.length) { + featuresRemoved = true; + } + + return { ...tooltipState, features: nextFeatures }; + }) + .filter(tooltipState => { + return tooltipState.features.length > 0; + }); + + if (featuresRemoved) { + dispatch({ + type: SET_OPEN_TOOLTIPS, + openTooltips, + }); + } + }; +} + +export function setLayerVisibility(layerId, makeVisible) { + return async (dispatch, getState) => { + //if the current-state is invisible, we also want to sync data + //e.g. if a layer was invisible at start-up, it won't have any data loaded + const layer = getLayerById(layerId, getState()); + + // If the layer visibility is already what we want it to be, do nothing + if (!layer || layer.isVisible() === makeVisible) { + return; + } + + if (!makeVisible) { + dispatch(cleanTooltipStateForLayer(layerId)); + } + + await dispatch({ + type: SET_LAYER_VISIBILITY, + layerId, + visibility: makeVisible, + }); + if (makeVisible) { + dispatch(syncDataForLayer(layerId)); + } + }; +} + +export function toggleLayerVisible(layerId) { + return async (dispatch, getState) => { + const layer = getLayerById(layerId, getState()); + if (!layer) { + return; + } + const makeVisible = !layer.isVisible(); + + dispatch(setLayerVisibility(layerId, makeVisible)); + }; +} + +export function setSelectedLayer(layerId) { + return async (dispatch, getState) => { + const oldSelectedLayer = getSelectedLayerId(getState()); + if (oldSelectedLayer) { + await dispatch(rollbackToTrackedLayerStateForSelectedLayer()); + } + if (layerId) { + dispatch(trackCurrentLayerState(layerId)); + } + dispatch({ + type: SET_SELECTED_LAYER, + selectedLayerId: layerId, + }); + }; +} + +export function removeTransientLayer() { + return async (dispatch, getState) => { + const transientLayerId = getTransientLayerId(getState()); + if (transientLayerId) { + await dispatch(removeLayerFromLayerList(transientLayerId)); + await dispatch(setTransientLayer(null)); + } + }; +} + +export function setTransientLayer(layerId) { + return { + type: SET_TRANSIENT_LAYER, + transientLayerId: layerId, + }; +} + +export function clearTransientLayerStateAndCloseFlyout() { + return async dispatch => { + await dispatch(updateFlyout(FLYOUT_STATE.NONE)); + await dispatch(setSelectedLayer(null)); + await dispatch(removeTransientLayer()); + }; +} + +export function updateLayerOrder(newLayerOrder) { + return { + type: UPDATE_LAYER_ORDER, + newLayerOrder, + }; +} + +export function mapReady() { + return (dispatch, getState) => { + dispatch({ + type: MAP_READY, + }); + + getWaitingForMapReadyLayerListRaw(getState()).forEach(layerDescriptor => { + dispatch(addLayer(layerDescriptor)); + }); + + dispatch({ + type: CLEAR_WAITING_FOR_MAP_READY_LAYER_LIST, + }); + }; +} + +export function mapDestroyed() { + return { + type: MAP_DESTROYED, + }; +} + +export function mapExtentChanged(newMapConstants) { + return async (dispatch, getState) => { + const state = getState(); + const dataFilters = getDataFilters(state); + const { extent, zoom: newZoom } = newMapConstants; + const { buffer, zoom: currentZoom } = dataFilters; + + if (extent) { + let doesBufferContainExtent = false; + if (buffer) { + const bufferGeometry = turf.bboxPolygon([ + buffer.minLon, + buffer.minLat, + buffer.maxLon, + buffer.maxLat, + ]); + const extentGeometry = turf.bboxPolygon([ + extent.minLon, + extent.minLat, + extent.maxLon, + extent.maxLat, + ]); + + doesBufferContainExtent = turfBooleanContains(bufferGeometry, extentGeometry); + } + + if (!doesBufferContainExtent || currentZoom !== newZoom) { + const scaleFactor = 0.5; // TODO put scale factor in store and fetch with selector + const width = extent.maxLon - extent.minLon; + const height = extent.maxLat - extent.minLat; + dataFilters.buffer = { + minLon: extent.minLon - width * scaleFactor, + minLat: extent.minLat - height * scaleFactor, + maxLon: extent.maxLon + width * scaleFactor, + maxLat: extent.maxLat + height * scaleFactor, + }; + } + } + + dispatch({ + type: MAP_EXTENT_CHANGED, + mapState: { + ...dataFilters, + ...newMapConstants, + }, + }); + const newDataFilters = { ...dataFilters, ...newMapConstants }; + await syncDataForAllLayers(dispatch, getState, newDataFilters); + }; +} + +export function closeOnClickTooltip(tooltipId) { + return (dispatch, getState) => { + dispatch({ + type: SET_OPEN_TOOLTIPS, + openTooltips: getOpenTooltips(getState()).filter(({ id }) => { + return tooltipId !== id; + }), + }); + }; +} + +export function openOnClickTooltip(tooltipState) { + return (dispatch, getState) => { + const openTooltips = getOpenTooltips(getState()).filter(({ features, location, isLocked }) => { + return ( + isLocked && + !_.isEqual(location, tooltipState.location) && + !_.isEqual(features, tooltipState.features) + ); + }); + + openTooltips.push({ + ...tooltipState, + isLocked: true, + id: uuid(), + }); + + dispatch({ + type: SET_OPEN_TOOLTIPS, + openTooltips, + }); + }; +} + +export function closeOnHoverTooltip() { + return (dispatch, getState) => { + if (getOpenTooltips(getState()).length) { + dispatch({ + type: SET_OPEN_TOOLTIPS, + openTooltips: [], + }); + } + }; +} + +export function openOnHoverTooltip(tooltipState) { + return { + type: SET_OPEN_TOOLTIPS, + openTooltips: [ + { + ...tooltipState, + isLocked: false, + id: uuid(), + }, + ], + }; +} + +export function setMouseCoordinates({ lat, lon }) { + let safeLon = lon; + if (lon > 180) { + const overlapWestOfDateLine = lon - 180; + safeLon = -180 + overlapWestOfDateLine; + } else if (lon < -180) { + const overlapEastOfDateLine = Math.abs(lon) - 180; + safeLon = 180 - overlapEastOfDateLine; + } + + return { + type: SET_MOUSE_COORDINATES, + lat, + lon: safeLon, + }; +} + +export function clearMouseCoordinates() { + return { type: CLEAR_MOUSE_COORDINATES }; +} + +export function disableScrollZoom() { + return { type: SET_SCROLL_ZOOM, scrollZoom: false }; +} + +export function fitToLayerExtent(layerId) { + return async function(dispatch, getState) { + const targetLayer = getLayerById(layerId, getState()); + + if (targetLayer) { + const dataFilters = getDataFilters(getState()); + const bounds = await targetLayer.getBounds(dataFilters); + if (bounds) { + await dispatch(setGotoWithBounds(bounds)); + } + } + }; +} + +export function setGotoWithBounds(bounds) { + return { + type: SET_GOTO, + bounds: bounds, + }; +} + +export function setGotoWithCenter({ lat, lon, zoom }) { + return { + type: SET_GOTO, + center: { lat, lon, zoom }, + }; +} + +export function clearGoto() { + return { type: CLEAR_GOTO }; +} + +export function startDataLoad(layerId, dataId, requestToken, meta = {}) { + return (dispatch, getState) => { + const layer = getLayerById(layerId, getState()); + if (layer) { + dispatch(cancelRequest(layer.getPrevRequestToken(dataId))); + } + + const eventHandlers = getEventHandlers(getState()); + if (eventHandlers && eventHandlers.onDataLoad) { + eventHandlers.onDataLoad({ + layerId, + dataId, + }); + } + + dispatch({ + meta, + type: LAYER_DATA_LOAD_STARTED, + layerId, + dataId, + requestToken, + }); + }; +} + +export function updateSourceDataRequest(layerId, newData) { + return dispatch => { + dispatch({ + type: UPDATE_SOURCE_DATA_REQUEST, + dataId: SOURCE_DATA_ID_ORIGIN, + layerId, + newData, + }); + + dispatch(updateStyleMeta(layerId)); + }; +} + +export function endDataLoad(layerId, dataId, requestToken, data, meta) { + return async (dispatch, getState) => { + dispatch(unregisterCancelCallback(requestToken)); + + const features = data && data.features ? data.features : []; + + const eventHandlers = getEventHandlers(getState()); + if (eventHandlers && eventHandlers.onDataLoadEnd) { + const layer = getLayerById(layerId, getState()); + const resultMeta = {}; + if (layer && layer.getType() === LAYER_TYPE.VECTOR) { + resultMeta.featuresCount = features.length; + } + + eventHandlers.onDataLoadEnd({ + layerId, + dataId, + resultMeta, + }); + } + + dispatch(cleanTooltipStateForLayer(layerId, features)); + dispatch({ + type: LAYER_DATA_LOAD_ENDED, + layerId, + dataId, + data, + meta, + requestToken, + }); + + //Clear any data-load errors when there is a succesful data return. + //Co this on end-data-load iso at start-data-load to avoid blipping the error status between true/false. + //This avoids jitter in the warning icon of the TOC when the requests continues to return errors. + dispatch(setLayerDataLoadErrorStatus(layerId, null)); + + dispatch(updateStyleMeta(layerId)); + }; +} + +export function onDataLoadError(layerId, dataId, requestToken, errorMessage) { + return async (dispatch, getState) => { + dispatch(unregisterCancelCallback(requestToken)); + + const eventHandlers = getEventHandlers(getState()); + if (eventHandlers && eventHandlers.onDataLoadError) { + eventHandlers.onDataLoadError({ + layerId, + dataId, + errorMessage, + }); + } + + dispatch(cleanTooltipStateForLayer(layerId)); + dispatch({ + type: LAYER_DATA_LOAD_ERROR, + data: null, + layerId, + dataId, + requestToken, + }); + + dispatch(setLayerDataLoadErrorStatus(layerId, errorMessage)); + }; +} + +export function updateSourceProp(layerId, propName, value, newLayerType) { + return async dispatch => { + dispatch({ + type: UPDATE_SOURCE_PROP, + layerId, + propName, + value, + }); + if (newLayerType) { + dispatch(updateLayerType(layerId, newLayerType)); + } + await dispatch(clearMissingStyleProperties(layerId)); + dispatch(syncDataForLayer(layerId)); + }; +} + +function updateLayerType(layerId, newLayerType) { + return (dispatch, getState) => { + const layer = getLayerById(layerId, getState()); + if (!layer || layer.getType() === newLayerType) { + return; + } + dispatch(clearDataRequests(layer)); + dispatch({ + type: UPDATE_LAYER_PROP, + id: layerId, + propName: 'type', + newValue: newLayerType, + }); + }; +} + +export function syncDataForLayer(layerId) { + return async (dispatch, getState) => { + const targetLayer = getLayerById(layerId, getState()); + if (targetLayer) { + const dataFilters = getDataFilters(getState()); + const loadingFunctions = getLayerLoadingCallbacks(dispatch, getState, layerId); + await targetLayer.syncData({ + ...loadingFunctions, + dataFilters, + }); + } + }; +} + +export function updateLayerLabel(id, newLabel) { + return { + type: UPDATE_LAYER_PROP, + id, + propName: 'label', + newValue: newLabel, + }; +} + +export function updateLayerMinZoom(id, minZoom) { + return { + type: UPDATE_LAYER_PROP, + id, + propName: 'minZoom', + newValue: minZoom, + }; +} + +export function updateLayerMaxZoom(id, maxZoom) { + return { + type: UPDATE_LAYER_PROP, + id, + propName: 'maxZoom', + newValue: maxZoom, + }; +} + +export function updateLayerAlpha(id, alpha) { + return { + type: UPDATE_LAYER_PROP, + id, + propName: 'alpha', + newValue: alpha, + }; +} + +export function setLayerQuery(id, query) { + return dispatch => { + dispatch({ + type: UPDATE_LAYER_PROP, + id, + propName: 'query', + newValue: query, + }); + + dispatch(syncDataForLayer(id)); + }; +} + +export function removeSelectedLayer() { + return (dispatch, getState) => { + const state = getState(); + const layerId = getSelectedLayerId(state); + dispatch(removeLayer(layerId)); + }; +} + +export function removeLayer(layerId) { + return async (dispatch, getState) => { + const state = getState(); + const selectedLayerId = getSelectedLayerId(state); + if (layerId === selectedLayerId) { + dispatch(updateFlyout(FLYOUT_STATE.NONE)); + await dispatch(setSelectedLayer(null)); + } + dispatch(removeLayerFromLayerList(layerId)); + }; +} + +function removeLayerFromLayerList(layerId) { + return (dispatch, getState) => { + const layerGettingRemoved = getLayerById(layerId, getState()); + if (!layerGettingRemoved) { + return; + } + + layerGettingRemoved.getInFlightRequestTokens().forEach(requestToken => { + dispatch(cancelRequest(requestToken)); + }); + dispatch(cleanTooltipStateForLayer(layerId)); + layerGettingRemoved.destroy(); + dispatch({ + type: REMOVE_LAYER, + id: layerId, + }); + }; +} + +export function setQuery({ query, timeFilters, filters = [], refresh = false }) { + function generateQueryTimestamp() { + return new Date().toISOString(); + } + return async (dispatch, getState) => { + const prevQuery = getQuery(getState()); + const prevTriggeredAt = + prevQuery && prevQuery.queryLastTriggeredAt + ? prevQuery.queryLastTriggeredAt + : generateQueryTimestamp(); + + dispatch({ + type: SET_QUERY, + timeFilters, + query: { + ...query, + // ensure query changes to trigger re-fetch when "Refresh" clicked + queryLastTriggeredAt: refresh ? generateQueryTimestamp() : prevTriggeredAt, + }, + filters, + }); + + const dataFilters = getDataFilters(getState()); + await syncDataForAllLayers(dispatch, getState, dataFilters); + }; +} + +export function setRefreshConfig({ isPaused, interval }) { + return { + type: SET_REFRESH_CONFIG, + isPaused, + interval, + }; +} + +export function triggerRefreshTimer() { + return async (dispatch, getState) => { + dispatch({ + type: TRIGGER_REFRESH_TIMER, + }); + + const dataFilters = getDataFilters(getState()); + await syncDataForAllLayers(dispatch, getState, dataFilters); + }; +} + +export function clearMissingStyleProperties(layerId) { + return async (dispatch, getState) => { + const targetLayer = getLayerById(layerId, getState()); + if (!targetLayer) { + return; + } + + const style = targetLayer.getCurrentStyle(); + if (!style) { + return; + } + + const nextFields = await targetLayer.getFields(); //take into account all fields, since labels can be driven by any field (source or join) + const { hasChanges, nextStyleDescriptor } = style.getDescriptorWithMissingStylePropsRemoved( + nextFields + ); + if (hasChanges) { + dispatch(updateLayerStyle(layerId, nextStyleDescriptor)); + } + }; +} + +export function updateLayerStyle(layerId, styleDescriptor) { + return dispatch => { + dispatch({ + type: UPDATE_LAYER_STYLE, + layerId, + style: { + ...styleDescriptor, + }, + }); + + // Ensure updateStyleMeta is triggered + // syncDataForLayer may not trigger endDataLoad if no re-fetch is required + dispatch(updateStyleMeta(layerId)); + + // Style update may require re-fetch, for example ES search may need to retrieve field used for dynamic styling + dispatch(syncDataForLayer(layerId)); + }; +} + +export function updateStyleMeta(layerId) { + return async (dispatch, getState) => { + const layer = getLayerById(layerId, getState()); + if (!layer) { + return; + } + const sourceDataRequest = layer.getSourceDataRequest(); + const style = layer.getCurrentStyle(); + if (!style || !sourceDataRequest) { + return; + } + const styleMeta = await style.pluckStyleMetaFromSourceDataRequest(sourceDataRequest); + dispatch({ + type: SET_LAYER_STYLE_META, + layerId, + styleMeta, + }); + }; +} + +export function updateLayerStyleForSelectedLayer(styleDescriptor) { + return (dispatch, getState) => { + const selectedLayerId = getSelectedLayerId(getState()); + if (!selectedLayerId) { + return; + } + dispatch(updateLayerStyle(selectedLayerId, styleDescriptor)); + }; +} + +export function setJoinsForLayer(layer, joins) { + return async dispatch => { + await dispatch({ + type: SET_JOINS, + layer: layer, + joins: joins, + }); + + await dispatch(clearMissingStyleProperties(layer.getId())); + dispatch(syncDataForLayer(layer.getId())); + }; +} + +export function updateDrawState(drawState) { + return dispatch => { + if (drawState !== null) { + dispatch({ type: SET_OPEN_TOOLTIPS, openTooltips: [] }); // tooltips just get in the way + } + dispatch({ + type: UPDATE_DRAW_STATE, + drawState: drawState, + }); + }; +} + +export function disableInteractive() { + return { type: SET_INTERACTIVE, disableInteractive: true }; +} + +export function disableTooltipControl() { + return { type: DISABLE_TOOLTIP_CONTROL, disableTooltipControl: true }; +} + +export function hideToolbarOverlay() { + return { type: HIDE_TOOLBAR_OVERLAY, hideToolbarOverlay: true }; +} + +export function hideLayerControl() { + return { type: HIDE_LAYER_CONTROL, hideLayerControl: true }; +} +export function hideViewControl() { + return { type: HIDE_VIEW_CONTROL, hideViewControl: true }; +} + +export function setHiddenLayers(hiddenLayerIds) { + return (dispatch, getState) => { + const isMapReady = getMapReady(getState()); + + if (!isMapReady) { + dispatch({ type: SET_WAITING_FOR_READY_HIDDEN_LAYERS, hiddenLayerIds }); + } else { + getLayerListRaw(getState()).forEach(layer => + dispatch(setLayerVisibility(layer.id, !hiddenLayerIds.includes(layer.id))) + ); + } + }; +} diff --git a/x-pack/legacy/plugins/maps/public/actions/map_actions.test.js b/x-pack/plugins/maps/public/actions/map_actions.test.js similarity index 98% rename from x-pack/legacy/plugins/maps/public/actions/map_actions.test.js rename to x-pack/plugins/maps/public/actions/map_actions.test.js index 7e2a3c827fa88f..c280b8af7ab80d 100644 --- a/x-pack/legacy/plugins/maps/public/actions/map_actions.test.js +++ b/x-pack/plugins/maps/public/actions/map_actions.test.js @@ -5,7 +5,7 @@ */ jest.mock('../selectors/map_selectors', () => ({})); -jest.mock('../../../../../plugins/maps/public/kibana_services', () => ({})); +jest.mock('../kibana_services', () => ({})); import { mapExtentChanged, setMouseCoordinates } from './map_actions'; diff --git a/x-pack/legacy/plugins/maps/public/actions/ui_actions.d.ts b/x-pack/plugins/maps/public/actions/ui_actions.d.ts similarity index 54% rename from x-pack/legacy/plugins/maps/public/actions/ui_actions.d.ts rename to x-pack/plugins/maps/public/actions/ui_actions.d.ts index 233918847de08b..e087dc70256f06 100644 --- a/x-pack/legacy/plugins/maps/public/actions/ui_actions.d.ts +++ b/x-pack/plugins/maps/public/actions/ui_actions.d.ts @@ -6,6 +6,17 @@ import { AnyAction } from 'redux'; +export const UPDATE_FLYOUT: string; +export const CLOSE_SET_VIEW: string; +export const OPEN_SET_VIEW: string; +export const SET_IS_LAYER_TOC_OPEN: string; +export const SET_FULL_SCREEN: string; +export const SET_READ_ONLY: string; +export const SET_OPEN_TOC_DETAILS: string; +export const SHOW_TOC_DETAILS: string; +export const HIDE_TOC_DETAILS: string; +export const UPDATE_INDEXING_STAGE: string; + export function setOpenTOCDetails(layerIds?: string[]): AnyAction; export function setIsLayerTOCOpen(open: boolean): AnyAction; diff --git a/x-pack/plugins/maps/public/actions/ui_actions.js b/x-pack/plugins/maps/public/actions/ui_actions.js index 59ae56c15056a0..77fdf6b0f12d23 100644 --- a/x-pack/plugins/maps/public/actions/ui_actions.js +++ b/x-pack/plugins/maps/public/actions/ui_actions.js @@ -14,3 +14,73 @@ export const SET_OPEN_TOC_DETAILS = 'SET_OPEN_TOC_DETAILS'; export const SHOW_TOC_DETAILS = 'SHOW_TOC_DETAILS'; export const HIDE_TOC_DETAILS = 'HIDE_TOC_DETAILS'; export const UPDATE_INDEXING_STAGE = 'UPDATE_INDEXING_STAGE'; + +export function exitFullScreen() { + return { + type: SET_FULL_SCREEN, + isFullScreen: false, + }; +} + +export function updateFlyout(display) { + return { + type: UPDATE_FLYOUT, + display, + }; +} +export function closeSetView() { + return { + type: CLOSE_SET_VIEW, + }; +} +export function openSetView() { + return { + type: OPEN_SET_VIEW, + }; +} +export function setIsLayerTOCOpen(isLayerTOCOpen) { + return { + type: SET_IS_LAYER_TOC_OPEN, + isLayerTOCOpen, + }; +} +export function enableFullScreen() { + return { + type: SET_FULL_SCREEN, + isFullScreen: true, + }; +} +export function setReadOnly(isReadOnly) { + return { + type: SET_READ_ONLY, + isReadOnly, + }; +} + +export function setOpenTOCDetails(layerIds) { + return { + type: SET_OPEN_TOC_DETAILS, + layerIds, + }; +} + +export function showTOCDetails(layerId) { + return { + type: SHOW_TOC_DETAILS, + layerId, + }; +} + +export function hideTOCDetails(layerId) { + return { + type: HIDE_TOC_DETAILS, + layerId, + }; +} + +export function updateIndexingStage(stage) { + return { + type: UPDATE_INDEXING_STAGE, + stage, + }; +} diff --git a/x-pack/legacy/plugins/maps/public/angular/get_initial_layers.d.ts b/x-pack/plugins/maps/public/angular/get_initial_layers.d.ts similarity index 100% rename from x-pack/legacy/plugins/maps/public/angular/get_initial_layers.d.ts rename to x-pack/plugins/maps/public/angular/get_initial_layers.d.ts diff --git a/x-pack/plugins/maps/public/angular/get_initial_layers.js b/x-pack/plugins/maps/public/angular/get_initial_layers.js new file mode 100644 index 00000000000000..1eb5dac309f28c --- /dev/null +++ b/x-pack/plugins/maps/public/angular/get_initial_layers.js @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import _ from 'lodash'; +// Import each layer type, even those not used, to init in registry + +import '../layers/sources/wms_source'; + +import '../layers/sources/ems_file_source'; + +import '../layers/sources/es_search_source'; + +import '../layers/sources/es_pew_pew_source/es_pew_pew_source'; + +import '../layers/sources/kibana_regionmap_source'; + +import '../layers/sources/es_geo_grid_source'; + +import '../layers/sources/xyz_tms_source'; + +import { KibanaTilemapSource } from '../layers/sources/kibana_tilemap_source'; + +import { EMSTMSSource } from '../layers/sources/ems_tms_source'; + +import { getInjectedVarFunc } from '../kibana_services'; + +import { getKibanaTileMap } from '../meta'; + +export function getInitialLayers(layerListJSON, initialLayers = []) { + if (layerListJSON) { + return JSON.parse(layerListJSON); + } + + const tilemapSourceFromKibana = getKibanaTileMap(); + if (_.get(tilemapSourceFromKibana, 'url')) { + const sourceDescriptor = KibanaTilemapSource.createDescriptor(); + const source = new KibanaTilemapSource(sourceDescriptor); + const layer = source.createDefaultLayer(); + return [layer.toLayerDescriptor(), ...initialLayers]; + } + + const isEmsEnabled = getInjectedVarFunc()('isEmsEnabled', true); + if (isEmsEnabled) { + const descriptor = EMSTMSSource.createDescriptor({ isAutoSelect: true }); + const source = new EMSTMSSource(descriptor); + const layer = source.createDefaultLayer(); + return [layer.toLayerDescriptor(), ...initialLayers]; + } + + return initialLayers; +} diff --git a/x-pack/legacy/plugins/maps/public/angular/get_initial_layers.test.js b/x-pack/plugins/maps/public/angular/get_initial_layers.test.js similarity index 80% rename from x-pack/legacy/plugins/maps/public/angular/get_initial_layers.test.js rename to x-pack/plugins/maps/public/angular/get_initial_layers.test.js index 8c9185a16ea0e7..f41ed26b2a05d3 100644 --- a/x-pack/legacy/plugins/maps/public/angular/get_initial_layers.test.js +++ b/x-pack/plugins/maps/public/angular/get_initial_layers.test.js @@ -4,10 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -jest.mock('../../../../../plugins/maps/public/meta', () => { +jest.mock('../meta', () => { return {}; }); -jest.mock('../../../../../plugins/maps/public/kibana_services'); +jest.mock('../kibana_services'); import { getInitialLayers } from './get_initial_layers'; @@ -15,8 +15,7 @@ const layerListNotProvided = undefined; describe('Saved object has layer list', () => { beforeEach(() => { - require('../../../../../plugins/maps/public/kibana_services').getInjectedVarFunc = () => - jest.fn(); + require('../kibana_services').getInjectedVarFunc = () => jest.fn(); }); it('Should get initial layers from saved object', () => { @@ -33,7 +32,7 @@ describe('Saved object has layer list', () => { describe('kibana.yml configured with map.tilemap.url', () => { beforeAll(() => { - require('../../../../../plugins/maps/public/meta').getKibanaTileMap = () => { + require('../meta').getKibanaTileMap = () => { return { url: 'myTileUrl', }; @@ -63,10 +62,10 @@ describe('kibana.yml configured with map.tilemap.url', () => { describe('EMS is enabled', () => { beforeAll(() => { - require('../../../../../plugins/maps/public/meta').getKibanaTileMap = () => { + require('../meta').getKibanaTileMap = () => { return null; }; - require('../../../../../plugins/maps/public/kibana_services').getInjectedVarFunc = () => key => { + require('../kibana_services').getInjectedVarFunc = () => key => { switch (key) { case 'emsTileLayerId': return { @@ -107,11 +106,11 @@ describe('EMS is enabled', () => { describe('EMS is not enabled', () => { beforeAll(() => { - require('../../../../../plugins/maps/public/meta').getKibanaTileMap = () => { + require('../meta').getKibanaTileMap = () => { return null; }; - require('../../../../../plugins/maps/public/kibana_services').getInjectedVarFunc = () => key => { + require('../kibana_services').getInjectedVarFunc = () => key => { switch (key) { case 'isEmsEnabled': return false; diff --git a/x-pack/legacy/plugins/maps/public/angular/get_initial_query.js b/x-pack/plugins/maps/public/angular/get_initial_query.js similarity index 82% rename from x-pack/legacy/plugins/maps/public/angular/get_initial_query.js rename to x-pack/plugins/maps/public/angular/get_initial_query.js index c50ecb2b05dc07..4f61142413671d 100644 --- a/x-pack/legacy/plugins/maps/public/angular/get_initial_query.js +++ b/x-pack/plugins/maps/public/angular/get_initial_query.js @@ -4,8 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getUiSettings } from '../../../../../plugins/maps/public/kibana_services'; +import { getUiSettings } from '../kibana_services'; export function getInitialQuery({ mapStateJSON, appState = {}, userQueryLanguage }) { const settings = getUiSettings(); diff --git a/x-pack/legacy/plugins/maps/public/angular/get_initial_refresh_config.js b/x-pack/plugins/maps/public/angular/get_initial_refresh_config.js similarity index 84% rename from x-pack/legacy/plugins/maps/public/angular/get_initial_refresh_config.js rename to x-pack/plugins/maps/public/angular/get_initial_refresh_config.js index 8735d45debfc4c..f13e435cd1d5cf 100644 --- a/x-pack/legacy/plugins/maps/public/angular/get_initial_refresh_config.js +++ b/x-pack/plugins/maps/public/angular/get_initial_refresh_config.js @@ -3,8 +3,8 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getUiSettings } from '../../../../../plugins/maps/public/kibana_services'; + +import { getUiSettings } from '../kibana_services'; export function getInitialRefreshConfig({ mapStateJSON, globalState = {} }) { const uiSettings = getUiSettings(); diff --git a/x-pack/legacy/plugins/maps/public/angular/get_initial_time_filters.js b/x-pack/plugins/maps/public/angular/get_initial_time_filters.js similarity index 80% rename from x-pack/legacy/plugins/maps/public/angular/get_initial_time_filters.js rename to x-pack/plugins/maps/public/angular/get_initial_time_filters.js index 74fbf603e99f5e..75d9f0e95ccf08 100644 --- a/x-pack/legacy/plugins/maps/public/angular/get_initial_time_filters.js +++ b/x-pack/plugins/maps/public/angular/get_initial_time_filters.js @@ -3,8 +3,8 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getUiSettings } from '../../../../../plugins/maps/public/kibana_services'; + +import { getUiSettings } from '../kibana_services'; export function getInitialTimeFilters({ mapStateJSON, globalState = {} }) { if (mapStateJSON) { diff --git a/x-pack/legacy/plugins/maps/public/angular/listing_ng_wrapper.html b/x-pack/plugins/maps/public/angular/listing_ng_wrapper.html similarity index 100% rename from x-pack/legacy/plugins/maps/public/angular/listing_ng_wrapper.html rename to x-pack/plugins/maps/public/angular/listing_ng_wrapper.html diff --git a/x-pack/legacy/plugins/maps/public/angular/map.html b/x-pack/plugins/maps/public/angular/map.html similarity index 100% rename from x-pack/legacy/plugins/maps/public/angular/map.html rename to x-pack/plugins/maps/public/angular/map.html diff --git a/x-pack/legacy/plugins/maps/public/angular/services/gis_map_saved_object_loader.js b/x-pack/plugins/maps/public/angular/services/gis_map_saved_object_loader.js similarity index 79% rename from x-pack/legacy/plugins/maps/public/angular/services/gis_map_saved_object_loader.js rename to x-pack/plugins/maps/public/angular/services/gis_map_saved_object_loader.js index 710997a9c0d7f3..2dcec35960b080 100644 --- a/x-pack/legacy/plugins/maps/public/angular/services/gis_map_saved_object_loader.js +++ b/x-pack/plugins/maps/public/angular/services/gis_map_saved_object_loader.js @@ -6,15 +6,14 @@ import _ from 'lodash'; import { createSavedGisMapClass } from './saved_gis_map'; -import { SavedObjectLoader } from '../../../../../../../src/plugins/saved_objects/public'; +import { SavedObjectLoader } from '../../../../../../src/plugins/saved_objects/public'; import { getCoreChrome, getSavedObjectsClient, getIndexPatternService, getCoreOverlays, getData, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../../../plugins/maps/public/kibana_services'; +} from '../../kibana_services'; export const getMapsSavedObjectLoader = _.once(function() { const services = { diff --git a/x-pack/legacy/plugins/maps/public/angular/services/saved_gis_map.js b/x-pack/plugins/maps/public/angular/services/saved_gis_map.js similarity index 88% rename from x-pack/legacy/plugins/maps/public/angular/services/saved_gis_map.js rename to x-pack/plugins/maps/public/angular/services/saved_gis_map.js index 990a0613da681c..1c47e0ab7dc2a4 100644 --- a/x-pack/legacy/plugins/maps/public/angular/services/saved_gis_map.js +++ b/x-pack/plugins/maps/public/angular/services/saved_gis_map.js @@ -5,7 +5,7 @@ */ import _ from 'lodash'; -import { createSavedObjectClass } from '../../../../../../../src/plugins/saved_objects/public'; +import { createSavedObjectClass } from '../../../../../../src/plugins/saved_objects/public'; import { getTimeFilters, getMapZoom, @@ -17,10 +17,10 @@ import { getFilters, } from '../../selectors/map_selectors'; import { getIsLayerTOCOpen, getOpenTOCDetails } from '../../selectors/ui_selectors'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { convertMapExtentToPolygon } from '../../../../../../plugins/maps/public/elasticsearch_geo_utils'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { copyPersistentState } from '../../../../../../plugins/maps/public/reducers/util'; + +import { convertMapExtentToPolygon } from '../../elasticsearch_geo_utils'; + +import { copyPersistentState } from '../../reducers/util'; import { extractReferences, injectReferences } from '../../../common/migrations/references'; import { MAP_SAVED_OBJECT_TYPE } from '../../../common/constants'; diff --git a/x-pack/legacy/plugins/maps/public/components/__snapshots__/geometry_filter_form.test.js.snap b/x-pack/plugins/maps/public/components/__snapshots__/geometry_filter_form.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/maps/public/components/__snapshots__/geometry_filter_form.test.js.snap rename to x-pack/plugins/maps/public/components/__snapshots__/geometry_filter_form.test.js.snap diff --git a/x-pack/legacy/plugins/maps/public/components/__snapshots__/layer_toc_actions.test.js.snap b/x-pack/plugins/maps/public/components/__snapshots__/layer_toc_actions.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/maps/public/components/__snapshots__/layer_toc_actions.test.js.snap rename to x-pack/plugins/maps/public/components/__snapshots__/layer_toc_actions.test.js.snap diff --git a/x-pack/legacy/plugins/maps/public/components/_geometry_filter.scss b/x-pack/plugins/maps/public/components/_geometry_filter.scss similarity index 100% rename from x-pack/legacy/plugins/maps/public/components/_geometry_filter.scss rename to x-pack/plugins/maps/public/components/_geometry_filter.scss diff --git a/x-pack/plugins/maps/public/components/_index.scss b/x-pack/plugins/maps/public/components/_index.scss new file mode 100644 index 00000000000000..161b3fefdb8f9e --- /dev/null +++ b/x-pack/plugins/maps/public/components/_index.scss @@ -0,0 +1,3 @@ +@import 'metric_editors'; +@import './geometry_filter'; +@import 'tooltip_selector'; diff --git a/x-pack/legacy/plugins/maps/public/components/_metric_editors.scss b/x-pack/plugins/maps/public/components/_metric_editors.scss similarity index 100% rename from x-pack/legacy/plugins/maps/public/components/_metric_editors.scss rename to x-pack/plugins/maps/public/components/_metric_editors.scss diff --git a/x-pack/legacy/plugins/maps/public/components/_tooltip_selector.scss b/x-pack/plugins/maps/public/components/_tooltip_selector.scss similarity index 100% rename from x-pack/legacy/plugins/maps/public/components/_tooltip_selector.scss rename to x-pack/plugins/maps/public/components/_tooltip_selector.scss diff --git a/x-pack/legacy/plugins/maps/public/components/distance_filter_form.tsx b/x-pack/plugins/maps/public/components/distance_filter_form.tsx similarity index 100% rename from x-pack/legacy/plugins/maps/public/components/distance_filter_form.tsx rename to x-pack/plugins/maps/public/components/distance_filter_form.tsx diff --git a/x-pack/legacy/plugins/maps/public/components/geo_field_with_index.ts b/x-pack/plugins/maps/public/components/geo_field_with_index.ts similarity index 100% rename from x-pack/legacy/plugins/maps/public/components/geo_field_with_index.ts rename to x-pack/plugins/maps/public/components/geo_field_with_index.ts diff --git a/x-pack/legacy/plugins/maps/public/components/geometry_filter_form.js b/x-pack/plugins/maps/public/components/geometry_filter_form.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/components/geometry_filter_form.js rename to x-pack/plugins/maps/public/components/geometry_filter_form.js diff --git a/x-pack/legacy/plugins/maps/public/components/geometry_filter_form.test.js b/x-pack/plugins/maps/public/components/geometry_filter_form.test.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/components/geometry_filter_form.test.js rename to x-pack/plugins/maps/public/components/geometry_filter_form.test.js diff --git a/x-pack/legacy/plugins/maps/public/components/global_filter_checkbox.js b/x-pack/plugins/maps/public/components/global_filter_checkbox.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/components/global_filter_checkbox.js rename to x-pack/plugins/maps/public/components/global_filter_checkbox.js diff --git a/x-pack/legacy/plugins/maps/public/components/layer_toc_actions.js b/x-pack/plugins/maps/public/components/layer_toc_actions.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/components/layer_toc_actions.js rename to x-pack/plugins/maps/public/components/layer_toc_actions.js diff --git a/x-pack/legacy/plugins/maps/public/components/layer_toc_actions.test.js b/x-pack/plugins/maps/public/components/layer_toc_actions.test.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/components/layer_toc_actions.test.js rename to x-pack/plugins/maps/public/components/layer_toc_actions.test.js diff --git a/x-pack/legacy/plugins/maps/public/components/map_listing.js b/x-pack/plugins/maps/public/components/map_listing.js similarity index 98% rename from x-pack/legacy/plugins/maps/public/components/map_listing.js rename to x-pack/plugins/maps/public/components/map_listing.js index ef1d524cb91dd2..ee10fe30130f37 100644 --- a/x-pack/legacy/plugins/maps/public/components/map_listing.js +++ b/x-pack/plugins/maps/public/components/map_listing.js @@ -7,8 +7,8 @@ import React from 'react'; import PropTypes from 'prop-types'; import _ from 'lodash'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getToasts } from '../../../../../plugins/maps/public/kibana_services'; + +import { getToasts } from '../kibana_services'; import { EuiTitle, EuiFieldSearch, diff --git a/x-pack/legacy/plugins/maps/public/components/multi_index_geo_field_select.tsx b/x-pack/plugins/maps/public/components/multi_index_geo_field_select.tsx similarity index 100% rename from x-pack/legacy/plugins/maps/public/components/multi_index_geo_field_select.tsx rename to x-pack/plugins/maps/public/components/multi_index_geo_field_select.tsx diff --git a/x-pack/plugins/maps/public/connected_components/_index.scss b/x-pack/plugins/maps/public/connected_components/_index.scss new file mode 100644 index 00000000000000..83042ae1d586cc --- /dev/null +++ b/x-pack/plugins/maps/public/connected_components/_index.scss @@ -0,0 +1,6 @@ +@import 'gis_map/gis_map'; +@import 'layer_addpanel/source_select/index'; +@import 'layer_panel/index'; +@import 'widget_overlay/index'; +@import 'toolbar_overlay/index'; +@import 'map/features_tooltip/index'; diff --git a/x-pack/legacy/plugins/maps/public/connected_components/gis_map/_gis_map.scss b/x-pack/plugins/maps/public/connected_components/gis_map/_gis_map.scss similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/gis_map/_gis_map.scss rename to x-pack/plugins/maps/public/connected_components/gis_map/_gis_map.scss diff --git a/x-pack/legacy/plugins/maps/public/connected_components/gis_map/index.d.ts b/x-pack/plugins/maps/public/connected_components/gis_map/index.d.ts similarity index 73% rename from x-pack/legacy/plugins/maps/public/connected_components/gis_map/index.d.ts rename to x-pack/plugins/maps/public/connected_components/gis_map/index.d.ts index 8689d882971719..92d92dfbd142da 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/gis_map/index.d.ts +++ b/x-pack/plugins/maps/public/connected_components/gis_map/index.d.ts @@ -6,8 +6,8 @@ import React from 'react'; import { Filter } from 'src/plugins/data/public'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { RenderToolTipContent } from '../../../../../../plugins/maps/public/layers/tooltips/tooltip_property'; + +import { RenderToolTipContent } from '../../layers/tooltips/tooltip_property'; export const GisMap: React.ComponentType<{ addFilters: ((filters: Filter[]) => void) | null; diff --git a/x-pack/legacy/plugins/maps/public/connected_components/gis_map/index.js b/x-pack/plugins/maps/public/connected_components/gis_map/index.js similarity index 85% rename from x-pack/legacy/plugins/maps/public/connected_components/gis_map/index.js rename to x-pack/plugins/maps/public/connected_components/gis_map/index.js index 2d8265bae93878..c825fdab75ca74 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/gis_map/index.js +++ b/x-pack/plugins/maps/public/connected_components/gis_map/index.js @@ -6,8 +6,8 @@ import { connect } from 'react-redux'; import { GisMap } from './view'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { FLYOUT_STATE } from '../../../../../../plugins/maps/public/reducers/ui'; + +import { FLYOUT_STATE } from '../../reducers/ui'; import { exitFullScreen } from '../../actions/ui_actions'; import { getFlyoutDisplay, getIsFullScreen } from '../../selectors/ui_selectors'; import { triggerRefreshTimer, cancelAllInFlightRequests } from '../../actions/map_actions'; @@ -18,8 +18,8 @@ import { getQueryableUniqueIndexPatternIds, isToolbarOverlayHidden, } from '../../selectors/map_selectors'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getCoreChrome } from '../../../../../../plugins/maps/public/kibana_services'; + +import { getCoreChrome } from '../../kibana_services'; function mapStateToProps(state = {}) { const flyoutDisplay = getFlyoutDisplay(state); diff --git a/x-pack/legacy/plugins/maps/public/connected_components/gis_map/view.js b/x-pack/plugins/maps/public/connected_components/gis_map/view.js similarity index 92% rename from x-pack/legacy/plugins/maps/public/connected_components/gis_map/view.js rename to x-pack/plugins/maps/public/connected_components/gis_map/view.js index 06097ebea1900a..28ad12133d6118 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/gis_map/view.js +++ b/x-pack/plugins/maps/public/connected_components/gis_map/view.js @@ -7,17 +7,16 @@ import _ from 'lodash'; import React, { Component } from 'react'; import { MBMapContainer } from '../map/mb'; -import { WidgetOverlay } from '../widget_overlay/index'; -import { ToolbarOverlay } from '../toolbar_overlay/index'; -import { LayerPanel } from '../layer_panel/index'; -import { AddLayerPanel } from '../layer_addpanel/index'; +import { WidgetOverlay } from '../widget_overlay'; +import { ToolbarOverlay } from '../toolbar_overlay'; +import { LayerPanel } from '../layer_panel'; +import { AddLayerPanel } from '../layer_addpanel'; import { EuiFlexGroup, EuiFlexItem, EuiCallOut } from '@elastic/eui'; -import { ExitFullScreenButton } from '../../../../../../../src/plugins/kibana_react/public'; +import { ExitFullScreenButton } from '../../../../../../src/plugins/kibana_react/public'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getIndexPatternsFromIds } from '../../../../../../plugins/maps/public/index_pattern_util'; +import { getIndexPatternsFromIds } from '../../index_pattern_util'; import { ES_GEO_FIELD_TYPE } from '../../../common/constants'; -import { indexPatterns as indexPatternsUtils } from '../../../../../../../src/plugins/data/public'; +import { indexPatterns as indexPatternsUtils } from '../../../../../../src/plugins/data/public'; import { i18n } from '@kbn/i18n'; import uuid from 'uuid/v4'; diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/flyout_footer/index.js b/x-pack/plugins/maps/public/connected_components/layer_addpanel/flyout_footer/index.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/flyout_footer/index.js rename to x-pack/plugins/maps/public/connected_components/layer_addpanel/flyout_footer/index.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/flyout_footer/view.js b/x-pack/plugins/maps/public/connected_components/layer_addpanel/flyout_footer/view.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/flyout_footer/view.js rename to x-pack/plugins/maps/public/connected_components/layer_addpanel/flyout_footer/view.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/import_editor/index.js b/x-pack/plugins/maps/public/connected_components/layer_addpanel/import_editor/index.js similarity index 76% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/import_editor/index.js rename to x-pack/plugins/maps/public/connected_components/layer_addpanel/import_editor/index.js index e8192795f98aef..bff235a7d27fcd 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/import_editor/index.js +++ b/x-pack/plugins/maps/public/connected_components/layer_addpanel/import_editor/index.js @@ -6,10 +6,10 @@ import { connect } from 'react-redux'; import { ImportEditor } from './view'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getInspectorAdapters } from '../../../../../../../plugins/maps/public/reducers/non_serializable_instances'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { INDEXING_STAGE } from '../../../../../../../plugins/maps/public/reducers/ui'; + +import { getInspectorAdapters } from '../../../reducers/non_serializable_instances'; + +import { INDEXING_STAGE } from '../../../reducers/ui'; import { updateIndexingStage } from '../../../actions/ui_actions'; import { getIndexingStage } from '../../../selectors/ui_selectors'; diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/import_editor/view.js b/x-pack/plugins/maps/public/connected_components/layer_addpanel/import_editor/view.js similarity index 89% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/import_editor/view.js rename to x-pack/plugins/maps/public/connected_components/layer_addpanel/import_editor/view.js index cb20d80733c33b..a4fa0d492bf3f5 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/import_editor/view.js +++ b/x-pack/plugins/maps/public/connected_components/layer_addpanel/import_editor/view.js @@ -7,8 +7,8 @@ import React, { Fragment } from 'react'; import { EuiSpacer, EuiPanel, EuiButtonEmpty } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { uploadLayerWizardConfig } from '../../../../../../../plugins/maps/public/layers/sources/client_file_source'; + +import { uploadLayerWizardConfig } from '../../../layers/sources/client_file_source'; export const ImportEditor = ({ clearSource, isIndexingTriggered, ...props }) => { const editorProperties = getEditorProperties({ isIndexingTriggered, ...props }); diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/index.js b/x-pack/plugins/maps/public/connected_components/layer_addpanel/index.js similarity index 85% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/index.js rename to x-pack/plugins/maps/public/connected_components/layer_addpanel/index.js index c4e2fa5169b0fa..24c1f5ced4fe65 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/index.js +++ b/x-pack/plugins/maps/public/connected_components/layer_addpanel/index.js @@ -6,13 +6,13 @@ import { connect } from 'react-redux'; import { AddLayerPanel } from './view'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { FLYOUT_STATE, INDEXING_STAGE } from '../../../../../../plugins/maps/public/reducers/ui'; + +import { FLYOUT_STATE, INDEXING_STAGE } from '../../reducers/ui'; import { updateFlyout, updateIndexingStage } from '../../actions/ui_actions'; import { getFlyoutDisplay, getIndexingStage } from '../../selectors/ui_selectors'; import { getMapColors } from '../../selectors/map_selectors'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getInspectorAdapters } from '../../../../../../plugins/maps/public/reducers/non_serializable_instances'; + +import { getInspectorAdapters } from '../../reducers/non_serializable_instances'; import { setTransientLayer, addLayer, diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/source_editor/index.js b/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_editor/index.js similarity index 75% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/source_editor/index.js rename to x-pack/plugins/maps/public/connected_components/layer_addpanel/source_editor/index.js index 553e54ee897665..8937f32d3bf05d 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/source_editor/index.js +++ b/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_editor/index.js @@ -6,8 +6,8 @@ import { connect } from 'react-redux'; import { SourceEditor } from './view'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getInspectorAdapters } from '../../../../../../../plugins/maps/public/reducers/non_serializable_instances'; + +import { getInspectorAdapters } from '../../../reducers/non_serializable_instances'; function mapStateToProps(state = {}) { return { diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/source_editor/view.js b/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_editor/view.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/source_editor/view.js rename to x-pack/plugins/maps/public/connected_components/layer_addpanel/source_editor/view.js diff --git a/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_select/_index.scss b/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_select/_index.scss new file mode 100644 index 00000000000000..8ae6970315e132 --- /dev/null +++ b/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_select/_index.scss @@ -0,0 +1 @@ +@import 'source_select'; diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/source_select/_source_select.scss b/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_select/_source_select.scss similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/source_select/_source_select.scss rename to x-pack/plugins/maps/public/connected_components/layer_addpanel/source_select/_source_select.scss diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/source_select/source_select.js b/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_select/source_select.js similarity index 90% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/source_select/source_select.js rename to x-pack/plugins/maps/public/connected_components/layer_addpanel/source_select/source_select.js index 67cc17ebaa2241..80b05a0fd015b7 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/source_select/source_select.js +++ b/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_select/source_select.js @@ -5,8 +5,8 @@ */ import React, { Fragment } from 'react'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getLayerWizards } from '../../../../../../../plugins/maps/public/layers/layer_wizard_registry'; + +import { getLayerWizards } from '../../../layers/layer_wizard_registry'; import { EuiTitle, EuiSpacer, EuiCard, EuiIcon } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import _ from 'lodash'; diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/view.js b/x-pack/plugins/maps/public/connected_components/layer_addpanel/view.js similarity index 98% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/view.js rename to x-pack/plugins/maps/public/connected_components/layer_addpanel/view.js index a54df69471aa04..92fcf01f3901f5 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/view.js +++ b/x-pack/plugins/maps/public/connected_components/layer_addpanel/view.js @@ -63,13 +63,13 @@ export class AddLayerPanel extends Component { return; } - const style = + const styleDescriptor = this.state.layer && this.state.layer.getCurrentStyle() ? this.state.layer.getCurrentStyle().getDescriptor() : null; const layerInitProps = { ...options, - style: style, + style: styleDescriptor, }; const newLayer = source.createDefaultLayer(layerInitProps, this.props.mapColors); if (!this._isMounted) { diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/__snapshots__/view.test.js.snap b/x-pack/plugins/maps/public/connected_components/layer_panel/__snapshots__/view.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/__snapshots__/view.test.js.snap rename to x-pack/plugins/maps/public/connected_components/layer_panel/__snapshots__/view.test.js.snap diff --git a/x-pack/plugins/maps/public/connected_components/layer_panel/_index.scss b/x-pack/plugins/maps/public/connected_components/layer_panel/_index.scss new file mode 100644 index 00000000000000..41b4826a02c675 --- /dev/null +++ b/x-pack/plugins/maps/public/connected_components/layer_panel/_index.scss @@ -0,0 +1,4 @@ +@import 'layer_panel'; +@import 'filter_editor/filter_editor'; +@import 'join_editor/resources/join'; +@import 'style_settings/style_settings'; diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/_layer_panel.scss b/x-pack/plugins/maps/public/connected_components/layer_panel/_layer_panel.scss similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/_layer_panel.scss rename to x-pack/plugins/maps/public/connected_components/layer_panel/_layer_panel.scss diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/_filter_editor.scss b/x-pack/plugins/maps/public/connected_components/layer_panel/filter_editor/_filter_editor.scss similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/_filter_editor.scss rename to x-pack/plugins/maps/public/connected_components/layer_panel/filter_editor/_filter_editor.scss diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js b/x-pack/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js similarity index 96% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js rename to x-pack/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js index 40fdac38493d4b..fba2ec05d0b1d6 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js +++ b/x-pack/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js @@ -20,12 +20,7 @@ import { import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import { - getIndexPatternService, - getUiSettings, - getData, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../../../../plugins/maps/public/kibana_services'; +import { getIndexPatternService, getUiSettings, getData } from '../../../kibana_services'; import { GlobalFilterCheckbox } from '../../../components/global_filter_checkbox'; export class FilterEditor extends Component { diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/index.js b/x-pack/plugins/maps/public/connected_components/layer_panel/filter_editor/index.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/index.js rename to x-pack/plugins/maps/public/connected_components/layer_panel/filter_editor/index.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/flyout_footer/index.js b/x-pack/plugins/maps/public/connected_components/layer_panel/flyout_footer/index.js similarity index 89% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/flyout_footer/index.js rename to x-pack/plugins/maps/public/connected_components/layer_panel/flyout_footer/index.js index 287f0019f18ecd..621ce209eb982f 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/flyout_footer/index.js +++ b/x-pack/plugins/maps/public/connected_components/layer_panel/flyout_footer/index.js @@ -6,8 +6,8 @@ import { connect } from 'react-redux'; import { FlyoutFooter } from './view'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { FLYOUT_STATE } from '../../../../../../../plugins/maps/public/reducers/ui'; + +import { FLYOUT_STATE } from '../../../reducers/ui'; import { updateFlyout } from '../../../actions/ui_actions'; import { hasDirtyState } from '../../../selectors/map_selectors'; import { diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/flyout_footer/view.js b/x-pack/plugins/maps/public/connected_components/layer_panel/flyout_footer/view.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/flyout_footer/view.js rename to x-pack/plugins/maps/public/connected_components/layer_panel/flyout_footer/view.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/index.js b/x-pack/plugins/maps/public/connected_components/layer_panel/index.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/index.js rename to x-pack/plugins/maps/public/connected_components/layer_panel/index.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/index.js b/x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/index.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/index.js rename to x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/index.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/__snapshots__/metrics_expression.test.js.snap b/x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/resources/__snapshots__/metrics_expression.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/__snapshots__/metrics_expression.test.js.snap rename to x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/resources/__snapshots__/metrics_expression.test.js.snap diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/_join.scss b/x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/resources/_join.scss similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/_join.scss rename to x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/resources/_join.scss diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/join.js b/x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/resources/join.js similarity index 95% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/join.js rename to x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/resources/join.js index 9c4e1cfdb5467c..0d26354e2449b2 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/join.js +++ b/x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/resources/join.js @@ -13,9 +13,9 @@ import { MetricsExpression } from './metrics_expression'; import { WhereExpression } from './where_expression'; import { GlobalFilterCheckbox } from '../../../../components/global_filter_checkbox'; -import { indexPatterns } from '../../../../../../../../../src/plugins/data/public'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getIndexPatternService } from '../../../../../../../../plugins/maps/public/kibana_services'; +import { indexPatterns } from '../../../../../../../../src/plugins/data/public'; + +import { getIndexPatternService } from '../../../../kibana_services'; export class Join extends Component { state = { diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/join_expression.js b/x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/resources/join_expression.js similarity index 93% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/join_expression.js rename to x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/resources/join_expression.js index 73600c81d221e2..12ca2f3c514a06 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/join_expression.js +++ b/x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/resources/join_expression.js @@ -16,16 +16,15 @@ import { EuiFormHelpText, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { SingleFieldSelect } from '../../../../../../../../plugins/maps/public/components/single_field_select'; + +import { SingleFieldSelect } from '../../../../components/single_field_select'; import { FormattedMessage } from '@kbn/i18n/react'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getTermsFields } from '../../../../../../../../plugins/maps/public/index_pattern_util'; + +import { getTermsFields } from '../../../../index_pattern_util'; import { getIndexPatternService, getIndexPatternSelectComponent, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../../../../../plugins/maps/public/kibana_services'; +} from '../../../../kibana_services'; export class JoinExpression extends Component { state = { diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/metrics_expression.js b/x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/resources/metrics_expression.js similarity index 95% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/metrics_expression.js rename to x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/resources/metrics_expression.js index c6a79a398f9af2..8c83743ac4c962 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/metrics_expression.js +++ b/x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/resources/metrics_expression.js @@ -14,8 +14,8 @@ import { EuiFormErrorText, EuiFormHelpText, } from '@elastic/eui'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { MetricsEditor } from '../../../../../../../../plugins/maps/public/components/metrics_editor'; + +import { MetricsEditor } from '../../../../components/metrics_editor'; import { FormattedMessage } from '@kbn/i18n/react'; import { AGG_TYPE } from '../../../../../common/constants'; diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/metrics_expression.test.js b/x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/resources/metrics_expression.test.js similarity index 92% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/metrics_expression.test.js rename to x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/resources/metrics_expression.test.js index d8bf8622494484..3cd8a3c42879a3 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/metrics_expression.test.js +++ b/x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/resources/metrics_expression.test.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -jest.mock('../../../../../../../../plugins/maps/public/components/metric_editor', () => ({ +jest.mock('../../../../components/metric_editor', () => ({ MetricsEditor: () => { return
mockMetricsEditor
; }, diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/where_expression.js b/x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/resources/where_expression.js similarity index 94% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/where_expression.js rename to x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/resources/where_expression.js index 54ec0ac46fa3d9..7c9b4f7b7b9a4d 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/where_expression.js +++ b/x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/resources/where_expression.js @@ -8,11 +8,7 @@ import React, { Component } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiButton, EuiPopover, EuiExpression, EuiFormHelpText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { - getUiSettings, - getData, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../../../../../plugins/maps/public/kibana_services'; +import { getUiSettings, getData } from '../../../../kibana_services'; export class WhereExpression extends Component { state = { diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/view.js b/x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/view.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/view.js rename to x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/view.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/layer_errors/__snapshots__/layer_errors.test.js.snap b/x-pack/plugins/maps/public/connected_components/layer_panel/layer_errors/__snapshots__/layer_errors.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/layer_errors/__snapshots__/layer_errors.test.js.snap rename to x-pack/plugins/maps/public/connected_components/layer_panel/layer_errors/__snapshots__/layer_errors.test.js.snap diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/layer_errors/index.js b/x-pack/plugins/maps/public/connected_components/layer_panel/layer_errors/index.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/layer_errors/index.js rename to x-pack/plugins/maps/public/connected_components/layer_panel/layer_errors/index.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/layer_errors/layer_errors.js b/x-pack/plugins/maps/public/connected_components/layer_panel/layer_errors/layer_errors.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/layer_errors/layer_errors.js rename to x-pack/plugins/maps/public/connected_components/layer_panel/layer_errors/layer_errors.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/layer_errors/layer_errors.test.js b/x-pack/plugins/maps/public/connected_components/layer_panel/layer_errors/layer_errors.test.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/layer_errors/layer_errors.test.js rename to x-pack/plugins/maps/public/connected_components/layer_panel/layer_errors/layer_errors.test.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/layer_settings/index.js b/x-pack/plugins/maps/public/connected_components/layer_panel/layer_settings/index.js similarity index 90% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/layer_settings/index.js rename to x-pack/plugins/maps/public/connected_components/layer_panel/layer_settings/index.js index 73c98db8e429de..e2f22c584d3b31 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/layer_settings/index.js +++ b/x-pack/plugins/maps/public/connected_components/layer_panel/layer_settings/index.js @@ -13,10 +13,13 @@ import { updateLayerMinZoom, updateLayerAlpha, } from '../../../actions/map_actions'; +import { MAX_ZOOM } from '../../../../common/constants'; function mapStateToProps(state = {}) { const selectedLayer = getSelectedLayer(state); return { + minVisibilityZoom: selectedLayer.getMinSourceZoom(), + maxVisibilityZoom: MAX_ZOOM, alpha: selectedLayer.getAlpha(), label: selectedLayer.getLabel(), layerId: selectedLayer.getId(), diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/layer_settings/layer_settings.js b/x-pack/plugins/maps/public/connected_components/layer_panel/layer_settings/layer_settings.js similarity index 84% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/layer_settings/layer_settings.js rename to x-pack/plugins/maps/public/connected_components/layer_panel/layer_settings/layer_settings.js index bd274509436382..168c735ab7a6c1 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/layer_settings/layer_settings.js +++ b/x-pack/plugins/maps/public/connected_components/layer_panel/layer_settings/layer_settings.js @@ -8,13 +8,10 @@ import React, { Fragment } from 'react'; import { EuiTitle, EuiPanel, EuiFormRow, EuiFieldText, EuiSpacer } from '@elastic/eui'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ValidatedRange } from '../../../../../../../plugins/maps/public/components/validated_range'; +import { ValidatedRange } from '../../../components/validated_range'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { ValidatedDualRange } from '../../../../../../../../src/plugins/kibana_react/public'; -import { MAX_ZOOM, MIN_ZOOM } from '../../../../common/constants'; - +import { ValidatedDualRange } from '../../../../../../../src/plugins/kibana_react/public'; export function LayerSettings(props) { const onLabelChange = event => { const label = event.target.value; @@ -22,8 +19,8 @@ export function LayerSettings(props) { }; const onZoomChange = ([min, max]) => { - props.updateMinZoom(props.layerId, Math.max(MIN_ZOOM, parseInt(min, 10))); - props.updateMaxZoom(props.layerId, Math.min(MAX_ZOOM, parseInt(max, 10))); + props.updateMinZoom(props.layerId, Math.max(props.minVisibilityZoom, parseInt(min, 10))); + props.updateMaxZoom(props.layerId, Math.min(props.maxVisibilityZoom, parseInt(max, 10))); }; const onAlphaChange = alpha => { @@ -38,8 +35,8 @@ export function LayerSettings(props) { defaultMessage: 'Visibility', })} formRowDisplay="columnCompressed" - min={MIN_ZOOM} - max={MAX_ZOOM} + min={props.minVisibilityZoom} + max={props.maxVisibilityZoom} value={[props.minZoom, props.maxZoom]} showInput="inputWithPopover" showRange diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/style_settings/_style_settings.scss b/x-pack/plugins/maps/public/connected_components/layer_panel/style_settings/_style_settings.scss similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/style_settings/_style_settings.scss rename to x-pack/plugins/maps/public/connected_components/layer_panel/style_settings/_style_settings.scss diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/style_settings/index.js b/x-pack/plugins/maps/public/connected_components/layer_panel/style_settings/index.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/style_settings/index.js rename to x-pack/plugins/maps/public/connected_components/layer_panel/style_settings/index.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/style_settings/style_settings.js b/x-pack/plugins/maps/public/connected_components/layer_panel/style_settings/style_settings.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/style_settings/style_settings.js rename to x-pack/plugins/maps/public/connected_components/layer_panel/style_settings/style_settings.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.js b/x-pack/plugins/maps/public/connected_components/layer_panel/view.js similarity index 95% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.js rename to x-pack/plugins/maps/public/connected_components/layer_panel/view.js index 2521318f0b3c9c..f8b7c417e67fd2 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.js +++ b/x-pack/plugins/maps/public/connected_components/layer_panel/view.js @@ -28,10 +28,10 @@ import { import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { KibanaContextProvider } from '../../../../../../../src/plugins/kibana_react/public'; -import { Storage } from '../../../../../../../src/plugins/kibana_utils/public'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getData, getCore } from '../../../../../../plugins/maps/public/kibana_services'; +import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; +import { Storage } from '../../../../../../src/plugins/kibana_utils/public'; + +import { getData, getCore } from '../../kibana_services'; const localStorage = new Storage(window.localStorage); diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.test.js b/x-pack/plugins/maps/public/connected_components/layer_panel/view.test.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.test.js rename to x-pack/plugins/maps/public/connected_components/layer_panel/view.test.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/__snapshots__/feature_properties.test.js.snap b/x-pack/plugins/maps/public/connected_components/map/features_tooltip/__snapshots__/feature_properties.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/__snapshots__/feature_properties.test.js.snap rename to x-pack/plugins/maps/public/connected_components/map/features_tooltip/__snapshots__/feature_properties.test.js.snap diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/__snapshots__/tooltip_header.test.js.snap b/x-pack/plugins/maps/public/connected_components/map/features_tooltip/__snapshots__/tooltip_header.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/__snapshots__/tooltip_header.test.js.snap rename to x-pack/plugins/maps/public/connected_components/map/features_tooltip/__snapshots__/tooltip_header.test.js.snap diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/_index.scss b/x-pack/plugins/maps/public/connected_components/map/features_tooltip/_index.scss similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/_index.scss rename to x-pack/plugins/maps/public/connected_components/map/features_tooltip/_index.scss diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/feature_geometry_filter_form.js b/x-pack/plugins/maps/public/connected_components/map/features_tooltip/feature_geometry_filter_form.js similarity index 92% rename from x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/feature_geometry_filter_form.js rename to x-pack/plugins/maps/public/connected_components/map/features_tooltip/feature_geometry_filter_form.js index 15824b82965e83..b103fb43af97c7 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/feature_geometry_filter_form.js +++ b/x-pack/plugins/maps/public/connected_components/map/features_tooltip/feature_geometry_filter_form.js @@ -8,12 +8,12 @@ import React, { Component, Fragment } from 'react'; import { EuiIcon } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { createSpatialFilterWithGeometry } from '../../../../../../../plugins/maps/public/elasticsearch_geo_utils'; + +import { createSpatialFilterWithGeometry } from '../../../elasticsearch_geo_utils'; import { GEO_JSON_TYPE } from '../../../../common/constants'; import { GeometryFilterForm } from '../../../components/geometry_filter_form'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { UrlOverflowService } from '../../../../../../../../src/plugins/kibana_legacy/public'; + +import { UrlOverflowService } from '../../../../../../../src/plugins/kibana_legacy/public'; import rison from 'rison-node'; // over estimated and imprecise value to ensure filter has additional room for any meta keys added when filter is mapped. diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/feature_properties.js b/x-pack/plugins/maps/public/connected_components/map/features_tooltip/feature_properties.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/feature_properties.js rename to x-pack/plugins/maps/public/connected_components/map/features_tooltip/feature_properties.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/feature_properties.test.js b/x-pack/plugins/maps/public/connected_components/map/features_tooltip/feature_properties.test.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/feature_properties.test.js rename to x-pack/plugins/maps/public/connected_components/map/features_tooltip/feature_properties.test.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/features_tooltip.js b/x-pack/plugins/maps/public/connected_components/map/features_tooltip/features_tooltip.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/features_tooltip.js rename to x-pack/plugins/maps/public/connected_components/map/features_tooltip/features_tooltip.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/tooltip_header.js b/x-pack/plugins/maps/public/connected_components/map/features_tooltip/tooltip_header.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/tooltip_header.js rename to x-pack/plugins/maps/public/connected_components/map/features_tooltip/tooltip_header.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/tooltip_header.test.js b/x-pack/plugins/maps/public/connected_components/map/features_tooltip/tooltip_header.test.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/map/features_tooltip/tooltip_header.test.js rename to x-pack/plugins/maps/public/connected_components/map/features_tooltip/tooltip_header.test.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/draw_control/draw_circle.ts b/x-pack/plugins/maps/public/connected_components/map/mb/draw_control/draw_circle.ts similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/map/mb/draw_control/draw_circle.ts rename to x-pack/plugins/maps/public/connected_components/map/mb/draw_control/draw_circle.ts diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/draw_control/draw_control.js b/x-pack/plugins/maps/public/connected_components/map/mb/draw_control/draw_control.js similarity index 96% rename from x-pack/legacy/plugins/maps/public/connected_components/map/mb/draw_control/draw_control.js rename to x-pack/plugins/maps/public/connected_components/map/mb/draw_control/draw_control.js index cc0e665525036f..d20faa39d6492a 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/draw_control/draw_control.js +++ b/x-pack/plugins/maps/public/connected_components/map/mb/draw_control/draw_control.js @@ -15,8 +15,7 @@ import { createSpatialFilterWithGeometry, getBoundingBoxGeometry, roundCoordinates, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../../../../../plugins/maps/public/elasticsearch_geo_utils'; +} from '../../../../elasticsearch_geo_utils'; import { DrawTooltip } from './draw_tooltip'; const mbDrawModes = MapboxDraw.modes; diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/draw_control/draw_tooltip.js b/x-pack/plugins/maps/public/connected_components/map/mb/draw_control/draw_tooltip.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/map/mb/draw_control/draw_tooltip.js rename to x-pack/plugins/maps/public/connected_components/map/mb/draw_control/draw_tooltip.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/draw_control/index.js b/x-pack/plugins/maps/public/connected_components/map/mb/draw_control/index.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/map/mb/draw_control/index.js rename to x-pack/plugins/maps/public/connected_components/map/mb/draw_control/index.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/index.js b/x-pack/plugins/maps/public/connected_components/map/mb/index.js similarity index 91% rename from x-pack/legacy/plugins/maps/public/connected_components/map/mb/index.js rename to x-pack/plugins/maps/public/connected_components/map/mb/index.js index 350cb7028abee2..d864b60eb433bf 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/index.js +++ b/x-pack/plugins/maps/public/connected_components/map/mb/index.js @@ -24,8 +24,8 @@ import { isTooltipControlDisabled, isViewControlHidden, } from '../../../selectors/map_selectors'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getInspectorAdapters } from '../../../../../../../plugins/maps/public/reducers/non_serializable_instances'; + +import { getInspectorAdapters } from '../../../reducers/non_serializable_instances'; function mapStateToProps(state = {}) { return { diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/mb.utils.test.js b/x-pack/plugins/maps/public/connected_components/map/mb/mb.utils.test.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/map/mb/mb.utils.test.js rename to x-pack/plugins/maps/public/connected_components/map/mb/mb.utils.test.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/tooltip_control/__snapshots__/tooltip_control.test.js.snap b/x-pack/plugins/maps/public/connected_components/map/mb/tooltip_control/__snapshots__/tooltip_control.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/map/mb/tooltip_control/__snapshots__/tooltip_control.test.js.snap rename to x-pack/plugins/maps/public/connected_components/map/mb/tooltip_control/__snapshots__/tooltip_control.test.js.snap diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/tooltip_control/__snapshots__/tooltip_popover.test.js.snap b/x-pack/plugins/maps/public/connected_components/map/mb/tooltip_control/__snapshots__/tooltip_popover.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/map/mb/tooltip_control/__snapshots__/tooltip_popover.test.js.snap rename to x-pack/plugins/maps/public/connected_components/map/mb/tooltip_control/__snapshots__/tooltip_popover.test.js.snap diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/tooltip_control/index.js b/x-pack/plugins/maps/public/connected_components/map/mb/tooltip_control/index.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/map/mb/tooltip_control/index.js rename to x-pack/plugins/maps/public/connected_components/map/mb/tooltip_control/index.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/tooltip_control/tooltip_control.js b/x-pack/plugins/maps/public/connected_components/map/mb/tooltip_control/tooltip_control.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/map/mb/tooltip_control/tooltip_control.js rename to x-pack/plugins/maps/public/connected_components/map/mb/tooltip_control/tooltip_control.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/tooltip_control/tooltip_control.test.js b/x-pack/plugins/maps/public/connected_components/map/mb/tooltip_control/tooltip_control.test.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/map/mb/tooltip_control/tooltip_control.test.js rename to x-pack/plugins/maps/public/connected_components/map/mb/tooltip_control/tooltip_control.test.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/tooltip_control/tooltip_popover.js b/x-pack/plugins/maps/public/connected_components/map/mb/tooltip_control/tooltip_popover.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/map/mb/tooltip_control/tooltip_popover.js rename to x-pack/plugins/maps/public/connected_components/map/mb/tooltip_control/tooltip_popover.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/tooltip_control/tooltip_popover.test.js b/x-pack/plugins/maps/public/connected_components/map/mb/tooltip_control/tooltip_popover.test.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/map/mb/tooltip_control/tooltip_popover.test.js rename to x-pack/plugins/maps/public/connected_components/map/mb/tooltip_control/tooltip_popover.test.js diff --git a/x-pack/plugins/maps/public/connected_components/map/mb/utils.js b/x-pack/plugins/maps/public/connected_components/map/mb/utils.js index 15aacfbf1f38db..7be2cd9e670843 100644 --- a/x-pack/plugins/maps/public/connected_components/map/mb/utils.js +++ b/x-pack/plugins/maps/public/connected_components/map/mb/utils.js @@ -4,8 +4,102 @@ * you may not use this file except in compliance with the Elastic License. */ +import _ from 'lodash'; import { RGBAImage } from './image_utils'; +export function removeOrphanedSourcesAndLayers(mbMap, layerList) { + const mbStyle = mbMap.getStyle(); + + const mbLayerIdsToRemove = []; + mbStyle.layers.forEach(mbLayer => { + const layer = layerList.find(layer => { + return layer.ownsMbLayerId(mbLayer.id); + }); + if (!layer) { + mbLayerIdsToRemove.push(mbLayer.id); + } + }); + mbLayerIdsToRemove.forEach(mbLayerId => mbMap.removeLayer(mbLayerId)); + + const mbSourcesToRemove = []; + for (const mbSourceId in mbStyle.sources) { + if (mbStyle.sources.hasOwnProperty(mbSourceId)) { + const layer = layerList.find(layer => { + return layer.ownsMbSourceId(mbSourceId); + }); + if (!layer) { + mbSourcesToRemove.push(mbSourceId); + } + } + } + mbSourcesToRemove.forEach(mbSourceId => mbMap.removeSource(mbSourceId)); +} + +/** + * This is function assumes only a single layer moved in the layerList, compared to mbMap + * It is optimized to minimize the amount of mbMap.moveLayer calls. + * @param mbMap + * @param layerList + */ +export function syncLayerOrderForSingleLayer(mbMap, layerList) { + if (!layerList || layerList.length === 0) { + return; + } + + const mbLayers = mbMap.getStyle().layers.slice(); + const layerIds = mbLayers.map(mbLayer => { + const layer = layerList.find(layer => layer.ownsMbLayerId(mbLayer.id)); + return layer.getId(); + }); + + const currentLayerOrderLayerIds = _.uniq(layerIds); + + const newLayerOrderLayerIdsUnfiltered = layerList.map(l => l.getId()); + const newLayerOrderLayerIds = newLayerOrderLayerIdsUnfiltered.filter(layerId => + currentLayerOrderLayerIds.includes(layerId) + ); + + let netPos = 0; + let netNeg = 0; + const movementArr = currentLayerOrderLayerIds.reduce((accu, id, idx) => { + const movement = newLayerOrderLayerIds.findIndex(newOId => newOId === id) - idx; + movement > 0 ? netPos++ : movement < 0 && netNeg++; + accu.push({ id, movement }); + return accu; + }, []); + if (netPos === 0 && netNeg === 0) { + return; + } + const movedLayerId = + (netPos >= netNeg && movementArr.find(l => l.movement < 0).id) || + (netPos < netNeg && movementArr.find(l => l.movement > 0).id); + const nextLayerIdx = newLayerOrderLayerIds.findIndex(layerId => layerId === movedLayerId) + 1; + + let nextMbLayerId; + if (nextLayerIdx === newLayerOrderLayerIds.length) { + nextMbLayerId = null; + } else { + const foundLayer = mbLayers.find(({ id: mbLayerId }) => { + const layerId = newLayerOrderLayerIds[nextLayerIdx]; + const layer = layerList.find(layer => layer.getId() === layerId); + return layer.ownsMbLayerId(mbLayerId); + }); + nextMbLayerId = foundLayer.id; + } + + const movedLayer = layerList.find(layer => layer.getId() === movedLayerId); + mbLayers.forEach(({ id: mbLayerId }) => { + if (movedLayer.ownsMbLayerId(mbLayerId)) { + mbMap.moveLayer(mbLayerId, nextMbLayerId); + } + }); +} + +export async function addSpritesheetToMap(json, imgUrl, mbMap) { + const imgData = await loadSpriteSheetImageData(imgUrl); + addSpriteSheetToMapFromImageData(json, imgData, mbMap); +} + function getImageData(img) { const canvas = window.document.createElement('canvas'); const context = canvas.getContext('2d'); diff --git a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/view.js b/x-pack/plugins/maps/public/connected_components/map/mb/view.js similarity index 93% rename from x-pack/legacy/plugins/maps/public/connected_components/map/mb/view.js rename to x-pack/plugins/maps/public/connected_components/map/mb/view.js index 1fe3d0d493ee79..0008ca5cb0f033 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/map/mb/view.js +++ b/x-pack/plugins/maps/public/connected_components/map/mb/view.js @@ -6,15 +6,19 @@ import _ from 'lodash'; import React from 'react'; -import { ResizeChecker } from '../../../../../../../../src/plugins/kibana_utils/public'; +import { ResizeChecker } from '../../../../../../../src/plugins/kibana_utils/public'; import { syncLayerOrderForSingleLayer, removeOrphanedSourcesAndLayers, addSpritesheetToMap, } from './utils'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getGlyphUrl, isRetina } from '../../../../../../../plugins/maps/public/meta'; -import { DECIMAL_DEGREES_PRECISION, ZOOM_PRECISION } from '../../../../common/constants'; +import { getGlyphUrl, isRetina } from '../../../meta'; +import { + DECIMAL_DEGREES_PRECISION, + MAX_ZOOM, + MIN_ZOOM, + ZOOM_PRECISION, +} from '../../../../common/constants'; import mapboxgl from 'mapbox-gl/dist/mapbox-gl-csp'; import mbWorkerUrl from '!!file-loader!mapbox-gl/dist/mapbox-gl-csp-worker'; import mbRtlPlugin from '!!file-loader!@mapbox/mapbox-gl-rtl-text/mapbox-gl-rtl-text.min.js'; @@ -23,13 +27,9 @@ import sprites1 from '@elastic/maki/dist/sprite@1.png'; import sprites2 from '@elastic/maki/dist/sprite@2.png'; import { DrawControl } from './draw_control'; import { TooltipControl } from './tooltip_control'; -import { - clampToLatBounds, - clampToLonBounds, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../../../../plugins/maps/public/elasticsearch_geo_utils'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getInjectedVarFunc } from '../../../../../../../plugins/maps/public/kibana_services'; +import { clampToLatBounds, clampToLonBounds } from '../../../elasticsearch_geo_utils'; + +import { getInjectedVarFunc } from '../../../kibana_services'; mapboxgl.workerUrl = mbWorkerUrl; mapboxgl.setRTLTextPlugin(mbRtlPlugin); @@ -132,6 +132,8 @@ export class MBMapContainer extends React.Component { scrollZoom: this.props.scrollZoom, preserveDrawingBuffer: getInjectedVarFunc()('preserveDrawingBuffer', false), interactive: !this.props.disableInteractive, + minZoom: MIN_ZOOM, + maxZoom: MAX_ZOOM, }; const initialView = _.get(this.props.goto, 'center'); if (initialView) { diff --git a/x-pack/legacy/plugins/maps/public/connected_components/toolbar_overlay/_index.scss b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/_index.scss similarity index 93% rename from x-pack/legacy/plugins/maps/public/connected_components/toolbar_overlay/_index.scss rename to x-pack/plugins/maps/public/connected_components/toolbar_overlay/_index.scss index 01aea403b27f09..2754a3e204263f 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/toolbar_overlay/_index.scss +++ b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/_index.scss @@ -1,4 +1,4 @@ -@import './tools_control/index'; +@import 'tools_control/index'; .mapToolbarOverlay { position: absolute; diff --git a/x-pack/legacy/plugins/maps/public/connected_components/toolbar_overlay/index.js b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/index.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/toolbar_overlay/index.js rename to x-pack/plugins/maps/public/connected_components/toolbar_overlay/index.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/toolbar_overlay/set_view_control/index.js b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/set_view_control/index.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/toolbar_overlay/set_view_control/index.js rename to x-pack/plugins/maps/public/connected_components/toolbar_overlay/set_view_control/index.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/toolbar_overlay/set_view_control/set_view_control.js b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/set_view_control/set_view_control.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/toolbar_overlay/set_view_control/set_view_control.js rename to x-pack/plugins/maps/public/connected_components/toolbar_overlay/set_view_control/set_view_control.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/toolbar_overlay/toolbar_overlay.js b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/toolbar_overlay.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/toolbar_overlay/toolbar_overlay.js rename to x-pack/plugins/maps/public/connected_components/toolbar_overlay/toolbar_overlay.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/toolbar_overlay/tools_control/__snapshots__/tools_control.test.js.snap b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/tools_control/__snapshots__/tools_control.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/toolbar_overlay/tools_control/__snapshots__/tools_control.test.js.snap rename to x-pack/plugins/maps/public/connected_components/toolbar_overlay/tools_control/__snapshots__/tools_control.test.js.snap diff --git a/x-pack/legacy/plugins/maps/public/connected_components/toolbar_overlay/tools_control/_index.scss b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/tools_control/_index.scss similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/toolbar_overlay/tools_control/_index.scss rename to x-pack/plugins/maps/public/connected_components/toolbar_overlay/tools_control/_index.scss diff --git a/x-pack/legacy/plugins/maps/public/connected_components/toolbar_overlay/tools_control/index.js b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/tools_control/index.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/toolbar_overlay/tools_control/index.js rename to x-pack/plugins/maps/public/connected_components/toolbar_overlay/tools_control/index.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/toolbar_overlay/tools_control/tools_control.js b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/tools_control/tools_control.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/toolbar_overlay/tools_control/tools_control.js rename to x-pack/plugins/maps/public/connected_components/toolbar_overlay/tools_control/tools_control.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/toolbar_overlay/tools_control/tools_control.test.js b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/tools_control/tools_control.test.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/toolbar_overlay/tools_control/tools_control.test.js rename to x-pack/plugins/maps/public/connected_components/toolbar_overlay/tools_control/tools_control.test.js diff --git a/x-pack/plugins/maps/public/connected_components/widget_overlay/_index.scss b/x-pack/plugins/maps/public/connected_components/widget_overlay/_index.scss new file mode 100644 index 00000000000000..5e5086bed2763f --- /dev/null +++ b/x-pack/plugins/maps/public/connected_components/widget_overlay/_index.scss @@ -0,0 +1,6 @@ +@import 'mixins'; + +@import 'widget_overlay'; +@import 'attribution_control/attribution_control'; +@import 'layer_control/index'; +@import 'view_control/view_control'; diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/_mixins.scss b/x-pack/plugins/maps/public/connected_components/widget_overlay/_mixins.scss similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/_mixins.scss rename to x-pack/plugins/maps/public/connected_components/widget_overlay/_mixins.scss diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/_widget_overlay.scss b/x-pack/plugins/maps/public/connected_components/widget_overlay/_widget_overlay.scss similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/_widget_overlay.scss rename to x-pack/plugins/maps/public/connected_components/widget_overlay/_widget_overlay.scss diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/attribution_control/__snapshots__/view.test.js.snap b/x-pack/plugins/maps/public/connected_components/widget_overlay/attribution_control/__snapshots__/view.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/attribution_control/__snapshots__/view.test.js.snap rename to x-pack/plugins/maps/public/connected_components/widget_overlay/attribution_control/__snapshots__/view.test.js.snap diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/attribution_control/_attribution_control.scss b/x-pack/plugins/maps/public/connected_components/widget_overlay/attribution_control/_attribution_control.scss similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/attribution_control/_attribution_control.scss rename to x-pack/plugins/maps/public/connected_components/widget_overlay/attribution_control/_attribution_control.scss diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/attribution_control/index.js b/x-pack/plugins/maps/public/connected_components/widget_overlay/attribution_control/index.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/attribution_control/index.js rename to x-pack/plugins/maps/public/connected_components/widget_overlay/attribution_control/index.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/attribution_control/view.js b/x-pack/plugins/maps/public/connected_components/widget_overlay/attribution_control/view.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/attribution_control/view.js rename to x-pack/plugins/maps/public/connected_components/widget_overlay/attribution_control/view.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/attribution_control/view.test.js b/x-pack/plugins/maps/public/connected_components/widget_overlay/attribution_control/view.test.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/attribution_control/view.test.js rename to x-pack/plugins/maps/public/connected_components/widget_overlay/attribution_control/view.test.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/index.js b/x-pack/plugins/maps/public/connected_components/widget_overlay/index.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/index.js rename to x-pack/plugins/maps/public/connected_components/widget_overlay/index.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/__snapshots__/view.test.js.snap b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/__snapshots__/view.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/__snapshots__/view.test.js.snap rename to x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/__snapshots__/view.test.js.snap diff --git a/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/_index.scss b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/_index.scss new file mode 100644 index 00000000000000..9a3e3a45d6c4e5 --- /dev/null +++ b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/_index.scss @@ -0,0 +1,2 @@ +@import 'layer_control'; +@import 'layer_toc/toc_entry/toc_entry'; diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/_layer_control.scss b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/_layer_control.scss similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/_layer_control.scss rename to x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/_layer_control.scss diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/index.js b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/index.js similarity index 90% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/index.js rename to x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/index.js index 04de5f71f5bfc4..8780bac59e4b72 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/index.js +++ b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/index.js @@ -6,8 +6,8 @@ import { connect } from 'react-redux'; import { LayerControl } from './view'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { FLYOUT_STATE } from '../../../../../../../plugins/maps/public/reducers/ui'; + +import { FLYOUT_STATE } from '../../../reducers/ui'; import { updateFlyout, setIsLayerTOCOpen } from '../../../actions/ui_actions'; import { setSelectedLayer } from '../../../actions/map_actions'; import { diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/__snapshots__/view.test.js.snap b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/__snapshots__/view.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/__snapshots__/view.test.js.snap rename to x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/__snapshots__/view.test.js.snap diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/index.js b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/index.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/index.js rename to x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/index.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/__snapshots__/view.test.js.snap b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/__snapshots__/view.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/__snapshots__/view.test.js.snap rename to x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/__snapshots__/view.test.js.snap diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/_toc_entry.scss b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/_toc_entry.scss similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/_toc_entry.scss rename to x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/_toc_entry.scss diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/index.js b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/index.js similarity index 93% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/index.js rename to x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/index.js index 588445d0b49928..ca3c6d325687dd 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/index.js +++ b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/index.js @@ -7,8 +7,8 @@ import _ from 'lodash'; import { connect } from 'react-redux'; import { TOCEntry } from './view'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { FLYOUT_STATE } from '../../../../../../../../../plugins/maps/public/reducers/ui'; + +import { FLYOUT_STATE } from '../../../../../reducers/ui'; import { updateFlyout, hideTOCDetails, showTOCDetails } from '../../../../../actions/ui_actions'; import { getIsReadOnly, getOpenTOCDetails } from '../../../../../selectors/ui_selectors'; import { diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/view.js b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/view.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/view.js rename to x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/view.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/view.test.js b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/view.test.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/view.test.js rename to x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/view.test.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/view.js b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/view.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/view.js rename to x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/view.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/view.test.js b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/view.test.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/view.test.js rename to x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/view.test.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/view.js b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/view.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/view.js rename to x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/view.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/view.test.js b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/view.test.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/layer_control/view.test.js rename to x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/view.test.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/view_control/_view_control.scss b/x-pack/plugins/maps/public/connected_components/widget_overlay/view_control/_view_control.scss similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/view_control/_view_control.scss rename to x-pack/plugins/maps/public/connected_components/widget_overlay/view_control/_view_control.scss diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/view_control/index.js b/x-pack/plugins/maps/public/connected_components/widget_overlay/view_control/index.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/view_control/index.js rename to x-pack/plugins/maps/public/connected_components/widget_overlay/view_control/index.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/view_control/view_control.js b/x-pack/plugins/maps/public/connected_components/widget_overlay/view_control/view_control.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/view_control/view_control.js rename to x-pack/plugins/maps/public/connected_components/widget_overlay/view_control/view_control.js diff --git a/x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/widget_overlay.js b/x-pack/plugins/maps/public/connected_components/widget_overlay/widget_overlay.js similarity index 100% rename from x-pack/legacy/plugins/maps/public/connected_components/widget_overlay/widget_overlay.js rename to x-pack/plugins/maps/public/connected_components/widget_overlay/widget_overlay.js diff --git a/x-pack/plugins/maps/public/elasticsearch_geo_utils.js b/x-pack/plugins/maps/public/elasticsearch_geo_utils.js index 617cf537fd5c31..417c5d84f8916e 100644 --- a/x-pack/plugins/maps/public/elasticsearch_geo_utils.js +++ b/x-pack/plugins/maps/public/elasticsearch_geo_utils.js @@ -64,7 +64,7 @@ function ensureGeometryType(type, expectedTypes) { * @param {string} geoFieldType Geometry field type ["geo_point", "geo_shape"] * @returns {number} */ -export function hitsToGeoJson(hits, flattenHit, geoFieldName, geoFieldType) { +export function hitsToGeoJson(hits, flattenHit, geoFieldName, geoFieldType, epochMillisFields) { const features = []; const tmpGeometriesAccumulator = []; @@ -80,6 +80,16 @@ export function hitsToGeoJson(hits, flattenHit, geoFieldName, geoFieldType) { geoShapeToGeometry(properties[geoFieldName], tmpGeometriesAccumulator); } + // There is a bug in Elasticsearch API where epoch_millis are returned as a string instead of a number + // https://github.com/elastic/elasticsearch/issues/50622 + // Convert these field values to integers. + for (let i = 0; i < epochMillisFields.length; i++) { + const fieldName = epochMillisFields[i]; + if (typeof properties[fieldName] === 'string') { + properties[fieldName] = parseInt(properties[fieldName]); + } + } + // don't include geometry field value in properties delete properties[geoFieldName]; diff --git a/x-pack/plugins/maps/public/elasticsearch_geo_utils.test.js b/x-pack/plugins/maps/public/elasticsearch_geo_utils.test.js index 5db7556be4639d..fc02e191738432 100644 --- a/x-pack/plugins/maps/public/elasticsearch_geo_utils.test.js +++ b/x-pack/plugins/maps/public/elasticsearch_geo_utils.test.js @@ -66,7 +66,7 @@ describe('hitsToGeoJson', () => { }, }, ]; - const geojson = hitsToGeoJson(hits, flattenHitMock, geoFieldName, 'geo_point'); + const geojson = hitsToGeoJson(hits, flattenHitMock, geoFieldName, 'geo_point', []); expect(geojson.type).toBe('FeatureCollection'); expect(geojson.features.length).toBe(2); expect(geojson.features[0]).toEqual({ @@ -94,7 +94,7 @@ describe('hitsToGeoJson', () => { _source: {}, }, ]; - const geojson = hitsToGeoJson(hits, flattenHitMock, geoFieldName, 'geo_point'); + const geojson = hitsToGeoJson(hits, flattenHitMock, geoFieldName, 'geo_point', []); expect(geojson.type).toBe('FeatureCollection'); expect(geojson.features.length).toBe(1); }); @@ -111,7 +111,7 @@ describe('hitsToGeoJson', () => { }, }, ]; - const geojson = hitsToGeoJson(hits, flattenHitMock, geoFieldName, 'geo_point'); + const geojson = hitsToGeoJson(hits, flattenHitMock, geoFieldName, 'geo_point', []); expect(geojson.features.length).toBe(1); const feature = geojson.features[0]; expect(feature.properties.myField).toBe(8); @@ -128,7 +128,7 @@ describe('hitsToGeoJson', () => { }, }, ]; - const geojson = hitsToGeoJson(hits, flattenHitMock, geoFieldName, 'geo_point'); + const geojson = hitsToGeoJson(hits, flattenHitMock, geoFieldName, 'geo_point', []); expect(geojson.type).toBe('FeatureCollection'); expect(geojson.features.length).toBe(2); expect(geojson.features[0]).toEqual({ @@ -159,6 +159,23 @@ describe('hitsToGeoJson', () => { }); }); + it('Should convert epoch_millis value from string to integer', () => { + const hits = [ + { + _id: 'doc1', + _index: 'index1', + _source: { + [geoFieldName]: '20,100', + myDateField: '1587156257081', + }, + }, + ]; + const geojson = hitsToGeoJson(hits, flattenHitMock, geoFieldName, 'geo_point', ['myDateField']); + expect(geojson.type).toBe('FeatureCollection'); + expect(geojson.features.length).toBe(1); + expect(geojson.features[0].properties.myDateField).toBe(1587156257081); + }); + describe('dot in geoFieldName', () => { const indexPatternMock = { fields: { @@ -184,7 +201,7 @@ describe('hitsToGeoJson', () => { }, }, ]; - const geojson = hitsToGeoJson(hits, indexPatternFlattenHit, 'my.location', 'geo_point'); + const geojson = hitsToGeoJson(hits, indexPatternFlattenHit, 'my.location', 'geo_point', []); expect(geojson.features[0].geometry).toEqual({ coordinates: [100, 20], type: 'Point', @@ -199,7 +216,7 @@ describe('hitsToGeoJson', () => { }, }, ]; - const geojson = hitsToGeoJson(hits, indexPatternFlattenHit, 'my.location', 'geo_point'); + const geojson = hitsToGeoJson(hits, indexPatternFlattenHit, 'my.location', 'geo_point', []); expect(geojson.features[0].geometry).toEqual({ coordinates: [100, 20], type: 'Point', diff --git a/x-pack/legacy/plugins/maps/public/embeddable/README.md b/x-pack/plugins/maps/public/embeddable/README.md similarity index 100% rename from x-pack/legacy/plugins/maps/public/embeddable/README.md rename to x-pack/plugins/maps/public/embeddable/README.md diff --git a/x-pack/legacy/plugins/maps/public/embeddable/index.ts b/x-pack/plugins/maps/public/embeddable/index.ts similarity index 100% rename from x-pack/legacy/plugins/maps/public/embeddable/index.ts rename to x-pack/plugins/maps/public/embeddable/index.ts diff --git a/x-pack/legacy/plugins/maps/public/embeddable/map_embeddable.tsx b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx similarity index 90% rename from x-pack/legacy/plugins/maps/public/embeddable/map_embeddable.tsx rename to x-pack/plugins/maps/public/embeddable/map_embeddable.tsx index b8e4c84ad56a17..dbd48d614e99b4 100644 --- a/x-pack/legacy/plugins/maps/public/embeddable/map_embeddable.tsx +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx @@ -9,8 +9,6 @@ import React from 'react'; import { Provider } from 'react-redux'; import { render, unmountComponentAtNode } from 'react-dom'; import 'mapbox-gl/dist/mapbox-gl.css'; - -import { I18nContext } from 'ui/i18n'; import { Subscription } from 'rxjs'; import { Unsubscribe } from 'redux'; import { @@ -18,8 +16,8 @@ import { IContainer, EmbeddableInput, EmbeddableOutput, -} from '../../../../../../src/plugins/embeddable/public'; -import { APPLY_FILTER_TRIGGER } from '../../../../../../src/plugins/ui_actions/public'; +} from '../../../../../src/plugins/embeddable/public'; +import { APPLY_FILTER_TRIGGER } from '../../../../../src/plugins/ui_actions/public'; import { esFilters, IIndexPattern, @@ -27,11 +25,9 @@ import { Filter, Query, RefreshInterval, -} from '../../../../../../src/plugins/data/public'; - +} from '../../../../../src/plugins/data/public'; import { GisMap } from '../connected_components/gis_map'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { createMapStore, MapStore } from '../../../../../plugins/maps/public/reducers/store'; +import { createMapStore, MapStore } from '../reducers/store'; import { setGotoWithCenter, replaceLayerList, @@ -45,21 +41,18 @@ import { hideViewControl, setHiddenLayers, } from '../actions/map_actions'; -import { MapCenterAndZoom } from '../../../../../plugins/maps/common/descriptor_types'; +import { MapCenterAndZoom } from '../../common/descriptor_types'; import { setReadOnly, setIsLayerTOCOpen, setOpenTOCDetails } from '../actions/ui_actions'; import { getIsLayerTOCOpen, getOpenTOCDetails } from '../selectors/ui_selectors'; import { getInspectorAdapters, setEventHandlers, EventHandlers, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../../plugins/maps/public/reducers/non_serializable_instances'; +} from '../reducers/non_serializable_instances'; import { getMapCenter, getMapZoom, getHiddenLayerIds } from '../selectors/map_selectors'; import { MAP_SAVED_OBJECT_TYPE } from '../../common/constants'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { RenderToolTipContent } from '../../../../../plugins/maps/public/layers/tooltips/tooltip_property'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getUiActions } from '../../../../../plugins/maps/public/kibana_services'; +import { RenderToolTipContent } from '../layers/tooltips/tooltip_property'; +import { getUiActions, getCoreI18n } from '../kibana_services'; interface MapEmbeddableConfig { editUrl?: string; @@ -247,6 +240,8 @@ export class MapEmbeddable extends Embeddable diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.ts b/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.ts new file mode 100644 index 00000000000000..a99fe63c5f3863 --- /dev/null +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.ts @@ -0,0 +1,136 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import _ from 'lodash'; +import { i18n } from '@kbn/i18n'; +import { IIndexPattern } from 'src/plugins/data/public'; +// @ts-ignore +import { getMapsSavedObjectLoader } from '../angular/services/gis_map_saved_object_loader'; +import { MapEmbeddable, MapEmbeddableInput } from './map_embeddable'; +import { getIndexPatternService, getHttp, getMapsCapabilities } from '../kibana_services'; +import { + EmbeddableFactoryDefinition, + IContainer, +} from '../../../../../src/plugins/embeddable/public'; + +import { createMapPath, MAP_SAVED_OBJECT_TYPE, APP_ICON } from '../../common/constants'; + +import { createMapStore } from '../reducers/store'; +import { addLayerWithoutDataSync } from '../actions/map_actions'; +import { getQueryableUniqueIndexPatternIds } from '../selectors/map_selectors'; +import { getInitialLayers } from '../angular/get_initial_layers'; +import { mergeInputWithSavedMap } from './merge_input_with_saved_map'; + +export class MapEmbeddableFactory implements EmbeddableFactoryDefinition { + type = MAP_SAVED_OBJECT_TYPE; + savedObjectMetaData = { + name: i18n.translate('xpack.maps.mapSavedObjectLabel', { + defaultMessage: 'Map', + }), + type: MAP_SAVED_OBJECT_TYPE, + getIconForSavedObject: () => APP_ICON, + }; + + async isEditable() { + return getMapsCapabilities().save as boolean; + } + + // Not supported yet for maps types. + canCreateNew() { + return false; + } + + getDisplayName() { + return i18n.translate('xpack.maps.embeddableDisplayName', { + defaultMessage: 'map', + }); + } + + async _getIndexPatterns(layerList: unknown[]): Promise { + // Need to extract layerList from store to get queryable index pattern ids + const store = createMapStore(); + let queryableIndexPatternIds; + try { + layerList.forEach((layerDescriptor: unknown) => { + store.dispatch(addLayerWithoutDataSync(layerDescriptor)); + }); + queryableIndexPatternIds = getQueryableUniqueIndexPatternIds(store.getState()); + } catch (error) { + throw new Error( + i18n.translate('xpack.maps.mapEmbeddableFactory.invalidLayerList', { + defaultMessage: 'Unable to load map, malformed layer list', + }) + ); + } + + const promises = queryableIndexPatternIds.map(async indexPatternId => { + try { + return await getIndexPatternService().get(indexPatternId); + } catch (error) { + // Unable to load index pattern, better to not throw error so map embeddable can render + // Error will be surfaced by map embeddable since it too will be unable to locate the index pattern + return null; + } + }); + const indexPatterns = await Promise.all(promises); + return _.compact(indexPatterns) as IIndexPattern[]; + } + + async _fetchSavedMap(savedObjectId: string) { + const savedObjectLoader = getMapsSavedObjectLoader(); + return await savedObjectLoader.get(savedObjectId); + } + + createFromSavedObject = async ( + savedObjectId: string, + input: MapEmbeddableInput, + parent?: IContainer + ) => { + const savedMap = await this._fetchSavedMap(savedObjectId); + const layerList = getInitialLayers(savedMap.layerListJSON); + const indexPatterns = await this._getIndexPatterns(layerList); + + const embeddable = new MapEmbeddable( + { + layerList, + title: savedMap.title, + editUrl: getHttp().basePath.prepend(createMapPath(savedObjectId)), + indexPatterns, + editable: await this.isEditable(), + }, + input, + parent + ); + + try { + embeddable.updateInput(mergeInputWithSavedMap(input, savedMap)); + } catch (error) { + throw new Error( + i18n.translate('xpack.maps.mapEmbeddableFactory.invalidSavedObject', { + defaultMessage: 'Unable to load map, malformed saved object', + }) + ); + } + + return embeddable; + }; + + create = async (input: MapEmbeddableInput, parent?: IContainer) => { + const layerList = getInitialLayers(); + const indexPatterns = await this._getIndexPatterns(layerList); + + return new MapEmbeddable( + { + layerList, + title: input.title ?? '', + indexPatterns, + editable: false, + }, + input, + parent + ); + }; +} diff --git a/x-pack/legacy/plugins/maps/public/embeddable/merge_input_with_saved_map.d.ts b/x-pack/plugins/maps/public/embeddable/merge_input_with_saved_map.d.ts similarity index 100% rename from x-pack/legacy/plugins/maps/public/embeddable/merge_input_with_saved_map.d.ts rename to x-pack/plugins/maps/public/embeddable/merge_input_with_saved_map.d.ts diff --git a/x-pack/legacy/plugins/maps/public/embeddable/merge_input_with_saved_map.js b/x-pack/plugins/maps/public/embeddable/merge_input_with_saved_map.js similarity index 89% rename from x-pack/legacy/plugins/maps/public/embeddable/merge_input_with_saved_map.js rename to x-pack/plugins/maps/public/embeddable/merge_input_with_saved_map.js index 8e3e0a9168e30e..d91c91b3b223c9 100644 --- a/x-pack/legacy/plugins/maps/public/embeddable/merge_input_with_saved_map.js +++ b/x-pack/plugins/maps/public/embeddable/merge_input_with_saved_map.js @@ -5,8 +5,8 @@ */ import _ from 'lodash'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { DEFAULT_IS_LAYER_TOC_OPEN } from '../../../../../plugins/maps/public/reducers/ui'; + +import { DEFAULT_IS_LAYER_TOC_OPEN } from '../reducers/ui'; const MAP_EMBEDDABLE_INPUT_KEYS = [ 'hideFilterActions', diff --git a/x-pack/legacy/plugins/maps/public/feature_catalogue_entry.ts b/x-pack/plugins/maps/public/feature_catalogue_entry.ts similarity index 89% rename from x-pack/legacy/plugins/maps/public/feature_catalogue_entry.ts rename to x-pack/plugins/maps/public/feature_catalogue_entry.ts index fdda76b4e12127..6c2579bd3e4e2a 100644 --- a/x-pack/legacy/plugins/maps/public/feature_catalogue_entry.ts +++ b/x-pack/plugins/maps/public/feature_catalogue_entry.ts @@ -6,7 +6,7 @@ import { i18n } from '@kbn/i18n'; import { APP_ID, APP_ICON } from '../common/constants'; import { getAppTitle } from '../common/i18n_getters'; -import { FeatureCatalogueCategory } from '../../../../../src/plugins/home/public'; +import { FeatureCatalogueCategory } from '../../../../src/plugins/home/public'; export const featureCatalogueEntry = { id: APP_ID, diff --git a/x-pack/legacy/plugins/maps/public/help_menu_util.js b/x-pack/plugins/maps/public/help_menu_util.js similarity index 81% rename from x-pack/legacy/plugins/maps/public/help_menu_util.js rename to x-pack/plugins/maps/public/help_menu_util.js index 70b9340b562cd1..053caf66883094 100644 --- a/x-pack/legacy/plugins/maps/public/help_menu_util.js +++ b/x-pack/plugins/maps/public/help_menu_util.js @@ -3,8 +3,8 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getDocLinks, getCoreChrome } from '../../../../plugins/maps/public/kibana_services'; + +import { getDocLinks, getCoreChrome } from './kibana_services'; export function addHelpMenuToAppChrome() { const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = getDocLinks(); diff --git a/x-pack/legacy/plugins/maps/public/icon.svg b/x-pack/plugins/maps/public/icon.svg similarity index 100% rename from x-pack/legacy/plugins/maps/public/icon.svg rename to x-pack/plugins/maps/public/icon.svg diff --git a/x-pack/plugins/maps/public/index.scss b/x-pack/plugins/maps/public/index.scss new file mode 100644 index 00000000000000..8b2f6d3cb61563 --- /dev/null +++ b/x-pack/plugins/maps/public/index.scss @@ -0,0 +1,17 @@ +/* GIS plugin styles */ + +// Import the EUI global scope so we can use EUI constants +@import 'src/legacy/ui/public/styles/_styling_constants'; + +// Prefix all styles with "map" to avoid conflicts. +// Examples +// mapChart +// mapChart__legend +// mapChart__legend--small +// mapChart__legend-isLoading + +@import 'main'; +@import 'mapbox_hacks'; +@import 'connected_components/index'; +@import 'components/index'; +@import 'layers/index'; diff --git a/x-pack/plugins/maps/public/kibana_services.js b/x-pack/plugins/maps/public/kibana_services.js index 2a793143803304..dcbd54a09381f1 100644 --- a/x-pack/plugins/maps/public/kibana_services.js +++ b/x-pack/plugins/maps/public/kibana_services.js @@ -38,7 +38,9 @@ export const getFileUploadComponent = () => { }; let getInjectedVar; -export const setInjectedVarFunc = getInjectedVarFunc => (getInjectedVar = getInjectedVarFunc); +export const setInjectedVarFunc = getInjectedVarFunc => { + getInjectedVar = getInjectedVarFunc; +}; export const getInjectedVarFunc = () => getInjectedVar; let uiSettings; diff --git a/x-pack/plugins/maps/public/layers/layer.d.ts b/x-pack/plugins/maps/public/layers/layer.d.ts index 8fb69734d3d069..e8fc5d473626cb 100644 --- a/x-pack/plugins/maps/public/layers/layer.d.ts +++ b/x-pack/plugins/maps/public/layers/layer.d.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { LayerDescriptor, MapExtent, MapFilters } from '../../common/descriptor_types'; +import { LayerDescriptor, MapExtent, MapFilters, MapQuery } from '../../common/descriptor_types'; import { ISource } from './sources/source'; import { DataRequest } from './util/data_request'; import { SyncContext } from '../actions/map_actions'; @@ -17,6 +17,11 @@ export interface ILayer { getSource(): ISource; getSourceForEditing(): ISource; syncData(syncContext: SyncContext): Promise; + isVisible(): boolean; + showAtZoomLevel(zoomLevel: number): boolean; + getMinZoom(): number; + getMaxZoom(): number; + getMinSourceZoom(): number; } export interface ILayerArguments { @@ -35,4 +40,12 @@ export class AbstractLayer implements ILayer { getSource(): ISource; getSourceForEditing(): ISource; syncData(syncContext: SyncContext): Promise; + isVisible(): boolean; + showAtZoomLevel(zoomLevel: number): boolean; + getMinZoom(): number; + getMaxZoom(): number; + getMinSourceZoom(): number; + getQuery(): MapQuery; + _removeStaleMbSourcesAndLayers(mbMap: unknown): void; + _requiresPrevSourceCleanup(mbMap: unknown): boolean; } diff --git a/x-pack/plugins/maps/public/layers/layer.js b/x-pack/plugins/maps/public/layers/layer.js index 26bce872b3c2c2..9362ce2c028e6e 100644 --- a/x-pack/plugins/maps/public/layers/layer.js +++ b/x-pack/plugins/maps/public/layers/layer.js @@ -14,7 +14,7 @@ import { SOURCE_DATA_ID_ORIGIN, } from '../../common/constants'; import uuid from 'uuid/v4'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths + import { copyPersistentState } from '../reducers/util.js'; import { i18n } from '@kbn/i18n'; @@ -141,7 +141,8 @@ export class AbstractLayer { defaultMessage: `Layer is hidden.`, }); } else if (!this.showAtZoomLevel(zoomLevel)) { - const { minZoom, maxZoom } = this.getZoomConfig(); + const minZoom = this.getMinZoom(); + const maxZoom = this.getMaxZoom(); icon = ; tooltipContent = i18n.translate('xpack.maps.layer.zoomFeedbackTooltip', { defaultMessage: `Layer is visible between zoom levels {minZoom} and {maxZoom}.`, @@ -203,7 +204,7 @@ export class AbstractLayer { } showAtZoomLevel(zoom) { - return zoom >= this._descriptor.minZoom && zoom <= this._descriptor.maxZoom; + return zoom >= this.getMinZoom() && zoom <= this.getMaxZoom(); } getMinZoom() { @@ -214,6 +215,30 @@ export class AbstractLayer { return this._descriptor.maxZoom; } + getMinSourceZoom() { + return this._source.getMinZoom(); + } + + _requiresPrevSourceCleanup() { + return false; + } + + _removeStaleMbSourcesAndLayers(mbMap) { + if (this._requiresPrevSourceCleanup(mbMap)) { + const mbStyle = mbMap.getStyle(); + mbStyle.layers.forEach(mbLayer => { + if (this.ownsMbLayerId(mbLayer.id)) { + mbMap.removeLayer(mbLayer.id); + } + }); + Object.keys(mbStyle.sources).some(mbSourceId => { + if (this.ownsMbSourceId(mbSourceId)) { + mbMap.removeSource(mbSourceId); + } + }); + } + } + getAlpha() { return this._descriptor.alpha; } @@ -222,13 +247,6 @@ export class AbstractLayer { return this._descriptor.query; } - getZoomConfig() { - return { - minZoom: this._descriptor.minZoom, - maxZoom: this._descriptor.maxZoom, - }; - } - getCurrentStyle() { return this._style; } diff --git a/x-pack/plugins/maps/public/layers/load_layer_wizards.js b/x-pack/plugins/maps/public/layers/load_layer_wizards.js deleted file mode 100644 index d0169165eaa35f..00000000000000 --- a/x-pack/plugins/maps/public/layers/load_layer_wizards.js +++ /dev/null @@ -1,30 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { registerLayerWizard } from './layer_wizard_registry'; -import { uploadLayerWizardConfig } from './sources/client_file_source'; -import { esDocumentsLayerWizardConfig } from './sources/es_search_source'; -import { clustersLayerWizardConfig, heatmapLayerWizardConfig } from './sources/es_geo_grid_source'; -import { point2PointLayerWizardConfig } from './sources/es_pew_pew_source/es_pew_pew_source'; -import { emsBoundariesLayerWizardConfig } from './sources/ems_file_source'; -import { emsBaseMapLayerWizardConfig } from './sources/ems_tms_source'; -import { kibanaRegionMapLayerWizardConfig } from './sources/kibana_regionmap_source'; -import { kibanaBasemapLayerWizardConfig } from './sources/kibana_tilemap_source'; -import { tmsLayerWizardConfig } from './sources/xyz_tms_source'; -import { wmsLayerWizardConfig } from './sources/wms_source'; - -// Registration order determines display order -registerLayerWizard(uploadLayerWizardConfig); -registerLayerWizard(esDocumentsLayerWizardConfig); -registerLayerWizard(clustersLayerWizardConfig); -registerLayerWizard(heatmapLayerWizardConfig); -registerLayerWizard(point2PointLayerWizardConfig); -registerLayerWizard(emsBoundariesLayerWizardConfig); -registerLayerWizard(emsBaseMapLayerWizardConfig); -registerLayerWizard(kibanaRegionMapLayerWizardConfig); -registerLayerWizard(kibanaBasemapLayerWizardConfig); -registerLayerWizard(tmsLayerWizardConfig); -registerLayerWizard(wmsLayerWizardConfig); diff --git a/x-pack/plugins/maps/public/layers/load_layer_wizards.ts b/x-pack/plugins/maps/public/layers/load_layer_wizards.ts new file mode 100644 index 00000000000000..49d128257fe206 --- /dev/null +++ b/x-pack/plugins/maps/public/layers/load_layer_wizards.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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { registerLayerWizard } from './layer_wizard_registry'; +// @ts-ignore +import { uploadLayerWizardConfig } from './sources/client_file_source'; +// @ts-ignore +import { esDocumentsLayerWizardConfig } from './sources/es_search_source'; +// @ts-ignore +import { clustersLayerWizardConfig, heatmapLayerWizardConfig } from './sources/es_geo_grid_source'; +// @ts-ignore +import { point2PointLayerWizardConfig } from './sources/es_pew_pew_source/es_pew_pew_source'; +// @ts-ignore +import { emsBoundariesLayerWizardConfig } from './sources/ems_file_source'; +// @ts-ignore +import { emsBaseMapLayerWizardConfig } from './sources/ems_tms_source'; +// @ts-ignore +import { kibanaRegionMapLayerWizardConfig } from './sources/kibana_regionmap_source'; +// @ts-ignore +import { kibanaBasemapLayerWizardConfig } from './sources/kibana_tilemap_source'; +import { tmsLayerWizardConfig } from './sources/xyz_tms_source'; +// @ts-ignore +import { wmsLayerWizardConfig } from './sources/wms_source'; +import { mvtVectorSourceWizardConfig } from './sources/mvt_single_layer_vector_source'; +// @ts-ignore +import { getInjectedVarFunc } from '../kibana_services'; + +// Registration order determines display order +let registered = false; +export function registerLayerWizards() { + if (registered) { + return; + } + // @ts-ignore + registerLayerWizard(uploadLayerWizardConfig); + // @ts-ignore + registerLayerWizard(esDocumentsLayerWizardConfig); + // @ts-ignore + registerLayerWizard(clustersLayerWizardConfig); + // @ts-ignore + registerLayerWizard(heatmapLayerWizardConfig); + // @ts-ignore + registerLayerWizard(point2PointLayerWizardConfig); + // @ts-ignore + registerLayerWizard(emsBoundariesLayerWizardConfig); + // @ts-ignore + registerLayerWizard(emsBaseMapLayerWizardConfig); + // @ts-ignore + registerLayerWizard(kibanaRegionMapLayerWizardConfig); + // @ts-ignore + registerLayerWizard(kibanaBasemapLayerWizardConfig); + registerLayerWizard(tmsLayerWizardConfig); + // @ts-ignore + registerLayerWizard(wmsLayerWizardConfig); + + const getInjectedVar = getInjectedVarFunc(); + if (getInjectedVar && getInjectedVar('enableVectorTiles', false)) { + // eslint-disable-next-line no-console + console.warn('Vector tiles are an experimental feature and should not be used in production.'); + registerLayerWizard(mvtVectorSourceWizardConfig); + } + registered = true; +} diff --git a/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.d.ts b/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.d.ts index 3f596cea1ae393..96347c444dd5b2 100644 --- a/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.d.ts +++ b/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.d.ts @@ -23,6 +23,7 @@ export class ESGeoGridSource extends AbstractESAggSource { constructor(sourceDescriptor: ESGeoGridSourceDescriptor, inspectorAdapters: unknown); + getFieldNames(): string[]; getGridResolution(): GRID_RESOLUTION; getGeoGridPrecision(zoom: number): number; } diff --git a/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.d.ts b/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.d.ts index 0a4e48a195ec66..c904280a38c85d 100644 --- a/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.d.ts +++ b/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.d.ts @@ -9,4 +9,5 @@ import { ESSearchSourceDescriptor } from '../../../../common/descriptor_types'; export class ESSearchSource extends AbstractESSource { constructor(sourceDescriptor: Partial, inspectorAdapters: unknown); + getFieldNames(): string[]; } diff --git a/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.js b/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.js index 96679f0e859412..aaa56b30c735a4 100644 --- a/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.js +++ b/x-pack/plugins/maps/public/layers/sources/es_search_source/es_search_source.js @@ -51,7 +51,7 @@ function getDocValueAndSourceFields(indexPattern, fieldNames) { lang: field.lang, }, }; - } else if (field.readFromDocValues) { + } else if (field.type !== ES_GEO_FIELD_TYPE.GEO_SHAPE && field.readFromDocValues) { const docValueField = field.type === 'date' ? { @@ -387,11 +387,21 @@ export class ESSearchSource extends AbstractESSource { }); return properties; }; + const epochMillisFields = searchFilters.fieldNames.filter(fieldName => { + const field = getField(indexPattern, fieldName); + return field.readFromDocValues && field.type === 'date'; + }); let featureCollection; try { const geoField = await this._getGeoField(); - featureCollection = hitsToGeoJson(hits, flattenHit, geoField.name, geoField.type); + featureCollection = hitsToGeoJson( + hits, + flattenHit, + geoField.name, + geoField.type, + epochMillisFields + ); } catch (error) { throw new Error( i18n.translate('xpack.maps.source.esSearch.convertToGeoJsonErrorMsg', { diff --git a/x-pack/plugins/maps/public/layers/sources/es_source/es_source.js b/x-pack/plugins/maps/public/layers/sources/es_source/es_source.js index 3402e367cbd736..9ab87577b77806 100644 --- a/x-pack/plugins/maps/public/layers/sources/es_source/es_source.js +++ b/x-pack/plugins/maps/public/layers/sources/es_source/es_source.js @@ -16,7 +16,7 @@ import { createExtentFilter } from '../../../elasticsearch_geo_utils'; import _ from 'lodash'; import { i18n } from '@kbn/i18n'; import uuid from 'uuid/v4'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths + import { copyPersistentState } from '../../../reducers/util'; import { ES_GEO_FIELD_TYPE } from '../../../../common/constants'; import { DataRequestAbortError } from '../../util/data_request'; diff --git a/x-pack/plugins/snapshot_restore/public/application/lib/authorization/index.ts b/x-pack/plugins/maps/public/layers/sources/mvt_single_layer_vector_source/index.ts similarity index 74% rename from x-pack/plugins/snapshot_restore/public/application/lib/authorization/index.ts rename to x-pack/plugins/maps/public/layers/sources/mvt_single_layer_vector_source/index.ts index 73bbde465146c0..89b7e76a7e359a 100644 --- a/x-pack/plugins/snapshot_restore/public/application/lib/authorization/index.ts +++ b/x-pack/plugins/maps/public/layers/sources/mvt_single_layer_vector_source/index.ts @@ -4,4 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -export * from './components'; +export * from './mvt_single_layer_vector_source'; +export * from './layer_wizard'; diff --git a/x-pack/plugins/maps/public/layers/sources/mvt_single_layer_vector_source/layer_wizard.tsx b/x-pack/plugins/maps/public/layers/sources/mvt_single_layer_vector_source/layer_wizard.tsx new file mode 100644 index 00000000000000..dfdea1489d50c2 --- /dev/null +++ b/x-pack/plugins/maps/public/layers/sources/mvt_single_layer_vector_source/layer_wizard.tsx @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { + MVTSingleLayerVectorSourceEditor, + MVTSingleLayerVectorSourceConfig, +} from './mvt_single_layer_vector_source_editor'; +import { MVTSingleLayerVectorSource, sourceTitle } from './mvt_single_layer_vector_source'; +import { LayerWizard, RenderWizardArguments } from '../../layer_wizard_registry'; +import { SOURCE_TYPES } from '../../../../common/constants'; + +export const mvtVectorSourceWizardConfig: LayerWizard = { + description: i18n.translate('xpack.maps.source.mvtVectorSourceWizard', { + defaultMessage: 'Vector source wizard', + }), + icon: 'grid', + renderWizard: ({ onPreviewSource, inspectorAdapters }: RenderWizardArguments) => { + const onSourceConfigChange = ({ + urlTemplate, + layerName, + minSourceZoom, + maxSourceZoom, + }: MVTSingleLayerVectorSourceConfig) => { + const sourceDescriptor = MVTSingleLayerVectorSource.createDescriptor({ + urlTemplate, + layerName, + minSourceZoom, + maxSourceZoom, + type: SOURCE_TYPES.MVT_SINGLE_LAYER, + }); + const source = new MVTSingleLayerVectorSource(sourceDescriptor, inspectorAdapters); + onPreviewSource(source); + }; + return ; + }, + title: sourceTitle, +}; diff --git a/x-pack/plugins/maps/public/layers/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.ts b/x-pack/plugins/maps/public/layers/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.ts new file mode 100644 index 00000000000000..0bfda6be722034 --- /dev/null +++ b/x-pack/plugins/maps/public/layers/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.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; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import uuid from 'uuid/v4'; +import { AbstractSource, ImmutableSourceProperty } from '../source'; +import { TiledVectorLayer } from '../../tiled_vector_layer'; +import { GeoJsonWithMeta, ITiledSingleLayerVectorSource } from '../vector_source'; +import { MAX_ZOOM, MIN_ZOOM, SOURCE_TYPES } from '../../../../common/constants'; +import { VECTOR_SHAPE_TYPES } from '../vector_feature_types'; +import { IField } from '../../fields/field'; +import { registerSource } from '../source_registry'; +import { getDataSourceLabel, getUrlLabel } from '../../../../common/i18n_getters'; +import { + LayerDescriptor, + MapExtent, + TiledSingleLayerVectorSourceDescriptor, + VectorSourceRequestMeta, + VectorSourceSyncMeta, +} from '../../../../common/descriptor_types'; +import { VectorLayerArguments } from '../../vector_layer'; + +export const sourceTitle = i18n.translate( + 'xpack.maps.source.MVTSingleLayerVectorSource.sourceTitle', + { + defaultMessage: 'Vector Tile Layer', + } +); + +export class MVTSingleLayerVectorSource extends AbstractSource + implements ITiledSingleLayerVectorSource { + static createDescriptor({ + urlTemplate, + layerName, + minSourceZoom, + maxSourceZoom, + }: TiledSingleLayerVectorSourceDescriptor) { + return { + type: SOURCE_TYPES.MVT_SINGLE_LAYER, + id: uuid(), + urlTemplate, + layerName, + minSourceZoom: Math.max(MIN_ZOOM, minSourceZoom), + maxSourceZoom: Math.min(MAX_ZOOM, maxSourceZoom), + }; + } + + readonly _descriptor: TiledSingleLayerVectorSourceDescriptor; + + constructor( + sourceDescriptor: TiledSingleLayerVectorSourceDescriptor, + inspectorAdapters?: object + ) { + super(sourceDescriptor, inspectorAdapters); + this._descriptor = sourceDescriptor; + } + + renderSourceSettingsEditor() { + return null; + } + + getFieldNames(): string[] { + return []; + } + + createDefaultLayer(options: LayerDescriptor): TiledVectorLayer { + const layerDescriptor = { + sourceDescriptor: this._descriptor, + ...options, + }; + const normalizedLayerDescriptor = TiledVectorLayer.createDescriptor(layerDescriptor, []); + const vectorLayerArguments: VectorLayerArguments = { + layerDescriptor: normalizedLayerDescriptor, + source: this, + }; + return new TiledVectorLayer(vectorLayerArguments); + } + + getGeoJsonWithMeta( + layerName: 'string', + searchFilters: unknown[], + registerCancelCallback: (callback: () => void) => void + ): Promise { + // todo: remove this method + // This is a consequence of ITiledSingleLayerVectorSource extending IVectorSource. + throw new Error('Does not implement getGeoJsonWithMeta'); + } + + async getFields(): Promise { + return []; + } + + async getImmutableProperties(): Promise { + return [ + { label: getDataSourceLabel(), value: sourceTitle }, + { label: getUrlLabel(), value: this._descriptor.urlTemplate }, + { + label: i18n.translate('xpack.maps.source.MVTSingleLayerVectorSource.layerNameMessage', { + defaultMessage: 'Layer name', + }), + value: this._descriptor.layerName, + }, + { + label: i18n.translate('xpack.maps.source.MVTSingleLayerVectorSource.minZoomMessage', { + defaultMessage: 'Min zoom', + }), + value: this._descriptor.minSourceZoom.toString(), + }, + { + label: i18n.translate('xpack.maps.source.MVTSingleLayerVectorSource.maxZoomMessage', { + defaultMessage: 'Max zoom', + }), + value: this._descriptor.maxSourceZoom.toString(), + }, + ]; + } + + async getDisplayName(): Promise { + return this._descriptor.layerName; + } + + async getUrlTemplateWithMeta() { + return { + urlTemplate: this._descriptor.urlTemplate, + layerName: this._descriptor.layerName, + minSourceZoom: this._descriptor.minSourceZoom, + maxSourceZoom: this._descriptor.maxSourceZoom, + }; + } + + async getSupportedShapeTypes(): Promise { + return [VECTOR_SHAPE_TYPES.POINT, VECTOR_SHAPE_TYPES.LINE, VECTOR_SHAPE_TYPES.POLYGON]; + } + + canFormatFeatureProperties() { + return false; + } + + getMinZoom() { + return this._descriptor.minSourceZoom; + } + + getMaxZoom() { + return this._descriptor.maxSourceZoom; + } + + getBoundsForFilters(searchFilters: VectorSourceRequestMeta): MapExtent { + return { + maxLat: 90, + maxLon: 180, + minLat: -90, + minLon: -180, + }; + } + + getFieldByName(fieldName: string): IField | null { + return null; + } + + getSyncMeta(): VectorSourceSyncMeta { + return null; + } + + getApplyGlobalQuery(): boolean { + return false; + } +} + +registerSource({ + ConstructorFunction: MVTSingleLayerVectorSource, + type: SOURCE_TYPES.MVT_SINGLE_LAYER, +}); diff --git a/x-pack/plugins/maps/public/layers/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source_editor.tsx b/x-pack/plugins/maps/public/layers/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source_editor.tsx new file mode 100644 index 00000000000000..7a4b8d43811da8 --- /dev/null +++ b/x-pack/plugins/maps/public/layers/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source_editor.tsx @@ -0,0 +1,128 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +/* eslint-disable @typescript-eslint/consistent-type-definitions */ + +import React, { Fragment, Component, ChangeEvent } from 'react'; +import _ from 'lodash'; +import { EuiFieldText, EuiFormRow } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { MAX_ZOOM, MIN_ZOOM } from '../../../../common/constants'; +import { ValidatedDualRange, Value } from '../../../../../../../src/plugins/kibana_react/public'; + +export type MVTSingleLayerVectorSourceConfig = { + urlTemplate: string; + layerName: string; + minSourceZoom: number; + maxSourceZoom: number; +}; + +export interface Props { + onSourceConfigChange: (sourceConfig: MVTSingleLayerVectorSourceConfig) => void; +} + +interface State { + urlTemplate: string; + layerName: string; + minSourceZoom: number; + maxSourceZoom: number; +} + +export class MVTSingleLayerVectorSourceEditor extends Component { + state = { + urlTemplate: '', + layerName: '', + minSourceZoom: MIN_ZOOM, + maxSourceZoom: MAX_ZOOM, + }; + + _sourceConfigChange = _.debounce(() => { + const canPreview = + this.state.urlTemplate.indexOf('{x}') >= 0 && + this.state.urlTemplate.indexOf('{y}') >= 0 && + this.state.urlTemplate.indexOf('{z}') >= 0; + + if (canPreview && this.state.layerName) { + this.props.onSourceConfigChange({ + urlTemplate: this.state.urlTemplate, + layerName: this.state.layerName, + minSourceZoom: this.state.minSourceZoom, + maxSourceZoom: this.state.maxSourceZoom, + }); + } + }, 200); + + _handleUrlTemplateChange = (e: ChangeEvent) => { + const url = e.target.value; + this.setState( + { + urlTemplate: url, + }, + () => this._sourceConfigChange() + ); + }; + + _handleLayerNameInputChange = (e: ChangeEvent) => { + const layerName = e.target.value; + this.setState( + { + layerName, + }, + () => this._sourceConfigChange() + ); + }; + + _handleZoomRangeChange = (e: Value) => { + const minSourceZoom = parseInt(e[0] as string, 10); + const maxSourceZoom = parseInt(e[1] as string, 10); + + if (this.state.minSourceZoom !== minSourceZoom || this.state.maxSourceZoom !== maxSourceZoom) { + this.setState({ minSourceZoom, maxSourceZoom }, () => this._sourceConfigChange()); + } + }; + + render() { + return ( + + + + + + + + + + ); + } +} diff --git a/x-pack/plugins/maps/public/layers/sources/source.d.ts b/x-pack/plugins/maps/public/layers/sources/source.d.ts index a1581b826d9a6a..5a01da02adaae4 100644 --- a/x-pack/plugins/maps/public/layers/sources/source.d.ts +++ b/x-pack/plugins/maps/public/layers/sources/source.d.ts @@ -19,7 +19,7 @@ export type Attribution = { }; export interface ISource { - createDefaultLayer(): ILayer; + createDefaultLayer(options?: LayerDescriptor): ILayer; destroy(): void; getDisplayName(): Promise; getInspectorAdapters(): object; @@ -31,6 +31,8 @@ export interface ISource { isTimeAware(): Promise; getImmutableProperties(): Promise; getAttributions(): Promise; + getMinZoom(): number; + getMaxZoom(): number; } export class AbstractSource implements ISource { @@ -49,4 +51,6 @@ export class AbstractSource implements ISource { isTimeAware(): Promise; getImmutableProperties(): Promise; getAttributions(): Promise; + getMinZoom(): number; + getMaxZoom(): number; } diff --git a/x-pack/plugins/maps/public/layers/sources/source.js b/x-pack/plugins/maps/public/layers/sources/source.js index 3029a5c0912026..fd93daf249b265 100644 --- a/x-pack/plugins/maps/public/layers/sources/source.js +++ b/x-pack/plugins/maps/public/layers/sources/source.js @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -// eslint-disable-next-line @kbn/eslint/no-restricted-paths import { copyPersistentState } from '../../reducers/util'; +import { MIN_ZOOM, MAX_ZOOM } from '../../../common/constants'; export class AbstractSource { static isIndexingSource = false; @@ -79,7 +79,7 @@ export class AbstractSource { return false; } - isQueryAware() { + async isTimeAware() { return false; } @@ -107,6 +107,14 @@ export class AbstractSource { return []; } + isFilterByMapBounds() { + return false; + } + + isQueryAware() { + return false; + } + getGeoGridPrecision() { return 0; } @@ -140,4 +148,12 @@ export class AbstractSource { async getValueSuggestions(/* field, query */) { return []; } + + getMinZoom() { + return MIN_ZOOM; + } + + getMaxZoom() { + return MAX_ZOOM; + } } diff --git a/x-pack/plugins/maps/public/layers/sources/source_registry.ts b/x-pack/plugins/maps/public/layers/sources/source_registry.ts index d16b16af74e9da..3b334d45092ad7 100644 --- a/x-pack/plugins/maps/public/layers/sources/source_registry.ts +++ b/x-pack/plugins/maps/public/layers/sources/source_registry.ts @@ -10,7 +10,7 @@ import { ISource } from './source'; type SourceRegistryEntry = { ConstructorFunction: new ( sourceDescriptor: any, // this is the source-descriptor that corresponds specifically to the particular ISource instance - inspectorAdapters: unknown + inspectorAdapters?: object ) => ISource; type: string; }; diff --git a/x-pack/plugins/maps/public/layers/sources/vector_feature_types.js b/x-pack/plugins/maps/public/layers/sources/vector_feature_types.js deleted file mode 100644 index cc5f30389c4f3a..00000000000000 --- a/x-pack/plugins/maps/public/layers/sources/vector_feature_types.js +++ /dev/null @@ -1,11 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -export const VECTOR_SHAPE_TYPES = { - POINT: 'POINT', - LINE: 'LINE', - POLYGON: 'POLYGON', -}; diff --git a/x-pack/plugins/maps/public/layers/sources/vector_feature_types.ts b/x-pack/plugins/maps/public/layers/sources/vector_feature_types.ts new file mode 100644 index 00000000000000..9f03357e17dad5 --- /dev/null +++ b/x-pack/plugins/maps/public/layers/sources/vector_feature_types.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export enum VECTOR_SHAPE_TYPES { + POINT = 'POINT', + LINE = 'LINE', + POLYGON = 'POLYGON', +} diff --git a/x-pack/plugins/maps/public/layers/sources/vector_source/vector_source.d.ts b/x-pack/plugins/maps/public/layers/sources/vector_source/vector_source.d.ts index 63429830d9f4fb..804915dd73052a 100644 --- a/x-pack/plugins/maps/public/layers/sources/vector_source/vector_source.d.ts +++ b/x-pack/plugins/maps/public/layers/sources/vector_source/vector_source.d.ts @@ -14,6 +14,7 @@ import { VectorSourceRequestMeta, VectorSourceSyncMeta, } from '../../../../common/descriptor_types'; +import { VECTOR_SHAPE_TYPES } from '../vector_feature_types'; export type GeoJsonFetchMeta = ESSearchSourceResponseMeta; @@ -31,8 +32,10 @@ export interface IVectorSource extends ISource { ): Promise; getFields(): Promise; - getFieldByName(fieldName: string): IField; + getFieldByName(fieldName: string): IField | null; getSyncMeta(): VectorSourceSyncMeta; + getFieldNames(): string[]; + getApplyGlobalQuery(): boolean; } export class AbstractVectorSource extends AbstractSource implements IVectorSource { @@ -44,6 +47,21 @@ export class AbstractVectorSource extends AbstractSource implements IVectorSourc ): Promise; getFields(): Promise; - getFieldByName(fieldName: string): IField; + getFieldByName(fieldName: string): IField | null; getSyncMeta(): VectorSourceSyncMeta; + getSupportedShapeTypes(): Promise; + canFormatFeatureProperties(): boolean; + getApplyGlobalQuery(): boolean; + getFieldNames(): string[]; +} + +export interface ITiledSingleLayerVectorSource extends IVectorSource { + getUrlTemplateWithMeta(): Promise<{ + layerName: string; + urlTemplate: string; + minSourceZoom: number; + maxSourceZoom: number; + }>; + getMinZoom(): number; + getMaxZoom(): number; } diff --git a/x-pack/plugins/maps/public/layers/sources/vector_source/vector_source.js b/x-pack/plugins/maps/public/layers/sources/vector_source/vector_source.js index bb37175b48655b..509584cbc415a4 100644 --- a/x-pack/plugins/maps/public/layers/sources/vector_source/vector_source.js +++ b/x-pack/plugins/maps/public/layers/sources/vector_source/vector_source.js @@ -60,6 +60,10 @@ export class AbstractVectorSource extends AbstractSource { throw new Error(`Should implemement ${this.constructor.type} ${this}`); } + getFieldNames() { + return []; + } + /** * Retrieves a field. This may be an existing instance. * @param fieldName diff --git a/x-pack/plugins/maps/public/layers/styles/vector/components/vector_style_editor.js b/x-pack/plugins/maps/public/layers/styles/vector/components/vector_style_editor.js index 6cece5efb3a5d9..c46dc2cb4b73e3 100644 --- a/x-pack/plugins/maps/public/layers/styles/vector/components/vector_style_editor.js +++ b/x-pack/plugins/maps/public/layers/styles/vector/components/vector_style_editor.js @@ -37,7 +37,7 @@ export class VectorStyleEditor extends Component { defaultDynamicProperties: getDefaultDynamicProperties(), defaultStaticProperties: getDefaultStaticProperties(), supportedFeatures: undefined, - selectedFeatureType: undefined, + selectedFeature: null, }; componentWillUnmount() { @@ -91,18 +91,20 @@ export class VectorStyleEditor extends Component { return; } - let selectedFeature = VECTOR_SHAPE_TYPES.POLYGON; - if (this.props.isPointsOnly) { - selectedFeature = VECTOR_SHAPE_TYPES.POINT; - } else if (this.props.isLinesOnly) { - selectedFeature = VECTOR_SHAPE_TYPES.LINE; + if (!_.isEqual(supportedFeatures, this.state.supportedFeatures)) { + this.setState({ supportedFeatures }); } - if ( - !_.isEqual(supportedFeatures, this.state.supportedFeatures) || - selectedFeature !== this.state.selectedFeature - ) { - this.setState({ supportedFeatures, selectedFeature }); + if (this.state.selectedFeature === null) { + let selectedFeature = VECTOR_SHAPE_TYPES.POLYGON; + if (this.props.isPointsOnly) { + selectedFeature = VECTOR_SHAPE_TYPES.POINT; + } else if (this.props.isLinesOnly) { + selectedFeature = VECTOR_SHAPE_TYPES.LINE; + } + this.setState({ + selectedFeature: selectedFeature, + }); } } diff --git a/x-pack/plugins/maps/public/layers/styles/vector/properties/dynamic_style_property.js b/x-pack/plugins/maps/public/layers/styles/vector/properties/dynamic_style_property.js index ea521f8749d80a..8cef78f9a8f210 100644 --- a/x-pack/plugins/maps/public/layers/styles/vector/properties/dynamic_style_property.js +++ b/x-pack/plugins/maps/public/layers/styles/vector/properties/dynamic_style_property.js @@ -279,6 +279,10 @@ export class DynamicStyleProperty extends AbstractStyleProperty { } getNumericalMbFeatureStateValue(value) { + if (typeof value === 'number') { + return value; + } + const valueAsFloat = parseFloat(value); return isNaN(valueAsFloat) ? null : valueAsFloat; } diff --git a/x-pack/plugins/maps/public/layers/styles/vector/vector_style.d.ts b/x-pack/plugins/maps/public/layers/styles/vector/vector_style.d.ts index 77ea44ac26bf92..e010d5ac7d7a31 100644 --- a/x-pack/plugins/maps/public/layers/styles/vector/vector_style.d.ts +++ b/x-pack/plugins/maps/public/layers/styles/vector/vector_style.d.ts @@ -7,17 +7,23 @@ import { IStyleProperty } from './properties/style_property'; import { IDynamicStyleProperty } from './properties/dynamic_style_property'; import { IVectorLayer } from '../../vector_layer'; import { IVectorSource } from '../../sources/vector_source'; -import { VectorStyleDescriptor } from '../../../../common/descriptor_types'; +import { + VectorStyleDescriptor, + VectorStylePropertiesDescriptor, +} from '../../../../common/descriptor_types'; export interface IVectorStyle { getAllStyleProperties(): IStyleProperty[]; getDescriptor(): VectorStyleDescriptor; getDynamicPropertiesArray(): IDynamicStyleProperty[]; + getSourceFieldNames(): string[]; } export class VectorStyle implements IVectorStyle { + static createDescriptor(properties: VectorStylePropertiesDescriptor): VectorStyleDescriptor; + static createDefaultStyleProperties(mapColors: string[]): VectorStylePropertiesDescriptor; constructor(descriptor: VectorStyleDescriptor, source: IVectorSource, layer: IVectorLayer); - + getSourceFieldNames(): string[]; getAllStyleProperties(): IStyleProperty[]; getDescriptor(): VectorStyleDescriptor; getDynamicPropertiesArray(): IDynamicStyleProperty[]; diff --git a/x-pack/plugins/maps/public/layers/tiled_vector_layer.tsx b/x-pack/plugins/maps/public/layers/tiled_vector_layer.tsx new file mode 100644 index 00000000000000..c47cae5641e563 --- /dev/null +++ b/x-pack/plugins/maps/public/layers/tiled_vector_layer.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; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { EuiIcon } from '@elastic/eui'; +import { VectorStyle } from './styles/vector/vector_style'; +import { SOURCE_DATA_ID_ORIGIN, LAYER_TYPE } from '../../common/constants'; +import { VectorLayer, VectorLayerArguments } from './vector_layer'; +import { canSkipSourceUpdate } from './util/can_skip_fetch'; +import { ITiledSingleLayerVectorSource } from './sources/vector_source'; +import { SyncContext } from '../actions/map_actions'; +import { ISource } from './sources/source'; +import { VectorLayerDescriptor, VectorSourceRequestMeta } from '../../common/descriptor_types'; +import { MVTSingleLayerVectorSourceConfig } from './sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source_editor'; + +export class TiledVectorLayer extends VectorLayer { + static type = LAYER_TYPE.TILED_VECTOR; + + static createDescriptor( + descriptor: VectorLayerDescriptor, + mapColors: string[] + ): VectorLayerDescriptor { + const layerDescriptor = super.createDescriptor(descriptor, mapColors); + layerDescriptor.type = TiledVectorLayer.type; + + if (!layerDescriptor.style) { + const styleProperties = VectorStyle.createDefaultStyleProperties(mapColors); + layerDescriptor.style = VectorStyle.createDescriptor(styleProperties); + } + + return layerDescriptor; + } + + readonly _source: ITiledSingleLayerVectorSource; // downcast to the more specific type + + constructor({ layerDescriptor, source }: VectorLayerArguments) { + super({ layerDescriptor, source }); + this._source = source as ITiledSingleLayerVectorSource; + } + + getCustomIconAndTooltipContent() { + return { + icon: , + }; + } + + async _syncMVTUrlTemplate({ startLoading, stopLoading, onLoadError, dataFilters }: SyncContext) { + const requestToken: symbol = Symbol(`layer-${this.getId()}-${SOURCE_DATA_ID_ORIGIN}`); + const searchFilters: VectorSourceRequestMeta = this._getSearchFilters( + dataFilters, + this.getSource(), + this._style + ); + const prevDataRequest = this.getSourceDataRequest(); + + const canSkip = await canSkipSourceUpdate({ + source: this._source as ISource, + prevDataRequest, + nextMeta: searchFilters, + }); + if (canSkip) { + return null; + } + + startLoading(SOURCE_DATA_ID_ORIGIN, requestToken, searchFilters); + try { + const templateWithMeta = await this._source.getUrlTemplateWithMeta(); + stopLoading(SOURCE_DATA_ID_ORIGIN, requestToken, templateWithMeta, {}); + } catch (error) { + onLoadError(SOURCE_DATA_ID_ORIGIN, requestToken, error.message); + } + } + + async syncData(syncContext: SyncContext) { + if (!this.isVisible() || !this.showAtZoomLevel(syncContext.dataFilters.zoom)) { + return; + } + + await this._syncSourceStyleMeta(syncContext, this._source, this._style); + await this._syncSourceFormatters(syncContext, this._source, this._style); + await this._syncMVTUrlTemplate(syncContext); + } + + _syncSourceBindingWithMb(mbMap: unknown) { + // @ts-ignore + const mbSource = mbMap.getSource(this.getId()); + if (!mbSource) { + const sourceDataRequest = this.getSourceDataRequest(); + if (!sourceDataRequest) { + // this is possible if the layer was invisible at startup. + // the actions will not perform any data=syncing as an optimization when a layer is invisible + // when turning the layer back into visible, it's possible the url has not been resovled yet. + return; + } + + const sourceMeta: MVTSingleLayerVectorSourceConfig | null = sourceDataRequest.getData() as MVTSingleLayerVectorSourceConfig; + if (!sourceMeta) { + return; + } + + const sourceId = this.getId(); + + // @ts-ignore + mbMap.addSource(sourceId, { + type: 'vector', + tiles: [sourceMeta.urlTemplate], + minzoom: sourceMeta.minSourceZoom, + maxzoom: sourceMeta.maxSourceZoom, + }); + } + } + + _syncStylePropertiesWithMb(mbMap: unknown) { + // @ts-ignore + const mbSource = mbMap.getSource(this.getId()); + if (!mbSource) { + return; + } + + const sourceDataRequest = this.getSourceDataRequest(); + if (!sourceDataRequest) { + return; + } + const sourceMeta: MVTSingleLayerVectorSourceConfig = sourceDataRequest.getData() as MVTSingleLayerVectorSourceConfig; + + this._setMbPointsProperties(mbMap, sourceMeta.layerName); + this._setMbLinePolygonProperties(mbMap, sourceMeta.layerName); + } + + _requiresPrevSourceCleanup(mbMap: unknown): boolean { + // @ts-ignore + const mbTileSource = mbMap.getSource(this.getId()); + if (!mbTileSource) { + return false; + } + const dataRequest = this.getSourceDataRequest(); + if (!dataRequest) { + return false; + } + const tiledSourceMeta: MVTSingleLayerVectorSourceConfig | null = dataRequest.getData() as MVTSingleLayerVectorSourceConfig; + if ( + mbTileSource.tiles[0] === tiledSourceMeta.urlTemplate && + mbTileSource.minzoom === tiledSourceMeta.minSourceZoom && + mbTileSource.maxzoom === tiledSourceMeta.maxSourceZoom + ) { + // TileURL and zoom-range captures all the state. If this does not change, no updates are required. + return false; + } + + return true; + } + + syncLayerWithMB(mbMap: unknown) { + this._removeStaleMbSourcesAndLayers(mbMap); + this._syncSourceBindingWithMb(mbMap); + this._syncStylePropertiesWithMb(mbMap); + } + + getJoins() { + return []; + } + + getMinZoom() { + // higher resolution vector tiles cannot be displayed at lower-res + return Math.max(this._source.getMinZoom(), super.getMinZoom()); + } +} diff --git a/x-pack/plugins/maps/public/layers/vector_layer.d.ts b/x-pack/plugins/maps/public/layers/vector_layer.d.ts index 88b1a1ce8535e3..3d5b8054ff3fd8 100644 --- a/x-pack/plugins/maps/public/layers/vector_layer.d.ts +++ b/x-pack/plugins/maps/public/layers/vector_layer.d.ts @@ -9,6 +9,7 @@ import { AbstractLayer } from './layer'; import { IVectorSource } from './sources/vector_source'; import { MapFilters, + LayerDescriptor, VectorLayerDescriptor, VectorSourceRequestMeta, } from '../../common/descriptor_types'; @@ -20,7 +21,7 @@ import { SyncContext } from '../actions/map_actions'; type VectorLayerArguments = { source: IVectorSource; - joins: IJoin[]; + joins?: IJoin[]; layerDescriptor: VectorLayerDescriptor; }; @@ -28,11 +29,12 @@ export interface IVectorLayer extends ILayer { getFields(): Promise; getStyleEditorFields(): Promise; getValidJoins(): IJoin[]; + getSource(): IVectorSource; } export class VectorLayer extends AbstractLayer implements IVectorLayer { static createDescriptor( - options: Partial, + options: Partial, mapColors?: string[] ): VectorLayerDescriptor; @@ -40,14 +42,30 @@ export class VectorLayer extends AbstractLayer implements IVectorLayer { protected readonly _style: IVectorStyle; constructor(options: VectorLayerArguments); - + getLayerTypeIconName(): string; getFields(): Promise; getStyleEditorFields(): Promise; getValidJoins(): IJoin[]; + _syncSourceStyleMeta( + syncContext: SyncContext, + source: IVectorSource, + style: IVectorStyle + ): Promise; + _syncSourceFormatters( + syncContext: SyncContext, + source: IVectorSource, + style: IVectorStyle + ): Promise; + syncLayerWithMB(mbMap: unknown): void; _getSearchFilters( dataFilters: MapFilters, source: IVectorSource, style: IVectorStyle ): VectorSourceRequestMeta; _syncData(syncContext: SyncContext, source: IVectorSource, style: IVectorStyle): Promise; + ownsMbSourceId(sourceId: string): boolean; + ownsMbLayerId(sourceId: string): boolean; + _setMbPointsProperties(mbMap: unknown, mvtSourceLayer?: string): void; + _setMbLinePolygonProperties(mbMap: unknown, mvtSourceLayer?: string): void; + getSource(): IVectorSource; } diff --git a/x-pack/plugins/maps/public/layers/vector_layer.js b/x-pack/plugins/maps/public/layers/vector_layer.js index d606420909281a..c5947a63587ea8 100644 --- a/x-pack/plugins/maps/public/layers/vector_layer.js +++ b/x-pack/plugins/maps/public/layers/vector_layer.js @@ -641,7 +641,7 @@ export class VectorLayer extends AbstractLayer { } } - _setMbPointsProperties(mbMap) { + _setMbPointsProperties(mbMap, mvtSourceLayer) { const pointLayerId = this._getMbPointLayerId(); const symbolLayerId = this._getMbSymbolLayerId(); const pointLayer = mbMap.getLayer(pointLayerId); @@ -658,7 +658,7 @@ export class VectorLayer extends AbstractLayer { if (symbolLayer) { mbMap.setLayoutProperty(symbolLayerId, 'visibility', 'none'); } - this._setMbCircleProperties(mbMap); + this._setMbCircleProperties(mbMap, mvtSourceLayer); } else { markerLayerId = symbolLayerId; textLayerId = symbolLayerId; @@ -666,7 +666,7 @@ export class VectorLayer extends AbstractLayer { mbMap.setLayoutProperty(pointLayerId, 'visibility', 'none'); mbMap.setLayoutProperty(this._getMbTextLayerId(), 'visibility', 'none'); } - this._setMbSymbolProperties(mbMap); + this._setMbSymbolProperties(mbMap, mvtSourceLayer); } this.syncVisibilityWithMb(mbMap, markerLayerId); @@ -677,27 +677,36 @@ export class VectorLayer extends AbstractLayer { } } - _setMbCircleProperties(mbMap) { + _setMbCircleProperties(mbMap, mvtSourceLayer) { const sourceId = this.getId(); const pointLayerId = this._getMbPointLayerId(); const pointLayer = mbMap.getLayer(pointLayerId); if (!pointLayer) { - mbMap.addLayer({ + const mbLayer = { id: pointLayerId, type: 'circle', source: sourceId, paint: {}, - }); + }; + + if (mvtSourceLayer) { + mbLayer['source-layer'] = mvtSourceLayer; + } + mbMap.addLayer(mbLayer); } const textLayerId = this._getMbTextLayerId(); const textLayer = mbMap.getLayer(textLayerId); if (!textLayer) { - mbMap.addLayer({ + const mbLayer = { id: textLayerId, type: 'symbol', source: sourceId, - }); + }; + if (mvtSourceLayer) { + mbLayer['source-layer'] = mvtSourceLayer; + } + mbMap.addLayer(mbLayer); } const filterExpr = getPointFilterExpression(this._hasJoins()); @@ -719,17 +728,21 @@ export class VectorLayer extends AbstractLayer { }); } - _setMbSymbolProperties(mbMap) { + _setMbSymbolProperties(mbMap, mvtSourceLayer) { const sourceId = this.getId(); const symbolLayerId = this._getMbSymbolLayerId(); const symbolLayer = mbMap.getLayer(symbolLayerId); if (!symbolLayer) { - mbMap.addLayer({ + const mbLayer = { id: symbolLayerId, type: 'symbol', source: sourceId, - }); + }; + if (mvtSourceLayer) { + mbLayer['source-layer'] = mvtSourceLayer; + } + mbMap.addLayer(mbLayer); } const filterExpr = getPointFilterExpression(this._hasJoins()); @@ -750,26 +763,34 @@ export class VectorLayer extends AbstractLayer { }); } - _setMbLinePolygonProperties(mbMap) { + _setMbLinePolygonProperties(mbMap, mvtSourceLayer) { const sourceId = this.getId(); const fillLayerId = this._getMbPolygonLayerId(); const lineLayerId = this._getMbLineLayerId(); const hasJoins = this._hasJoins(); if (!mbMap.getLayer(fillLayerId)) { - mbMap.addLayer({ + const mbLayer = { id: fillLayerId, type: 'fill', source: sourceId, paint: {}, - }); + }; + if (mvtSourceLayer) { + mbLayer['source-layer'] = mvtSourceLayer; + } + mbMap.addLayer(mbLayer); } if (!mbMap.getLayer(lineLayerId)) { - mbMap.addLayer({ + const mbLayer = { id: lineLayerId, type: 'line', source: sourceId, paint: {}, - }); + }; + if (mvtSourceLayer) { + mbLayer['source-layer'] = mvtSourceLayer; + } + mbMap.addLayer(mbLayer); } this.getCurrentStyle().setMBPaintProperties({ alpha: this.getAlpha(), diff --git a/x-pack/plugins/maps/public/layers/vector_tile_layer.js b/x-pack/plugins/maps/public/layers/vector_tile_layer.js index 44987fd3e78f02..c620ec6c56dc3a 100644 --- a/x-pack/plugins/maps/public/layers/vector_tile_layer.js +++ b/x-pack/plugins/maps/public/layers/vector_tile_layer.js @@ -161,19 +161,7 @@ export class VectorTileLayer extends TileLayer { return; } - if (this._requiresPrevSourceCleanup(mbMap)) { - const mbStyle = mbMap.getStyle(); - mbStyle.layers.forEach(mbLayer => { - if (this.ownsMbLayerId(mbLayer.id)) { - mbMap.removeLayer(mbLayer.id); - } - }); - Object.keys(mbStyle.sources).some(mbSourceId => { - if (this.ownsMbSourceId(mbSourceId)) { - mbMap.removeSource(mbSourceId); - } - }); - } + this._removeStaleMbSourcesAndLayers(mbMap); let initialBootstrapCompleted = false; const sourceIds = Object.keys(vectorStyle.sources); diff --git a/x-pack/plugins/maps/public/maps_vis_type_alias.js b/x-pack/plugins/maps/public/maps_vis_type_alias.js new file mode 100644 index 00000000000000..85613f4608c6f4 --- /dev/null +++ b/x-pack/plugins/maps/public/maps_vis_type_alias.js @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import { APP_ID, APP_ICON, MAP_BASE_URL } from '../common/constants'; +import { getInjectedVarFunc, getVisualizations } from './kibana_services'; + +export function getMapsVisTypeAlias() { + const showMapVisualizationTypes = getInjectedVarFunc()('showMapVisualizationTypes', false); + if (!showMapVisualizationTypes) { + getVisualizations().hideTypes(['region_map', 'tile_map']); + } + + const description = i18n.translate('xpack.maps.visTypeAlias.description', { + defaultMessage: 'Create and style maps with multiple layers and indices.', + }); + + const legacyMapVisualizationWarning = i18n.translate( + 'xpack.maps.visTypeAlias.legacyMapVizWarning', + { + defaultMessage: `Use the Maps app instead of Coordinate Map and Region Map. +The Maps app offers more functionality and is easier to use.`, + } + ); + + return { + aliasUrl: MAP_BASE_URL, + name: APP_ID, + title: i18n.translate('xpack.maps.visTypeAlias.title', { + defaultMessage: 'Maps', + }), + description: showMapVisualizationTypes + ? `${description} ${legacyMapVisualizationWarning}` + : description, + icon: APP_ICON, + stage: 'production', + }; +} diff --git a/x-pack/plugins/maps/public/plugin.ts b/x-pack/plugins/maps/public/plugin.ts index 649627690ec9a6..863d439ab7f1d9 100644 --- a/x-pack/plugins/maps/public/plugin.ts +++ b/x-pack/plugins/maps/public/plugin.ts @@ -33,9 +33,17 @@ import { setVisualizations, // @ts-ignore } from './kibana_services'; +import { featureCatalogueEntry } from './feature_catalogue_entry'; +// @ts-ignore +import { getMapsVisTypeAlias } from './maps_vis_type_alias'; +import { HomePublicPluginSetup } from '../../../../src/plugins/home/public'; +import { VisualizationsSetup } from '../../../../src/plugins/visualizations/public'; +import { registerLayerWizards } from './layers/load_layer_wizards'; export interface MapsPluginSetupDependencies { inspector: InspectorSetupContract; + home: HomePublicPluginSetup; + visualizations: VisualizationsSetup; } // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface MapsPluginStartDependencies {} @@ -72,6 +80,7 @@ export const bindStartCoreAndPlugins = (core: CoreStart, plugins: any) => { setUiActions(plugins.uiActions); setNavigation(plugins.navigation); setCoreI18n(core.i18n); + registerLayerWizards(); }; /** @@ -92,8 +101,15 @@ export class MapsPlugin MapsPluginStartDependencies > { public setup(core: CoreSetup, plugins: MapsPluginSetupDependencies) { - plugins.inspector.registerView(MapView); + const { inspector, home, visualizations } = plugins; + bindSetupCoreAndPlugins(core, plugins); + + inspector.registerView(MapView); + home.featureCatalogue.register(featureCatalogueEntry); + visualizations.registerAlias(getMapsVisTypeAlias()); } - public start(core: CoreStart, plugins: any) {} + public start(core: CoreStart, plugins: any) { + bindStartCoreAndPlugins(core, plugins); + } } diff --git a/x-pack/plugins/maps/public/reducers/ui.ts b/x-pack/plugins/maps/public/reducers/ui.ts index 7429545ec0e46e..f577618c74ffef 100644 --- a/x-pack/plugins/maps/public/reducers/ui.ts +++ b/x-pack/plugins/maps/public/reducers/ui.ts @@ -16,7 +16,6 @@ import { SHOW_TOC_DETAILS, HIDE_TOC_DETAILS, UPDATE_INDEXING_STAGE, - // @ts-ignore } from '../actions/ui_actions'; export enum FLYOUT_STATE { diff --git a/x-pack/legacy/plugins/maps/public/selectors/map_selectors.d.ts b/x-pack/plugins/maps/public/selectors/map_selectors.d.ts similarity index 81% rename from x-pack/legacy/plugins/maps/public/selectors/map_selectors.d.ts rename to x-pack/plugins/maps/public/selectors/map_selectors.d.ts index 8c99e0adcc14fe..32579d036590e3 100644 --- a/x-pack/legacy/plugins/maps/public/selectors/map_selectors.d.ts +++ b/x-pack/plugins/maps/public/selectors/map_selectors.d.ts @@ -6,8 +6,8 @@ import { AnyAction } from 'redux'; import { MapCenter } from '../../common/descriptor_types'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { MapStoreState } from '../../../../../plugins/maps/public/reducers/store'; + +import { MapStoreState } from '../reducers/store'; export function getHiddenLayerIds(state: MapStoreState): string[]; diff --git a/x-pack/legacy/plugins/maps/public/selectors/map_selectors.js b/x-pack/plugins/maps/public/selectors/map_selectors.js similarity index 83% rename from x-pack/legacy/plugins/maps/public/selectors/map_selectors.js rename to x-pack/plugins/maps/public/selectors/map_selectors.js index f350a2c9447563..56e07f542782a3 100644 --- a/x-pack/legacy/plugins/maps/public/selectors/map_selectors.js +++ b/x-pack/plugins/maps/public/selectors/map_selectors.js @@ -6,29 +6,17 @@ import { createSelector } from 'reselect'; import _ from 'lodash'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { TileLayer } from '../../../../../plugins/maps/public/layers/tile_layer'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { VectorTileLayer } from '../../../../../plugins/maps/public/layers/vector_tile_layer'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { VectorLayer } from '../../../../../plugins/maps/public/layers/vector_layer'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { HeatmapLayer } from '../../../../../plugins/maps/public/layers/heatmap_layer'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { BlendedVectorLayer } from '../../../../../plugins/maps/public/layers/blended_vector_layer'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getTimeFilter } from '../../../../../plugins/maps/public/kibana_services'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getInspectorAdapters } from '../../../../../plugins/maps/public/reducers/non_serializable_instances'; -import { - copyPersistentState, - TRACKED_LAYER_DESCRIPTOR, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../../plugins/maps/public/reducers/util'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { InnerJoin } from '../../../../../plugins/maps/public/layers/joins/inner_join'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getSourceByType } from '../../../../../plugins/maps/public/layers/sources/source_registry'; +import { TileLayer } from '../layers/tile_layer'; +import { VectorTileLayer } from '../layers/vector_tile_layer'; +import { VectorLayer } from '../layers/vector_layer'; +import { HeatmapLayer } from '../layers/heatmap_layer'; +import { BlendedVectorLayer } from '../layers/blended_vector_layer'; +import { getTimeFilter } from '../kibana_services'; +import { TiledVectorLayer } from '../layers/tiled_vector_layer'; +import { getInspectorAdapters } from '../reducers/non_serializable_instances'; +import { copyPersistentState, TRACKED_LAYER_DESCRIPTOR } from '../reducers/util'; +import { InnerJoin } from '../layers/joins/inner_join'; +import { getSourceByType } from '../layers/sources/source_registry'; function createLayerInstance(layerDescriptor, inspectorAdapters) { const source = createSourceInstance(layerDescriptor.sourceDescriptor, inspectorAdapters); @@ -51,6 +39,8 @@ function createLayerInstance(layerDescriptor, inspectorAdapters) { return new HeatmapLayer({ layerDescriptor, source }); case BlendedVectorLayer.type: return new BlendedVectorLayer({ layerDescriptor, source }); + case TiledVectorLayer.type: + return new TiledVectorLayer({ layerDescriptor, source }); default: throw new Error(`Unrecognized layerType ${layerDescriptor.type}`); } diff --git a/x-pack/legacy/plugins/maps/public/selectors/map_selectors.test.js b/x-pack/plugins/maps/public/selectors/map_selectors.test.js similarity index 66% rename from x-pack/legacy/plugins/maps/public/selectors/map_selectors.test.js rename to x-pack/plugins/maps/public/selectors/map_selectors.test.js index b83be301653b80..fec16251914ead 100644 --- a/x-pack/legacy/plugins/maps/public/selectors/map_selectors.test.js +++ b/x-pack/plugins/maps/public/selectors/map_selectors.test.js @@ -4,17 +4,18 @@ * you may not use this file except in compliance with the Elastic License. */ -jest.mock('../../../../../plugins/maps/public/layers/vector_layer', () => {}); -jest.mock('../../../../../plugins/maps/public/layers/blended_vector_layer', () => {}); -jest.mock('../../../../../plugins/maps/public/layers/heatmap_layer', () => {}); -jest.mock('../../../../../plugins/maps/public/layers/vector_tile_layer', () => {}); -jest.mock('../../../../../plugins/maps/public/layers/joins/inner_join', () => {}); -jest.mock('../../../../../plugins/maps/public/reducers/non_serializable_instances', () => ({ +jest.mock('../layers/vector_layer', () => {}); +jest.mock('../layers/tiled_vector_layer', () => {}); +jest.mock('../layers/blended_vector_layer', () => {}); +jest.mock('../layers/heatmap_layer', () => {}); +jest.mock('../layers/vector_tile_layer', () => {}); +jest.mock('../layers/joins/inner_join', () => {}); +jest.mock('../reducers/non_serializable_instances', () => ({ getInspectorAdapters: () => { return {}; }, })); -jest.mock('../../../../../plugins/maps/public/kibana_services', () => ({ +jest.mock('../kibana_services', () => ({ getTimeFilter: () => ({ getTime: () => { return { diff --git a/x-pack/legacy/plugins/maps/public/selectors/ui_selectors.ts b/x-pack/plugins/maps/public/selectors/ui_selectors.ts similarity index 74% rename from x-pack/legacy/plugins/maps/public/selectors/ui_selectors.ts rename to x-pack/plugins/maps/public/selectors/ui_selectors.ts index fdf2a8ea0e4f37..32d4beeb381d7f 100644 --- a/x-pack/legacy/plugins/maps/public/selectors/ui_selectors.ts +++ b/x-pack/plugins/maps/public/selectors/ui_selectors.ts @@ -4,10 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { MapStoreState } from '../../../../../plugins/maps/public/reducers/store'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { FLYOUT_STATE, INDEXING_STAGE } from '../../../../../plugins/maps/public/reducers/ui'; +import { MapStoreState } from '../reducers/store'; + +import { FLYOUT_STATE, INDEXING_STAGE } from '../reducers/ui'; export const getFlyoutDisplay = ({ ui }: MapStoreState): FLYOUT_STATE => ui.flyoutDisplay; export const getIsSetViewOpen = ({ ui }: MapStoreState): boolean => ui.isSetViewOpen; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/common/analytics.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/common/analytics.ts index 3c959b827bb1c7..fb3b2b35199477 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/common/analytics.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/common/analytics.ts @@ -52,7 +52,7 @@ export interface ClassificationAnalysis { classification: Classification; } -export interface LoadRegressionExploreDataArg { +export interface LoadExploreDataArg { filterByIsTraining?: boolean; searchQuery: SavedSearchQuery; } @@ -409,11 +409,11 @@ export function getEvalQueryBody({ ignoreDefaultQuery, }: { resultsField: string; - isTraining: boolean; + isTraining?: boolean; searchQuery?: ResultsSearchQuery; ignoreDefaultQuery?: boolean; }) { - let query; + let query: any; const trainingQuery: ResultsSearchQuery = { term: { [`${resultsField}.is_training`]: { value: isTraining } }, @@ -426,19 +426,25 @@ export function getEvalQueryBody({ searchQueryClone.bool.must = []; } - searchQueryClone.bool.must.push(trainingQuery); + if (isTraining !== undefined) { + searchQueryClone.bool.must.push(trainingQuery); + } + query = searchQueryClone; } else if (isQueryStringQuery(searchQueryClone)) { query = { bool: { - must: [searchQueryClone, trainingQuery], + must: [searchQueryClone], }, }; + if (isTraining !== undefined) { + query.bool.must.push(trainingQuery); + } } else { // Not a bool or string query so we need to create it so can add the trainingQuery query = { bool: { - must: [trainingQuery], + must: isTraining !== undefined ? [trainingQuery] : [], }, }; } @@ -456,7 +462,7 @@ interface EvaluateMetrics { } interface LoadEvalDataConfig { - isTraining: boolean; + isTraining?: boolean; index: string; dependentVariable: string; resultsField: string; @@ -535,7 +541,7 @@ interface TrackTotalHitsSearchResponse { interface LoadDocsCountConfig { ignoreDefaultQuery?: boolean; - isTraining: boolean; + isTraining?: boolean; searchQuery: SavedSearchQuery; resultsField: string; destIndex: string; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/classification_exploration_data_grid.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/classification_exploration_data_grid.tsx new file mode 100644 index 00000000000000..424fc002795caa --- /dev/null +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/classification_exploration_data_grid.tsx @@ -0,0 +1,135 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { Dispatch, FC, SetStateAction, useCallback, useMemo } from 'react'; + +import { i18n } from '@kbn/i18n'; + +import { EuiDataGrid, EuiDataGridPaginationProps, EuiDataGridSorting } from '@elastic/eui'; + +import { euiDataGridStyle, euiDataGridToolbarSettings } from '../../../../common'; + +import { mlFieldFormatService } from '../../../../../services/field_format_service'; + +import { IndexPattern } from '../../../../../../../../../../src/plugins/data/public'; + +const PAGE_SIZE_OPTIONS = [5, 10, 25, 50]; + +type Pagination = Pick; +type TableItem = Record; + +interface ExplorationDataGridProps { + colorRange?: (d: number) => string; + columns: any[]; + indexPattern: IndexPattern; + pagination: Pagination; + resultsField: string; + rowCount: number; + selectedFields: string[]; + setPagination: Dispatch>; + setSelectedFields: Dispatch>; + setSortingColumns: Dispatch>; + sortingColumns: EuiDataGridSorting['columns']; + tableItems: TableItem[]; +} + +export const ClassificationExplorationDataGrid: FC = ({ + columns, + indexPattern, + pagination, + resultsField, + rowCount, + selectedFields, + setPagination, + setSelectedFields, + setSortingColumns, + sortingColumns, + tableItems, +}) => { + const renderCellValue = useMemo(() => { + return ({ rowIndex, columnId }: { rowIndex: number; columnId: string; setCellProps: any }) => { + const adjustedRowIndex = rowIndex - pagination.pageIndex * pagination.pageSize; + + const fullItem = tableItems[adjustedRowIndex]; + + if (fullItem === undefined) { + return null; + } + + let format: any; + + if (indexPattern !== undefined) { + format = mlFieldFormatService.getFieldFormatFromIndexPattern(indexPattern, columnId, ''); + } + + const cellValue = + fullItem.hasOwnProperty(columnId) && fullItem[columnId] !== undefined + ? fullItem[columnId] + : null; + + if (format !== undefined) { + return format.convert(cellValue, 'text'); + } + + if (typeof cellValue === 'string' || cellValue === null) { + return cellValue; + } + + if (typeof cellValue === 'boolean') { + return cellValue ? 'true' : 'false'; + } + + if (typeof cellValue === 'object' && cellValue !== null) { + return JSON.stringify(cellValue); + } + + return cellValue; + }; + }, [resultsField, rowCount, tableItems, pagination.pageIndex, pagination.pageSize]); + + const onChangeItemsPerPage = useCallback( + pageSize => { + setPagination(p => { + const pageIndex = Math.floor((p.pageSize * p.pageIndex) / pageSize); + return { pageIndex, pageSize }; + }); + }, + [setPagination] + ); + + const onChangePage = useCallback(pageIndex => setPagination(p => ({ ...p, pageIndex })), [ + setPagination, + ]); + + const onSort = useCallback(sc => setSortingColumns(sc), [setSortingColumns]); + + return ( + + ); +}; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_panel.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_panel.tsx index 91dae49ba5c497..af90547606f82d 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_panel.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/evaluate_panel.tsx @@ -117,13 +117,7 @@ export const EvaluatePanel: FC = ({ jobConfig, jobStatus, searchQuery }) const resultsField = jobConfig.dest.results_field; let requiresKeyword = false; - const loadData = async ({ - isTrainingClause, - ignoreDefaultQuery = true, - }: { - isTrainingClause: { query: string; operator: string }; - ignoreDefaultQuery?: boolean; - }) => { + const loadData = async ({ isTraining }: { isTraining: boolean | undefined }) => { setIsLoading(true); try { @@ -134,19 +128,18 @@ export const EvaluatePanel: FC = ({ jobConfig, jobStatus, searchQuery }) } const evalData = await loadEvalData({ - isTraining: false, + isTraining, index, dependentVariable, resultsField, predictionFieldName, searchQuery, - ignoreDefaultQuery, jobType: ANALYSIS_CONFIG_TYPE.CLASSIFICATION, requiresKeyword, }); const docsCountResp = await loadDocsCount({ - isTraining: false, + isTraining, searchQuery, resultsField, destIndex: jobConfig.dest.index, @@ -225,29 +218,46 @@ export const EvaluatePanel: FC = ({ jobConfig, jobStatus, searchQuery }) }, [confusionMatrixData]); useEffect(() => { - const hasIsTrainingClause = - isResultsSearchBoolQuery(searchQuery) && - searchQuery.bool.must.filter( - (clause: any) => clause.match && clause.match[`${resultsField}.is_training`] !== undefined - ); - const isTrainingClause = - hasIsTrainingClause && - hasIsTrainingClause[0] && - hasIsTrainingClause[0].match[`${resultsField}.is_training`]; + let isTraining: boolean | undefined; + const query = + isResultsSearchBoolQuery(searchQuery) && (searchQuery.bool.should || searchQuery.bool.filter); - const noTrainingQuery = isTrainingClause === false || isTrainingClause === undefined; + if (query !== undefined && query !== false) { + for (let i = 0; i < query.length; i++) { + const clause = query[i]; - if (noTrainingQuery) { + if (clause.match && clause.match[`${resultsField}.is_training`] !== undefined) { + isTraining = clause.match[`${resultsField}.is_training`]; + break; + } else if ( + clause.bool && + (clause.bool.should !== undefined || clause.bool.filter !== undefined) + ) { + const innerQuery = clause.bool.should || clause.bool.filter; + if (innerQuery !== undefined) { + for (let j = 0; j < innerQuery.length; j++) { + const innerClause = innerQuery[j]; + if ( + innerClause.match && + innerClause.match[`${resultsField}.is_training`] !== undefined + ) { + isTraining = innerClause.match[`${resultsField}.is_training`]; + break; + } + } + } + } + } + } + if (isTraining === undefined) { setDataSubsetTitle(SUBSET_TITLE.ENTIRE); } else { setDataSubsetTitle( - isTrainingClause && isTrainingClause.query === 'true' - ? SUBSET_TITLE.TRAINING - : SUBSET_TITLE.TESTING + isTraining && isTraining === true ? SUBSET_TITLE.TRAINING : SUBSET_TITLE.TESTING ); } - loadData({ isTrainingClause }); + loadData({ isTraining }); }, [JSON.stringify(searchQuery)]); const renderCellValue = ({ diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/results_table.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/results_table.tsx index 9758dd969b443f..bf63dfe68fe9e5 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/results_table.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/results_table.tsx @@ -4,71 +4,39 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment, FC, useEffect, useState } from 'react'; -import moment from 'moment-timezone'; - +import React, { Fragment, FC, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import { - EuiBadge, - EuiButtonIcon, EuiCallOut, - EuiCheckbox, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiPanel, - EuiPopover, - EuiPopoverTitle, EuiProgress, EuiSpacer, EuiText, - EuiToolTip, - Query, } from '@elastic/eui'; -import { Query as QueryType } from '../../../analytics_management/components/analytics_list/common'; -import { ES_FIELD_TYPES } from '../../../../../../../../../../src/plugins/data/public'; -import { mlFieldFormatService } from '../../../../../services/field_format_service'; import { IndexPattern } from '../../../../../../../../../../src/plugins/data/public'; - -import { - ColumnType, - mlInMemoryTableBasicFactory, - OnTableChangeArg, - SortingPropType, - SORT_DIRECTION, -} from '../../../../../components/ml_in_memory_table'; - -import { formatHumanReadableDateTimeSeconds } from '../../../../../util/date_utils'; -import { Field } from '../../../../../../../common/types/fields'; -import { SavedSearchQuery } from '../../../../../contexts/ml'; import { BASIC_NUMERICAL_TYPES, EXTENDED_NUMERICAL_TYPES, - isKeywordAndTextType, sortRegressionResultsFields, } from '../../../../common/fields'; import { - toggleSelectedField, - EsDoc, DataFrameAnalyticsConfig, - EsFieldName, MAX_COLUMNS, - getPredictedFieldName, INDEX_STATUS, SEARCH_SIZE, defaultSearchQuery, - getDependentVar, } from '../../../../common'; import { getTaskStateBadge } from '../../../analytics_management/components/analytics_list/columns'; import { DATA_FRAME_TASK_STATE } from '../../../analytics_management/components/analytics_list/common'; -import { useExploreData, TableItem } from './use_explore_data'; +import { useExploreData } from './use_explore_data'; // TableItem import { ExplorationTitle } from './classification_exploration'; - -const PAGE_SIZE_OPTIONS = [5, 10, 25, 50]; - -const MlInMemoryTableBasic = mlInMemoryTableBasicFactory(); +import { ClassificationExplorationDataGrid } from './classification_exploration_data_grid'; +import { ExplorationQueryBar } from '../exploration_query_bar'; const showingDocs = i18n.translate( 'xpack.ml.dataframe.analytics.classificationExploration.documentsShownHelpText', @@ -94,307 +62,65 @@ interface Props { export const ResultsTable: FC = React.memo( ({ indexPattern, jobConfig, jobStatus, setEvaluateSearchQuery }) => { - const [pageIndex, setPageIndex] = useState(0); - const [pageSize, setPageSize] = useState(25); - const [selectedFields, setSelectedFields] = useState([] as Field[]); - const [docFields, setDocFields] = useState([] as Field[]); - const [depVarType, setDepVarType] = useState(undefined); - const [isColumnsPopoverVisible, setColumnsPopoverVisible] = useState(false); - const [searchQuery, setSearchQuery] = useState(defaultSearchQuery); - const [searchError, setSearchError] = useState(undefined); - const [searchString, setSearchString] = useState(undefined); - - const predictedFieldName = getPredictedFieldName( - jobConfig.dest.results_field, - jobConfig.analysis - ); - - const dependentVariable = getDependentVar(jobConfig.analysis); - - function toggleColumnsPopover() { - setColumnsPopoverVisible(!isColumnsPopoverVisible); - } - - function closeColumnsPopover() { - setColumnsPopoverVisible(false); - } - - function toggleColumn(column: EsFieldName) { - if (tableItems.length > 0 && jobConfig !== undefined) { - // spread to a new array otherwise the component wouldn't re-render - setSelectedFields([ - ...toggleSelectedField(selectedFields, column, jobConfig.dest.results_field, depVarType), - ]); - } - } - const needsDestIndexFields = indexPattern && indexPattern.title === jobConfig.source.index[0]; - + const resultsField = jobConfig.dest.results_field; const { errorMessage, - loadExploreData, - sortField, - sortDirection, - status, - tableItems, - } = useExploreData( - jobConfig, - needsDestIndexFields, + fieldTypes, + pagination, + searchQuery, selectedFields, + rowCount, + setPagination, + setSearchQuery, setSelectedFields, - setDocFields, - setDepVarType - ); + setSortingColumns, + sortingColumns, + status, + tableFields, + tableItems, + } = useExploreData(jobConfig, needsDestIndexFields); - const columns: Array> = selectedFields - .sort(({ name: a }, { name: b }) => sortRegressionResultsFields(a, b, jobConfig)) - .map(field => { - const { type } = field; - let format: any; + useEffect(() => { + setEvaluateSearchQuery(searchQuery); + }, [JSON.stringify(searchQuery)]); - if (indexPattern !== undefined) { - format = mlFieldFormatService.getFieldFormatFromIndexPattern(indexPattern, field.id, ''); - } + const columns = tableFields + .sort((a: any, b: any) => sortRegressionResultsFields(a, b, jobConfig)) + .map((field: any) => { + // Built-in values are ['boolean', 'currency', 'datetime', 'numeric', 'json'] + // To fall back to the default string schema it needs to be undefined. + let schema; + let isSortable = true; + const type = fieldTypes[field]; const isNumber = type !== undefined && (BASIC_NUMERICAL_TYPES.has(type) || EXTENDED_NUMERICAL_TYPES.has(type)); - const column: ColumnType = { - field: field.name, - name: field.name, - sortable: true, - truncateText: true, - }; - - const render = (d: any, fullItem: EsDoc) => { - if (format !== undefined) { - d = format.convert(d, 'text'); - return d; - } - - if (Array.isArray(d) && d.every(item => typeof item === 'string')) { - // If the cells data is an array of strings, return as a comma separated list. - // The list will get limited to 5 items with `…` at the end if there's more in the original array. - return `${d.slice(0, 5).join(', ')}${d.length > 5 ? ', …' : ''}`; - } else if (Array.isArray(d)) { - // If the cells data is an array of e.g. objects, display a 'array' badge with a - // tooltip that explains that this type of field is not supported in this table. - return ( - - - {i18n.translate( - 'xpack.ml.dataframe.analytics.classificationExploration.indexArrayBadgeContent', - { - defaultMessage: 'array', - } - )} - - - ); - } - - return d; - }; - if (isNumber) { - column.dataType = 'number'; - column.render = render; - } else if (typeof type !== 'undefined') { - switch (type) { - case ES_FIELD_TYPES.BOOLEAN: - column.dataType = ES_FIELD_TYPES.BOOLEAN; - column.render = d => (d ? 'true' : 'false'); - break; - case ES_FIELD_TYPES.DATE: - column.align = 'right'; - if (format !== undefined) { - column.render = render; - } else { - column.render = (d: any) => { - if (d !== undefined) { - return formatHumanReadableDateTimeSeconds(moment(d).unix() * 1000); - } - return d; - }; - } - break; - default: - column.render = render; - break; - } - } else { - column.render = render; + schema = 'numeric'; } - return column; - }); - - const docFieldsCount = docFields.length; - - useEffect(() => { - if ( - jobConfig !== undefined && - columns.length > 0 && - selectedFields.length > 0 && - sortField !== undefined && - sortDirection !== undefined && - selectedFields.some(field => field.name === sortField) - ) { - let field = sortField; - // If sorting by predictedField use dependentVar type - if (predictedFieldName === sortField) { - field = dependentVariable; + switch (type) { + case 'date': + schema = 'datetime'; + break; + case 'geo_point': + schema = 'json'; + break; + case 'boolean': + schema = 'boolean'; + break; } - const requiresKeyword = isKeywordAndTextType(field); - - loadExploreData({ - field: sortField, - direction: sortDirection, - searchQuery, - requiresKeyword, - }); - } - }, [JSON.stringify(searchQuery)]); - - useEffect(() => { - // By default set sorting to descending on the prediction field (`_prediction`). - // if that's not available sort ascending on the first column. Check if the current sorting field is still available. - if ( - jobConfig !== undefined && - columns.length > 0 && - selectedFields.length > 0 && - !selectedFields.some(field => field.name === sortField) - ) { - const predictedFieldSelected = selectedFields.some( - field => field.name === predictedFieldName - ); - - // CHECK IF keyword suffix is needed (if predicted field is selected we have to check the dependent variable type) - let sortByField = predictedFieldSelected ? dependentVariable : selectedFields[0].name; - - const requiresKeyword = isKeywordAndTextType(sortByField); - - sortByField = predictedFieldSelected ? predictedFieldName : sortByField; - - const direction = predictedFieldSelected ? SORT_DIRECTION.DESC : SORT_DIRECTION.ASC; - loadExploreData({ field: sortByField, direction, searchQuery, requiresKeyword }); - } - }, [ - jobConfig, - columns.length, - selectedFields.length, - sortField, - sortDirection, - tableItems.length, - ]); - - let sorting: SortingPropType = false; - let onTableChange; - - if (columns.length > 0 && sortField !== '' && sortField !== undefined) { - sorting = { - sort: { - field: sortField, - direction: sortDirection, - }, - }; - - onTableChange = ({ - page = { index: 0, size: 10 }, - sort = { field: sortField, direction: sortDirection }, - }: OnTableChangeArg) => { - const { index, size } = page; - setPageIndex(index); - setPageSize(size); - if (sort.field !== sortField || sort.direction !== sortDirection) { - let field = sort.field; - // If sorting by predictedField use depVar for type check - if (predictedFieldName === sort.field) { - field = dependentVariable; - } - - loadExploreData({ - ...sort, - searchQuery, - requiresKeyword: isKeywordAndTextType(field), - }); + if (field === `${resultsField}.feature_importance`) { + isSortable = false; } - }; - } - const pagination = { - initialPageIndex: pageIndex, - initialPageSize: pageSize, - totalItemCount: tableItems.length, - pageSizeOptions: PAGE_SIZE_OPTIONS, - hidePerPageOptions: false, - }; - - const onQueryChange = ({ query, error }: { query: QueryType; error: any }) => { - if (error) { - setSearchError(error.message); - } else { - try { - const esQueryDsl = Query.toESQuery(query); - setSearchQuery(esQueryDsl); - setSearchString(query.text); - setSearchError(undefined); - // set query for use in evaluate panel - setEvaluateSearchQuery(esQueryDsl); - } catch (e) { - setSearchError(e.toString()); - } - } - }; + return { id: field, schema, isSortable }; + }); - const search = { - onChange: onQueryChange, - defaultQuery: searchString, - box: { - incremental: false, - placeholder: i18n.translate( - 'xpack.ml.dataframe.analytics.regressionExploration.searchBoxPlaceholder', - { - defaultMessage: 'E.g. avg>0.5', - } - ), - }, - filters: [ - { - type: 'field_value_toggle_group', - field: `${jobConfig.dest.results_field}.is_training`, - items: [ - { - value: false, - name: i18n.translate( - 'xpack.ml.dataframe.analytics.regressionExploration.isTestingLabel', - { - defaultMessage: 'Testing', - } - ), - }, - { - value: true, - name: i18n.translate( - 'xpack.ml.dataframe.analytics.regressionExploration.isTrainingLabel', - { - defaultMessage: 'Training', - } - ), - }, - ], - }, - ], - }; + const docFieldsCount = tableFields.length; if (jobConfig === undefined) { return null; @@ -426,11 +152,6 @@ export const ResultsTable: FC = React.memo( ); } - const tableError = - status === INDEX_STATUS.ERROR && errorMessage.includes('parsing_exception') - ? errorMessage - : searchError; - return ( = React.memo( {docFieldsCount > MAX_COLUMNS && ( {i18n.translate( - 'xpack.ml.dataframe.analytics.regressionExploration.fieldSelection', + 'xpack.ml.dataframe.analytics.classificationExploration.fieldSelection', { defaultMessage: '{selectedFieldsLength, number} of {docFieldsCount, number} {docFieldsCount, plural, one {field} other {fields}} selected', @@ -466,52 +187,6 @@ export const ResultsTable: FC = React.memo( )}
- - - - } - isOpen={isColumnsPopoverVisible} - closePopover={closeColumnsPopover} - ownFocus - > - - {i18n.translate( - 'xpack.ml.dataframe.analytics.regressionExploration.selectFieldsPopoverTitle', - { - defaultMessage: 'Select fields', - } - )} - -
- {docFields.map(({ name }) => ( - field.name === name)} - onChange={() => toggleColumn(name)} - disabled={ - selectedFields.some(field => field.name === name) && - selectedFields.length === 1 - } - /> - ))} -
-
-
-
@@ -520,28 +195,39 @@ export const ResultsTable: FC = React.memo( )} {(columns.length > 0 || searchQuery !== defaultSearchQuery) && ( - - - - - - - + + + + + + + + + + + + + + + + )} ); diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/use_explore_data.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/use_explore_data.ts index 9527a9adb98ced..c8809ca5e471bd 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/use_explore_data.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/use_explore_data.ts @@ -3,113 +3,158 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -import React, { useEffect, useState } from 'react'; +import { useEffect, useState, Dispatch, SetStateAction } from 'react'; +import { EuiDataGridPaginationProps, EuiDataGridSorting } from '@elastic/eui'; import { SearchResponse } from 'elasticsearch'; import { cloneDeep } from 'lodash'; -import { SortDirection, SORT_DIRECTION } from '../../../../../components/ml_in_memory_table'; +import { SORT_DIRECTION } from '../../../../../components/ml_in_memory_table'; import { ml } from '../../../../../services/ml_api_service'; import { getNestedProperty } from '../../../../../util/object_utils'; import { newJobCapsService } from '../../../../../services/new_job_capabilities_service'; -import { Field } from '../../../../../../../common/types/fields'; +import { isKeywordAndTextType } from '../../../../common/fields'; +import { Dictionary } from '../../../../../../../common/types/common'; import { ES_FIELD_TYPES } from '../../../../../../../../../../src/plugins/data/public'; import { defaultSearchQuery, ResultsSearchQuery, isResultsSearchBoolQuery, + LoadExploreDataArg, } from '../../../../common/analytics'; import { getDefaultFieldsFromJobCaps, + getDependentVar, getFlattenedFields, + getPredictedFieldName, DataFrameAnalyticsConfig, EsFieldName, INDEX_STATUS, - SEARCH_SIZE, - SearchQuery, } from '../../../../common'; import { SavedSearchQuery } from '../../../../../contexts/ml'; -interface LoadClassificationExploreDataArg { - direction: SortDirection; - filterByIsTraining?: boolean; - field: string; - searchQuery: SavedSearchQuery; - requiresKeyword?: boolean; - pageIndex?: number; - pageSize?: number; -} - export type TableItem = Record; +type Pagination = Pick; export interface UseExploreDataReturnType { errorMessage: string; - loadExploreData: (arg: LoadClassificationExploreDataArg) => void; - sortField: EsFieldName; - sortDirection: SortDirection; + fieldTypes: { [key: string]: ES_FIELD_TYPES }; + pagination: Pagination; + rowCount: number; + searchQuery: SavedSearchQuery; + selectedFields: EsFieldName[]; + setFilterByIsTraining: Dispatch>; + setPagination: Dispatch>; + setSearchQuery: Dispatch>; + setSelectedFields: Dispatch>; + setSortingColumns: Dispatch>; + sortingColumns: EuiDataGridSorting['columns']; status: INDEX_STATUS; + tableFields: string[]; tableItems: TableItem[]; } +type EsSorting = Dictionary<{ + order: 'asc' | 'desc'; +}>; + +// The types specified in `@types/elasticsearch` are out of date and still have `total: number`. +interface SearchResponse7 extends SearchResponse { + hits: SearchResponse['hits'] & { + total: { + value: number; + relation: string; + }; + }; +} + export const useExploreData = ( - jobConfig: DataFrameAnalyticsConfig | undefined, - needsDestIndexFields: boolean, - selectedFields: Field[], - setSelectedFields: React.Dispatch>, - setDocFields: React.Dispatch>, - setDepVarType: React.Dispatch> + jobConfig: DataFrameAnalyticsConfig, + needsDestIndexFields: boolean ): UseExploreDataReturnType => { const [errorMessage, setErrorMessage] = useState(''); const [status, setStatus] = useState(INDEX_STATUS.UNUSED); + + const [selectedFields, setSelectedFields] = useState([] as EsFieldName[]); + const [tableFields, setTableFields] = useState([]); const [tableItems, setTableItems] = useState([]); - const [sortField, setSortField] = useState(''); - const [sortDirection, setSortDirection] = useState(SORT_DIRECTION.ASC); + const [fieldTypes, setFieldTypes] = useState<{ [key: string]: ES_FIELD_TYPES }>({}); + const [rowCount, setRowCount] = useState(0); + + const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 25 }); + const [searchQuery, setSearchQuery] = useState(defaultSearchQuery); + const [filterByIsTraining, setFilterByIsTraining] = useState(undefined); + const [sortingColumns, setSortingColumns] = useState([]); + + const predictedFieldName = getPredictedFieldName( + jobConfig.dest.results_field, + jobConfig.analysis + ); + const dependentVariable = getDependentVar(jobConfig.analysis); const getDefaultSelectedFields = () => { const { fields } = newJobCapsService; - if (selectedFields.length === 0 && jobConfig !== undefined) { - const { - selectedFields: defaultSelected, - docFields, - depVarType, - } = getDefaultFieldsFromJobCaps(fields, jobConfig, needsDestIndexFields); - - setDepVarType(depVarType); - setSelectedFields(defaultSelected); - setDocFields(docFields); + const { selectedFields: defaultSelected, docFields } = getDefaultFieldsFromJobCaps( + fields, + jobConfig, + needsDestIndexFields + ); + + const types: { [key: string]: ES_FIELD_TYPES } = {}; + const allFields: string[] = []; + + docFields.forEach(field => { + types[field.id] = field.type; + allFields.push(field.id); + }); + + setFieldTypes(types); + setSelectedFields(defaultSelected.map(field => field.id)); + setTableFields(allFields); } }; const loadExploreData = async ({ - field, - direction, - searchQuery, - requiresKeyword, - }: LoadClassificationExploreDataArg) => { + filterByIsTraining: isTraining, + searchQuery: incomingQuery, + }: LoadExploreDataArg) => { if (jobConfig !== undefined) { setErrorMessage(''); setStatus(INDEX_STATUS.LOADING); try { const resultsField = jobConfig.dest.results_field; - const searchQueryClone: ResultsSearchQuery = cloneDeep(searchQuery); + const searchQueryClone: ResultsSearchQuery = cloneDeep(incomingQuery); let query: ResultsSearchQuery; + const { pageIndex, pageSize } = pagination; + // If filterByIsTraining is defined - add that in to the final query + const trainingQuery = + isTraining !== undefined + ? { + term: { [`${resultsField}.is_training`]: { value: isTraining } }, + } + : undefined; - if (JSON.stringify(searchQuery) === JSON.stringify(defaultSearchQuery)) { - query = { + if (JSON.stringify(incomingQuery) === JSON.stringify(defaultSearchQuery)) { + const existsQuery = { exists: { field: resultsField, }, }; + + query = { + bool: { + must: [existsQuery], + }, + }; + + if (trainingQuery !== undefined && isResultsSearchBoolQuery(query)) { + query.bool.must.push(trainingQuery); + } } else if (isResultsSearchBoolQuery(searchQueryClone)) { if (searchQueryClone.bool.must === undefined) { searchQueryClone.bool.must = []; @@ -121,33 +166,37 @@ export const useExploreData = ( }, }); + if (trainingQuery !== undefined) { + searchQueryClone.bool.must.push(trainingQuery); + } + query = searchQueryClone; } else { query = searchQueryClone; } - const body: SearchQuery = { - query, - }; - - if (field !== undefined) { - body.sort = [ - { - [`${field}${requiresKeyword ? '.keyword' : ''}`]: { - order: direction, - }, - }, - ]; - } + const sort: EsSorting = sortingColumns + .map(column => { + const { id } = column; + column.id = isKeywordAndTextType(id) ? `${id}.keyword` : id; + return column; + }) + .reduce((s, column) => { + s[column.id] = { order: column.direction }; + return s; + }, {} as EsSorting); - const resp: SearchResponse = await ml.esSearch({ + const resp: SearchResponse7 = await ml.esSearch({ index: jobConfig.dest.index, - size: SEARCH_SIZE, - body, + body: { + query, + from: pageIndex * pageSize, + size: pageSize, + ...(Object.keys(sort).length > 0 ? { sort } : {}), + }, }); - setSortField(field); - setSortDirection(direction); + setRowCount(resp.hits.total.value); const docs = resp.hits.hits; @@ -199,10 +248,45 @@ export const useExploreData = ( }; useEffect(() => { - if (jobConfig !== undefined) { - getDefaultSelectedFields(); - } + getDefaultSelectedFields(); + }, [jobConfig && jobConfig.id]); + + // By default set sorting to descending on the prediction field (`_prediction`). + useEffect(() => { + const sortByField = isKeywordAndTextType(dependentVariable) + ? `${predictedFieldName}.keyword` + : predictedFieldName; + const direction = SORT_DIRECTION.DESC; + + setSortingColumns([{ id: sortByField, direction }]); }, [jobConfig && jobConfig.id]); - return { errorMessage, loadExploreData, sortField, sortDirection, status, tableItems }; + useEffect(() => { + loadExploreData({ filterByIsTraining, searchQuery }); + }, [ + filterByIsTraining, + jobConfig && jobConfig.id, + pagination, + searchQuery, + selectedFields, + sortingColumns, + ]); + + return { + errorMessage, + fieldTypes, + pagination, + searchQuery, + selectedFields, + rowCount, + setFilterByIsTraining, + setPagination, + setSelectedFields, + setSortingColumns, + setSearchQuery, + sortingColumns, + status, + tableItems, + tableFields, + }; }; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/use_explore_data.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/use_explore_data.ts index c68fe5b2cbee86..978aafd10de11f 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/use_explore_data.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/regression_exploration/use_explore_data.ts @@ -29,7 +29,7 @@ import { Dictionary } from '../../../../../../../common/types/common'; import { isKeywordAndTextType } from '../../../../common/fields'; import { ES_FIELD_TYPES } from '../../../../../../../../../../src/plugins/data/public'; import { - LoadRegressionExploreDataArg, + LoadExploreDataArg, defaultSearchQuery, ResultsSearchQuery, isResultsSearchBoolQuery, @@ -120,7 +120,7 @@ export const useExploreData = ( const loadExploreData = async ({ filterByIsTraining: isTraining, searchQuery: incomingQuery, - }: LoadRegressionExploreDataArg) => { + }: LoadExploreDataArg) => { if (jobConfig !== undefined) { setErrorMessage(''); setStatus(INDEX_STATUS.LOADING); diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js index 5e505757dd2aa3..42742f6efcb2a5 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js @@ -150,7 +150,7 @@ function getTimeseriesexplorerDefaultState() { }; } -const containerPadding = 24; +const containerPadding = 34; export class TimeSeriesExplorer extends React.Component { static propTypes = { diff --git a/x-pack/plugins/monitoring/server/telemetry_collection/get_all_stats.test.ts b/x-pack/plugins/monitoring/server/telemetry_collection/get_all_stats.test.ts index 1a9f2a4da32c20..f0ad6399c6c72d 100644 --- a/x-pack/plugins/monitoring/server/telemetry_collection/get_all_stats.test.ts +++ b/x-pack/plugins/monitoring/server/telemetry_collection/get_all_stats.test.ts @@ -182,7 +182,6 @@ describe('get_all_stats', () => { }, { logger: coreMock.createPluginInitializerContext().logger.get('test'), - isDev: true, version: 'version', maxBucketSize: 1, } @@ -208,7 +207,6 @@ describe('get_all_stats', () => { }, { logger: coreMock.createPluginInitializerContext().logger.get('test'), - isDev: true, version: 'version', maxBucketSize: 1, } diff --git a/x-pack/legacy/plugins/logstash/common/lib/index.js b/x-pack/plugins/reporting/common/types.d.ts old mode 100755 new mode 100644 similarity index 83% rename from x-pack/legacy/plugins/logstash/common/lib/index.js rename to x-pack/plugins/reporting/common/types.d.ts index 6ed1d24a377916..34f0bc9ac8a366 --- a/x-pack/legacy/plugins/logstash/common/lib/index.js +++ b/x-pack/plugins/reporting/common/types.d.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { getMoment } from './get_moment'; +export { ConfigType } from '../server/config'; diff --git a/x-pack/plugins/reporting/constants.ts b/x-pack/plugins/reporting/constants.ts index 5756d29face12a..8079c5b1d98875 100644 --- a/x-pack/plugins/reporting/constants.ts +++ b/x-pack/plugins/reporting/constants.ts @@ -7,13 +7,6 @@ export const JOB_COMPLETION_NOTIFICATIONS_SESSION_KEY = 'xpack.reporting.jobCompletionNotifications'; -export const JOB_COMPLETION_NOTIFICATIONS_POLLER_CONFIG = { - jobCompletionNotifier: { - interval: 10000, - intervalErrorMultiplier: 5, - }, -}; - // Routes export const API_BASE_URL = '/api/reporting'; export const API_LIST_URL = `${API_BASE_URL}/jobs`; diff --git a/x-pack/plugins/reporting/index.d.ts b/x-pack/plugins/reporting/index.d.ts index 26d661e29bd946..77faf837e65058 100644 --- a/x-pack/plugins/reporting/index.d.ts +++ b/x-pack/plugins/reporting/index.d.ts @@ -4,15 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - CoreSetup, - CoreStart, - HttpSetup, - Plugin, - PluginInitializerContext, - NotificationsStart, -} from '../../../src/core/public'; - export type JobId = string; export type JobStatus = | 'completed' @@ -21,9 +12,6 @@ export type JobStatus = | 'processing' | 'failed'; -export type HttpService = HttpSetup; -export type NotificationsService = NotificationsStart; - export interface SourceJob { _id: JobId; _source: { diff --git a/x-pack/plugins/reporting/public/components/report_listing.test.tsx b/x-pack/plugins/reporting/public/components/report_listing.test.tsx index 380a3b3295b9f1..787279e6caf9b1 100644 --- a/x-pack/plugins/reporting/public/components/report_listing.test.tsx +++ b/x-pack/plugins/reporting/public/components/report_listing.test.tsx @@ -47,12 +47,24 @@ const toasts = { addDanger: jest.fn(), } as any; +const mockPollConfig = { + jobCompletionNotifier: { + interval: 5000, + intervalErrorMultiplier: 3, + }, + jobsRefresh: { + interval: 5000, + intervalErrorMultiplier: 3, + }, +}; + describe('ReportListing', () => { it('Report job listing with some items', () => { const wrapper = mountWithIntl( @@ -74,6 +86,7 @@ describe('ReportListing', () => { } + pollConfig={mockPollConfig} redirect={jest.fn()} toasts={toasts} /> diff --git a/x-pack/plugins/reporting/public/components/report_listing.tsx b/x-pack/plugins/reporting/public/components/report_listing.tsx index d8ed050fec6c63..f85c479c28e3a7 100644 --- a/x-pack/plugins/reporting/public/components/report_listing.tsx +++ b/x-pack/plugins/reporting/public/components/report_listing.tsx @@ -16,14 +16,15 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react'; import { get } from 'lodash'; import moment from 'moment'; -import { Component, Fragment, default as React } from 'react'; +import { Component, default as React, Fragment } from 'react'; import { Subscription } from 'rxjs'; import { ApplicationStart, ToastsSetup } from 'src/core/public'; import { ILicense, LicensingPluginSetup } from '../../../licensing/public'; import { Poller } from '../../common/poller'; -import { JobStatuses, JOB_COMPLETION_NOTIFICATIONS_POLLER_CONFIG } from '../../constants'; +import { JobStatuses } from '../../constants'; import { checkLicense } from '../lib/license_check'; import { JobQueueEntry, ReportingAPIClient } from '../lib/reporting_api_client'; +import { ClientConfigType } from '../plugin'; import { ReportDeleteButton, ReportDownloadButton, @@ -53,6 +54,7 @@ export interface Props { intl: InjectedIntl; apiClient: ReportingAPIClient; license$: LicensingPluginSetup['license$']; + pollConfig: ClientConfigType['poll']; redirect: ApplicationStart['navigateToApp']; toasts: ToastsSetup; } @@ -167,12 +169,10 @@ class ReportListingUi extends Component { functionToPoll: () => { return this.fetchJobs(); }, - pollFrequencyInMillis: - JOB_COMPLETION_NOTIFICATIONS_POLLER_CONFIG.jobCompletionNotifier.interval, + pollFrequencyInMillis: this.props.pollConfig.jobsRefresh.interval, trailing: false, continuePollingOnError: true, - pollFrequencyErrorMultiplier: - JOB_COMPLETION_NOTIFICATIONS_POLLER_CONFIG.jobCompletionNotifier.intervalErrorMultiplier, + pollFrequencyErrorMultiplier: this.props.pollConfig.jobsRefresh.intervalErrorMultiplier, }); this.poller.start(); this.licenseSubscription = this.props.license$.subscribe(this.licenseHandler); diff --git a/x-pack/plugins/reporting/public/lib/stream_handler.ts b/x-pack/plugins/reporting/public/lib/stream_handler.ts index 3c121f1712685b..eed6d5dd141e70 100644 --- a/x-pack/plugins/reporting/public/lib/stream_handler.ts +++ b/x-pack/plugins/reporting/public/lib/stream_handler.ts @@ -4,30 +4,23 @@ * you may not use this file except in compliance with the Elastic License. */ +import { i18n } from '@kbn/i18n'; import * as Rx from 'rxjs'; import { catchError, map } from 'rxjs/operators'; -import { i18n } from '@kbn/i18n'; +import { NotificationsSetup } from 'src/core/public'; import { JOB_COMPLETION_NOTIFICATIONS_SESSION_KEY, JOB_STATUS_COMPLETED, JOB_STATUS_FAILED, JOB_STATUS_WARNINGS, } from '../../constants'; - -import { - JobId, - JobSummary, - JobStatusBuckets, - NotificationsService, - SourceJob, -} from '../../index.d'; - +import { JobId, JobStatusBuckets, JobSummary, SourceJob } from '../../index.d'; import { - getSuccessToast, getFailureToast, + getGeneralErrorToast, + getSuccessToast, getWarningFormulasToast, getWarningMaxSizeToast, - getGeneralErrorToast, } from '../components'; import { ReportingAPIClient } from './reporting_api_client'; @@ -47,7 +40,7 @@ function summarizeJob(src: SourceJob): JobSummary { } export class ReportingNotifierStreamHandler { - constructor(private notifications: NotificationsService, private apiClient: ReportingAPIClient) {} + constructor(private notifications: NotificationsSetup, private apiClient: ReportingAPIClient) {} /* * Use Kibana Toast API to show our messages diff --git a/x-pack/plugins/reporting/public/plugin.tsx b/x-pack/plugins/reporting/public/plugin.tsx index 08ba10ff692078..c40e7ad373eafa 100644 --- a/x-pack/plugins/reporting/public/plugin.tsx +++ b/x-pack/plugins/reporting/public/plugin.tsx @@ -4,44 +4,42 @@ * you may not use this file except in compliance with the Elastic License. */ -import * as Rx from 'rxjs'; +import { i18n } from '@kbn/i18n'; +import { I18nProvider } from '@kbn/i18n/react'; import React from 'react'; import ReactDOM from 'react-dom'; +import * as Rx from 'rxjs'; import { catchError, filter, map, mergeMap, takeUntil } from 'rxjs/operators'; -import { i18n } from '@kbn/i18n'; +import { + CoreSetup, + CoreStart, + NotificationsSetup, + Plugin, + PluginInitializerContext, +} from 'src/core/public'; import { ManagementSetup } from 'src/plugins/management/public'; -import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from 'src/core/public'; -import { I18nProvider } from '@kbn/i18n/react'; import { UiActionsSetup } from 'src/plugins/ui_actions/public'; - -import { ReportListing } from './components/report_listing'; -import { getGeneralErrorToast } from './components'; - -import { ReportingNotifierStreamHandler as StreamHandler } from './lib/stream_handler'; -import { ReportingAPIClient } from './lib/reporting_api_client'; -import { GetCsvReportPanelAction } from './panel_actions/get_csv_panel_action'; -import { csvReportingProvider } from './share_context_menu/register_csv_reporting'; -import { reportingPDFPNGProvider } from './share_context_menu/register_pdf_png_reporting'; - -import { LicensingPluginSetup } from '../../licensing/public'; +import { JobId, JobStatusBuckets } from '../'; import { CONTEXT_MENU_TRIGGER } from '../../../../src/plugins/embeddable/public'; -import { SharePluginSetup } from '../../../../src/plugins/share/public'; - import { FeatureCatalogueCategory, HomePublicPluginSetup, } from '../../../../src/plugins/home/public'; +import { SharePluginSetup } from '../../../../src/plugins/share/public'; +import { LicensingPluginSetup } from '../../licensing/public'; +import { ConfigType } from '../common/types'; +import { JOB_COMPLETION_NOTIFICATIONS_SESSION_KEY } from '../constants'; +import { getGeneralErrorToast } from './components'; +import { ReportListing } from './components/report_listing'; +import { ReportingAPIClient } from './lib/reporting_api_client'; +import { ReportingNotifierStreamHandler as StreamHandler } from './lib/stream_handler'; +import { GetCsvReportPanelAction } from './panel_actions/get_csv_panel_action'; +import { csvReportingProvider } from './share_context_menu/register_csv_reporting'; +import { reportingPDFPNGProvider } from './share_context_menu/register_pdf_png_reporting'; -import { - JOB_COMPLETION_NOTIFICATIONS_POLLER_CONFIG, - JOB_COMPLETION_NOTIFICATIONS_SESSION_KEY, -} from '../constants'; - -import { JobId, JobStatusBuckets, NotificationsService } from '..'; - -const { - jobCompletionNotifier: { interval: JOBS_REFRESH_INTERVAL }, -} = JOB_COMPLETION_NOTIFICATIONS_POLLER_CONFIG; +export interface ClientConfigType { + poll: ConfigType['poll']; +} function getStored(): JobId[] { const sessionValue = sessionStorage.getItem(JOB_COMPLETION_NOTIFICATIONS_SESSION_KEY); @@ -49,7 +47,7 @@ function getStored(): JobId[] { } function handleError( - notifications: NotificationsService, + notifications: NotificationsSetup, err: Error ): Rx.Observable { notifications.toasts.addDanger( @@ -64,18 +62,19 @@ function handleError( return Rx.of({ completed: [], failed: [] }); } -export class ReportingPublicPlugin implements Plugin { +export class ReportingPublicPlugin implements Plugin { + private config: ClientConfigType; private readonly stop$ = new Rx.ReplaySubject(1); - private readonly title = i18n.translate('xpack.reporting.management.reportingTitle', { defaultMessage: 'Reporting', }); - private readonly breadcrumbText = i18n.translate('xpack.reporting.breadcrumb', { defaultMessage: 'Reporting', }); - constructor(initializerContext: PluginInitializerContext) {} + constructor(initializerContext: PluginInitializerContext) { + this.config = initializerContext.config.get(); + } public setup( core: CoreSetup, @@ -130,6 +129,7 @@ export class ReportingPublicPlugin implements Plugin { @@ -163,8 +163,9 @@ export class ReportingPublicPlugin implements Plugin { const { http, notifications } = core; const apiClient = new ReportingAPIClient(http); const streamHandler = new StreamHandler(notifications, apiClient); + const { interval } = this.config.poll.jobsRefresh; - Rx.timer(0, JOBS_REFRESH_INTERVAL) + Rx.timer(0, interval) .pipe( takeUntil(this.stop$), // stop the interval when stop method is called map(() => getStored()), // read all pending job IDs from session storage diff --git a/x-pack/plugins/reporting/server/config/index.ts b/x-pack/plugins/reporting/server/config/index.ts index f0a0a093aa8c08..a0d7618322c653 100644 --- a/x-pack/plugins/reporting/server/config/index.ts +++ b/x-pack/plugins/reporting/server/config/index.ts @@ -10,6 +10,7 @@ import { ConfigSchema, ConfigType } from './schema'; export { createConfig$ } from './create_config'; export const config: PluginConfigDescriptor = { + exposeToBrowser: { poll: true }, schema: ConfigSchema, deprecations: ({ unused }) => [ unused('capture.browser.chromium.maxScreenshotDimension'), diff --git a/x-pack/plugins/reporting/server/config/schema.ts b/x-pack/plugins/reporting/server/config/schema.ts index 67d70c1513c15d..402fddcb5e0146 100644 --- a/x-pack/plugins/reporting/server/config/schema.ts +++ b/x-pack/plugins/reporting/server/config/schema.ts @@ -114,6 +114,7 @@ const CaptureSchema = schema.object({ const CsvSchema = schema.object({ checkForFormulas: schema.boolean({ defaultValue: true }), + escapeFormulaValues: schema.boolean({ defaultValue: false }), enablePanelActionDownload: schema.boolean({ defaultValue: true }), maxSizeBytes: schema.number({ defaultValue: 1024 * 1024 * 10, // 10MB diff --git a/x-pack/plugins/rollup/common/index.ts b/x-pack/plugins/rollup/common/index.ts new file mode 100644 index 00000000000000..aeffa3dc3959fd --- /dev/null +++ b/x-pack/plugins/rollup/common/index.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export const CONFIG_ROLLUPS = 'rollups:enableIndexPatterns'; + +export const API_BASE_PATH = '/api/rollup'; + +export { + UIM_APP_NAME, + UIM_APP_LOAD, + UIM_JOB_CREATE, + UIM_JOB_DELETE, + UIM_JOB_DELETE_MANY, + UIM_JOB_START, + UIM_JOB_START_MANY, + UIM_JOB_STOP, + UIM_JOB_STOP_MANY, + UIM_SHOW_DETAILS_CLICK, + UIM_DETAIL_PANEL_SUMMARY_TAB_CLICK, + UIM_DETAIL_PANEL_TERMS_TAB_CLICK, + UIM_DETAIL_PANEL_HISTOGRAM_TAB_CLICK, + UIM_DETAIL_PANEL_METRICS_TAB_CLICK, + UIM_DETAIL_PANEL_JSON_TAB_CLICK, +} from './ui_metric'; diff --git a/x-pack/legacy/plugins/rollup/common/ui_metric.ts b/x-pack/plugins/rollup/common/ui_metric.ts similarity index 100% rename from x-pack/legacy/plugins/rollup/common/ui_metric.ts rename to x-pack/plugins/rollup/common/ui_metric.ts diff --git a/x-pack/legacy/plugins/rollup/fixtures/index.js b/x-pack/plugins/rollup/fixtures/index.js similarity index 100% rename from x-pack/legacy/plugins/rollup/fixtures/index.js rename to x-pack/plugins/rollup/fixtures/index.js diff --git a/x-pack/legacy/plugins/rollup/fixtures/job.js b/x-pack/plugins/rollup/fixtures/job.js similarity index 95% rename from x-pack/legacy/plugins/rollup/fixtures/job.js rename to x-pack/plugins/rollup/fixtures/job.js index 3889cc6087d836..310244a5031e7a 100644 --- a/x-pack/legacy/plugins/rollup/fixtures/job.js +++ b/x-pack/plugins/rollup/fixtures/job.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { getRandomString } from '../../../../test_utils'; +import { getRandomString } from '../../../test_utils'; const initialValues = { dateHistogramField: 'timestamp', diff --git a/x-pack/plugins/rollup/kibana.json b/x-pack/plugins/rollup/kibana.json index 6ab2fc8907c0db..8f832f6c6a345a 100644 --- a/x-pack/plugins/rollup/kibana.json +++ b/x-pack/plugins/rollup/kibana.json @@ -2,5 +2,8 @@ "id": "rollup", "version": "8.0.0", "kibanaVersion": "kibana", - "server": true + "server": true, + "ui": true, + "optionalPlugins": ["home", "indexManagement", "indexPatternManagement", "usageCollection"], + "requiredPlugins": ["management", "data"] } diff --git a/x-pack/legacy/plugins/rollup/public/application.tsx b/x-pack/plugins/rollup/public/application.tsx similarity index 87% rename from x-pack/legacy/plugins/rollup/public/application.tsx rename to x-pack/plugins/rollup/public/application.tsx index df17d37bc34656..1bdf940d746b28 100644 --- a/x-pack/legacy/plugins/rollup/public/application.tsx +++ b/x-pack/plugins/rollup/public/application.tsx @@ -5,15 +5,17 @@ */ import React from 'react'; +import { ChromeBreadcrumb, CoreSetup } from 'kibana/public'; import { render, unmountComponentAtNode } from 'react-dom'; import { Provider } from 'react-redux'; -import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public'; -import { ChromeBreadcrumb, CoreSetup } from '../../../../../src/core/public'; +import { KibanaContextProvider } from '../../../../src/plugins/kibana_react/public'; // @ts-ignore import { rollupJobsStore } from './crud_app/store'; // @ts-ignore import { App } from './crud_app/app'; +import './index.scss'; + /** * This module will be loaded asynchronously to reduce the bundle size of your plugin's main bundle. */ diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/_crud_app.scss b/x-pack/plugins/rollup/public/crud_app/_crud_app.scss similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/_crud_app.scss rename to x-pack/plugins/rollup/public/crud_app/_crud_app.scss diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/app.js b/x-pack/plugins/rollup/public/crud_app/app.js similarity index 93% rename from x-pack/legacy/plugins/rollup/public/crud_app/app.js rename to x-pack/plugins/rollup/public/crud_app/app.js index da35c8a56f2d20..0ef3253eeb94ea 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/app.js +++ b/x-pack/plugins/rollup/public/crud_app/app.js @@ -10,7 +10,8 @@ import { HashRouter, Switch, Route, Redirect, withRouter } from 'react-router-do import { UIM_APP_LOAD } from '../../common'; import { CRUD_APP_BASE_PATH } from './constants'; -import { registerRouter, setUserHasLeftApp, trackUiMetric, METRIC_TYPE } from './services'; +import { registerRouter, setUserHasLeftApp, METRIC_TYPE } from './services'; +import { trackUiMetric } from '../kibana_services'; import { JobList, JobCreate } from './sections'; class ShareRouterComponent extends Component { diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/constants/index.js b/x-pack/plugins/rollup/public/crud_app/constants/index.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/constants/index.js rename to x-pack/plugins/rollup/public/crud_app/constants/index.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/constants/metrics_config.js b/x-pack/plugins/rollup/public/crud_app/constants/metrics_config.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/constants/metrics_config.js rename to x-pack/plugins/rollup/public/crud_app/constants/metrics_config.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/constants/paths.js b/x-pack/plugins/rollup/public/crud_app/constants/paths.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/constants/paths.js rename to x-pack/plugins/rollup/public/crud_app/constants/paths.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/field_list/field_list.js b/x-pack/plugins/rollup/public/crud_app/sections/components/field_list/field_list.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/components/field_list/field_list.js rename to x-pack/plugins/rollup/public/crud_app/sections/components/field_list/field_list.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/field_list/index.js b/x-pack/plugins/rollup/public/crud_app/sections/components/field_list/index.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/components/field_list/index.js rename to x-pack/plugins/rollup/public/crud_app/sections/components/field_list/index.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/index.js b/x-pack/plugins/rollup/public/crud_app/sections/components/index.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/components/index.js rename to x-pack/plugins/rollup/public/crud_app/sections/components/index.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_action_menu/confirm_delete_modal/confirm_delete_modal.js b/x-pack/plugins/rollup/public/crud_app/sections/components/job_action_menu/confirm_delete_modal/confirm_delete_modal.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_action_menu/confirm_delete_modal/confirm_delete_modal.js rename to x-pack/plugins/rollup/public/crud_app/sections/components/job_action_menu/confirm_delete_modal/confirm_delete_modal.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_action_menu/confirm_delete_modal/index.js b/x-pack/plugins/rollup/public/crud_app/sections/components/job_action_menu/confirm_delete_modal/index.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_action_menu/confirm_delete_modal/index.js rename to x-pack/plugins/rollup/public/crud_app/sections/components/job_action_menu/confirm_delete_modal/index.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_action_menu/index.js b/x-pack/plugins/rollup/public/crud_app/sections/components/job_action_menu/index.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_action_menu/index.js rename to x-pack/plugins/rollup/public/crud_app/sections/components/job_action_menu/index.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_action_menu/job_action_menu.container.js b/x-pack/plugins/rollup/public/crud_app/sections/components/job_action_menu/job_action_menu.container.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_action_menu/job_action_menu.container.js rename to x-pack/plugins/rollup/public/crud_app/sections/components/job_action_menu/job_action_menu.container.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_action_menu/job_action_menu.js b/x-pack/plugins/rollup/public/crud_app/sections/components/job_action_menu/job_action_menu.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_action_menu/job_action_menu.js rename to x-pack/plugins/rollup/public/crud_app/sections/components/job_action_menu/job_action_menu.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_details/index.js b/x-pack/plugins/rollup/public/crud_app/sections/components/job_details/index.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_details/index.js rename to x-pack/plugins/rollup/public/crud_app/sections/components/job_details/index.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_details/job_details.js b/x-pack/plugins/rollup/public/crud_app/sections/components/job_details/job_details.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_details/job_details.js rename to x-pack/plugins/rollup/public/crud_app/sections/components/job_details/job_details.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_details/tabs/index.js b/x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/index.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_details/tabs/index.js rename to x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/index.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_histogram.js b/x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_histogram.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_histogram.js rename to x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_histogram.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_json.js b/x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_json.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_json.js rename to x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_json.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_metrics.js b/x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_metrics.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_metrics.js rename to x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_metrics.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_request.js b/x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_request.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_request.js rename to x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_request.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_summary.js b/x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_summary.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_summary.js rename to x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_summary.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_terms.js b/x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_terms.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_terms.js rename to x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_terms.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_status/index.js b/x-pack/plugins/rollup/public/crud_app/sections/components/job_status/index.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_status/index.js rename to x-pack/plugins/rollup/public/crud_app/sections/components/job_status/index.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_status/job_status.js b/x-pack/plugins/rollup/public/crud_app/sections/components/job_status/job_status.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/components/job_status/job_status.js rename to x-pack/plugins/rollup/public/crud_app/sections/components/job_status/job_status.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/index.js b/x-pack/plugins/rollup/public/crud_app/sections/index.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/index.js rename to x-pack/plugins/rollup/public/crud_app/sections/index.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/index.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/index.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/index.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/index.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/job_create.container.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/job_create.container.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/job_create.container.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/job_create.container.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/job_create.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/job_create.js similarity index 99% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/job_create.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/job_create.js index d45e28d7c5456c..0f6fb8dbfee14f 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/job_create.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/job_create/job_create.js @@ -14,7 +14,7 @@ import first from 'lodash/array/first'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { withKibana } from '../../../../../../../../src/plugins/kibana_react/public/'; +import { withKibana } from '../../../../../../../src/plugins/kibana_react/public'; import { EuiCallOut, diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/navigation/index.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/navigation/index.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/navigation/index.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/navigation/index.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/navigation/navigation.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/navigation/navigation.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/navigation/navigation.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/navigation/navigation.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/components/field_chooser.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps/components/field_chooser.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/components/field_chooser.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/steps/components/field_chooser.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/components/index.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps/components/index.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/components/index.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/steps/components/index.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/components/step_error.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps/components/step_error.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/components/step_error.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/steps/components/step_error.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/index.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps/index.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/index.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/steps/index.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_date_histogram.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps/step_date_histogram.js similarity index 99% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_date_histogram.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/steps/step_date_histogram.js index ba65d082c0b4b8..c327e51a6b7eeb 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_date_histogram.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps/step_date_histogram.js @@ -24,7 +24,7 @@ import { EuiTitle, } from '@elastic/eui'; -import { search } from '../../../../../../../../../src/plugins/data/public'; +import { search } from '../../../../../../../../src/plugins/data/public'; const { parseEsInterval } = search.aggs; import { getDateHistogramDetailsUrl, getDateHistogramAggregationUrl } from '../../../services'; diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_histogram.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps/step_histogram.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_histogram.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/steps/step_histogram.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_logistics.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps/step_logistics.js similarity index 99% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_logistics.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/steps/step_logistics.js index 5462a46bf59b96..0fd76e572b2e50 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_logistics.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps/step_logistics.js @@ -24,8 +24,8 @@ import { EuiTitle, } from '@elastic/eui'; -import { CronEditor } from '../../../../../../../../../src/plugins/es_ui_shared/public'; -import { indexPatterns } from '../../../../../../../../../src/plugins/data/public'; +import { CronEditor } from '../../../../../../../../src/plugins/es_ui_shared/public'; +import { indexPatterns } from '../../../../../../../../src/plugins/data/public'; import { indices } from '../../../../shared_imports'; import { getLogisticalDetailsUrl, getCronUrl } from '../../../services'; diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_metrics.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps/step_metrics.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_metrics.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/steps/step_metrics.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_review.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps/step_review.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_review.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/steps/step_review.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_terms.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps/step_terms.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/step_terms.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/steps/step_terms.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/index.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/index.js similarity index 96% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/index.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/index.js index e1efcfdd24627b..4a55c4679c3d86 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/index.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/index.js @@ -8,7 +8,7 @@ import cloneDeep from 'lodash/lang/cloneDeep'; import get from 'lodash/object/get'; import pick from 'lodash/object/pick'; -import { WEEK } from '../../../../../../../../../src/plugins/es_ui_shared/public'; +import { WEEK } from '../../../../../../../../src/plugins/es_ui_shared/public'; import { validateId } from './validate_id'; import { validateIndexPattern } from './validate_index_pattern'; @@ -42,7 +42,7 @@ export const stepIds = [ * 1. getDefaultFields: (overrides) => object * 2. fieldValidations * - * See x-pack/legacy/plugins/rollup/public/crud_app/services/jobs.js for more information on override's shape + * See x-pack/plugins/rollup/public/crud_app/services/jobs.js for more information on override's shape */ export const stepIdToStepConfigMap = { [STEP_LOGISTICS]: { diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_date_histogram_field.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_date_histogram_field.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_date_histogram_field.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_date_histogram_field.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_date_histogram_interval.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_date_histogram_interval.js similarity index 95% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_date_histogram_interval.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_date_histogram_interval.js index b6c824bc8c553a..819c814e373d59 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_date_histogram_interval.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_date_histogram_interval.js @@ -6,7 +6,7 @@ import React from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import { search } from '../../../../../../../../../src/plugins/data/public'; +import { search } from '../../../../../../../../src/plugins/data/public'; const { InvalidEsIntervalFormatError, InvalidEsCalendarIntervalError, diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_histogram_interval.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_histogram_interval.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_histogram_interval.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_histogram_interval.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_id.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_id.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_id.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_id.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_index_pattern.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_index_pattern.js similarity index 95% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_index_pattern.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_index_pattern.js index 206cc325813c0d..534fcaa744744a 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_index_pattern.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_index_pattern.js @@ -7,7 +7,7 @@ import React from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import { indexPatterns } from '../../../../../../../../../src/plugins/data/public'; +import { indexPatterns } from '../../../../../../../../src/plugins/data/public'; export function validateIndexPattern(indexPattern, rollupIndex) { if (!indexPattern || !indexPattern.trim()) { return [ diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_metrics.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_metrics.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_metrics.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_metrics.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_cron.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_cron.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_cron.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_cron.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_delay.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_delay.js similarity index 95% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_delay.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_delay.js index 37c2ca9a1d775d..66bfd43bc3d1bd 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_delay.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_delay.js @@ -6,7 +6,7 @@ import React from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import { search } from '../../../../../../../../../src/plugins/data/public'; +import { search } from '../../../../../../../../src/plugins/data/public'; const { InvalidEsIntervalFormatError, InvalidEsCalendarIntervalError, diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_index.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_index.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_index.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_index.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_page_size.js b/x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_page_size.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_page_size.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_create/steps_config/validate_rollup_page_size.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.container.js b/x-pack/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.container.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.container.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.container.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.js b/x-pack/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.js similarity index 98% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.js index f774b1d7f63b72..3f168a66feed84 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.js @@ -34,7 +34,8 @@ import { UIM_DETAIL_PANEL_METRICS_TAB_CLICK, UIM_DETAIL_PANEL_JSON_TAB_CLICK, } from '../../../../../common'; -import { trackUiMetric, METRIC_TYPE } from '../../../services'; +import { METRIC_TYPE } from '../../../services'; +import { trackUiMetric } from '../../../../kibana_services'; import { JobActionMenu, diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.test.js b/x-pack/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.test.js similarity index 98% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.test.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.test.js index 9ac8e6075e4cf3..cea5b3c3e96e57 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.test.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.test.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { registerTestBed } from '../../../../../../../../test_utils'; +import { registerTestBed } from '../../../../../../../test_utils'; import { getJob } from '../../../../../fixtures'; import { rollupJobsStore } from '../../../store'; import { DetailPanel } from './detail_panel'; @@ -17,9 +17,8 @@ import { tabToHumanizedMap, } from '../../components'; -jest.mock('ui/new_platform'); -jest.mock('../../../services', () => { - const services = require.requireActual('../../../services'); +jest.mock('../../../../kibana_services', () => { + const services = require.requireActual('../../../../kibana_services'); return { ...services, trackUiMetric: jest.fn(), diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/detail_panel/index.js b/x-pack/plugins/rollup/public/crud_app/sections/job_list/detail_panel/index.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/detail_panel/index.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_list/detail_panel/index.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/index.js b/x-pack/plugins/rollup/public/crud_app/sections/job_list/index.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/index.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_list/index.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_list.container.js b/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.container.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_list.container.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.container.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_list.js b/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.js similarity index 98% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_list.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.js index 98329a687217a7..011becded148cf 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_list.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.js @@ -25,7 +25,7 @@ import { EuiCallOut, } from '@elastic/eui'; -import { withKibana } from '../../../../../../../../src/plugins/kibana_react/public/'; +import { withKibana } from '../../../../../../../src/plugins/kibana_react/public'; import { CRUD_APP_BASE_PATH } from '../../constants'; import { getRouterLinkProps, extractQueryParams, listBreadcrumb } from '../../services'; diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_list.test.js b/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.test.js similarity index 90% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_list.test.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.test.js index 725789fc584de5..8c3bffd223ca9c 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_list.test.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.test.js @@ -5,16 +5,14 @@ */ import React from 'react'; -import { registerTestBed } from '../../../../../../../test_utils'; +import { registerTestBed } from '../../../../../../test_utils'; import { rollupJobsStore } from '../../store'; import { JobList } from './job_list'; -import { KibanaContextProvider } from '../../../../../../../../src/plugins/kibana_react/public'; -import { coreMock } from '../../../../../../../../src/core/public/mocks'; +import { KibanaContextProvider } from '../../../../../../../src/plugins/kibana_react/public'; +import { coreMock } from '../../../../../../../src/core/public/mocks'; const startMock = coreMock.createStart(); -jest.mock('ui/new_platform'); - jest.mock('../../services', () => { const services = require.requireActual('../../services'); return { diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_table/index.js b/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_table/index.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_table/index.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_list/job_table/index.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.container.js b/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.container.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.container.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.container.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.js b/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.js similarity index 99% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.js index 4dbe396ab8410f..f47992e1b501ae 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.js @@ -30,7 +30,8 @@ import { } from '@elastic/eui'; import { UIM_SHOW_DETAILS_CLICK } from '../../../../../common'; -import { trackUiMetric, METRIC_TYPE } from '../../../services'; +import { METRIC_TYPE } from '../../../services'; +import { trackUiMetric } from '../../../../kibana_services'; import { JobActionMenu, JobStatus } from '../../components'; const COLUMNS = [ diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.test.js b/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.test.js similarity index 96% rename from x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.test.js rename to x-pack/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.test.js index c688343d5f7681..c6a3d3a8f69add 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.test.js +++ b/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.test.js @@ -6,14 +6,13 @@ import { Pager } from '@elastic/eui'; -import { registerTestBed } from '../../../../../../../../test_utils'; +import { registerTestBed } from '../../../../../../../test_utils'; import { getJobs, jobCount } from '../../../../../fixtures'; import { rollupJobsStore } from '../../../store'; import { JobTable } from './job_table'; -jest.mock('ui/new_platform'); -jest.mock('../../../services', () => { - const services = require.requireActual('../../../services'); +jest.mock('../../../../kibana_services', () => { + const services = require.requireActual('../../../../kibana_services'); return { ...services, trackUiMetric: jest.fn(), diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/services/api.js b/x-pack/plugins/rollup/public/crud_app/services/api.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/services/api.js rename to x-pack/plugins/rollup/public/crud_app/services/api.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/services/api_errors.ts b/x-pack/plugins/rollup/public/crud_app/services/api_errors.ts similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/services/api_errors.ts rename to x-pack/plugins/rollup/public/crud_app/services/api_errors.ts diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/services/breadcrumbs.js b/x-pack/plugins/rollup/public/crud_app/services/breadcrumbs.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/services/breadcrumbs.js rename to x-pack/plugins/rollup/public/crud_app/services/breadcrumbs.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/services/documentation_links.js b/x-pack/plugins/rollup/public/crud_app/services/documentation_links.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/services/documentation_links.js rename to x-pack/plugins/rollup/public/crud_app/services/documentation_links.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/services/filter_items.js b/x-pack/plugins/rollup/public/crud_app/services/filter_items.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/services/filter_items.js rename to x-pack/plugins/rollup/public/crud_app/services/filter_items.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/services/flatten_panel_tree.js b/x-pack/plugins/rollup/public/crud_app/services/flatten_panel_tree.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/services/flatten_panel_tree.js rename to x-pack/plugins/rollup/public/crud_app/services/flatten_panel_tree.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/services/format_fields.js b/x-pack/plugins/rollup/public/crud_app/services/format_fields.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/services/format_fields.js rename to x-pack/plugins/rollup/public/crud_app/services/format_fields.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/services/http_provider.ts b/x-pack/plugins/rollup/public/crud_app/services/http_provider.ts similarity index 91% rename from x-pack/legacy/plugins/rollup/public/crud_app/services/http_provider.ts rename to x-pack/plugins/rollup/public/crud_app/services/http_provider.ts index dd84328084d050..93898610b844ed 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/services/http_provider.ts +++ b/x-pack/plugins/rollup/public/crud_app/services/http_provider.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { HttpStart } from 'src/core/public'; +import { HttpStart } from 'kibana/public'; let _http: HttpStart | null = null; diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/services/index.js b/x-pack/plugins/rollup/public/crud_app/services/index.js similarity index 95% rename from x-pack/legacy/plugins/rollup/public/crud_app/services/index.js rename to x-pack/plugins/rollup/public/crud_app/services/index.js index 790770b9b6a9f4..0b45b1bdb6b5fb 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/services/index.js +++ b/x-pack/plugins/rollup/public/crud_app/services/index.js @@ -47,4 +47,4 @@ export { sortTable } from './sort_table'; export { retypeMetrics } from './retype_metrics'; -export { trackUiMetric, METRIC_TYPE } from './track_ui_metric'; +export { METRIC_TYPE } from './track_ui_metric'; diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/services/jobs.js b/x-pack/plugins/rollup/public/crud_app/services/jobs.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/services/jobs.js rename to x-pack/plugins/rollup/public/crud_app/services/jobs.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/services/noticeable_delay.js b/x-pack/plugins/rollup/public/crud_app/services/noticeable_delay.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/services/noticeable_delay.js rename to x-pack/plugins/rollup/public/crud_app/services/noticeable_delay.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/services/query_params.js b/x-pack/plugins/rollup/public/crud_app/services/query_params.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/services/query_params.js rename to x-pack/plugins/rollup/public/crud_app/services/query_params.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/services/retype_metrics.js b/x-pack/plugins/rollup/public/crud_app/services/retype_metrics.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/services/retype_metrics.js rename to x-pack/plugins/rollup/public/crud_app/services/retype_metrics.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/services/routing.js b/x-pack/plugins/rollup/public/crud_app/services/routing.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/services/routing.js rename to x-pack/plugins/rollup/public/crud_app/services/routing.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/services/sort_table.js b/x-pack/plugins/rollup/public/crud_app/services/sort_table.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/services/sort_table.js rename to x-pack/plugins/rollup/public/crud_app/services/sort_table.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/services/track_ui_metric.js b/x-pack/plugins/rollup/public/crud_app/services/track_ui_metric.ts similarity index 70% rename from x-pack/legacy/plugins/rollup/public/crud_app/services/track_ui_metric.js rename to x-pack/plugins/rollup/public/crud_app/services/track_ui_metric.ts index 69a5995386bd74..aa1cc2dfea323d 100644 --- a/x-pack/legacy/plugins/rollup/public/crud_app/services/track_ui_metric.js +++ b/x-pack/plugins/rollup/public/crud_app/services/track_ui_metric.ts @@ -4,20 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - createUiStatsReporter, - METRIC_TYPE, -} from '../../../../../../../src/legacy/core_plugins/ui_metric/public'; -import { UIM_APP_NAME } from '../../../common'; +import { METRIC_TYPE } from '@kbn/analytics'; +import { trackUiMetric } from '../../kibana_services'; -export const trackUiMetric = createUiStatsReporter(UIM_APP_NAME); export { METRIC_TYPE }; /** * Transparently return provided request Promise, while allowing us to track * a successful completion of the request. */ -export function trackUserRequest(request, actionType) { +export function trackUserRequest(request: Promise, actionType: string) { // Only track successful actions. return request.then(response => { trackUiMetric(METRIC_TYPE.LOADED, actionType); diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/store/action_types.js b/x-pack/plugins/rollup/public/crud_app/store/action_types.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/store/action_types.js rename to x-pack/plugins/rollup/public/crud_app/store/action_types.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/store/actions/change_job_status.js b/x-pack/plugins/rollup/public/crud_app/store/actions/change_job_status.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/store/actions/change_job_status.js rename to x-pack/plugins/rollup/public/crud_app/store/actions/change_job_status.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/store/actions/clone_job.js b/x-pack/plugins/rollup/public/crud_app/store/actions/clone_job.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/store/actions/clone_job.js rename to x-pack/plugins/rollup/public/crud_app/store/actions/clone_job.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/store/actions/create_job.js b/x-pack/plugins/rollup/public/crud_app/store/actions/create_job.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/store/actions/create_job.js rename to x-pack/plugins/rollup/public/crud_app/store/actions/create_job.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/store/actions/delete_jobs.js b/x-pack/plugins/rollup/public/crud_app/store/actions/delete_jobs.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/store/actions/delete_jobs.js rename to x-pack/plugins/rollup/public/crud_app/store/actions/delete_jobs.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/store/actions/detail_panel.js b/x-pack/plugins/rollup/public/crud_app/store/actions/detail_panel.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/store/actions/detail_panel.js rename to x-pack/plugins/rollup/public/crud_app/store/actions/detail_panel.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/store/actions/index.js b/x-pack/plugins/rollup/public/crud_app/store/actions/index.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/store/actions/index.js rename to x-pack/plugins/rollup/public/crud_app/store/actions/index.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/store/actions/load_jobs.js b/x-pack/plugins/rollup/public/crud_app/store/actions/load_jobs.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/store/actions/load_jobs.js rename to x-pack/plugins/rollup/public/crud_app/store/actions/load_jobs.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/store/actions/refresh_jobs.js b/x-pack/plugins/rollup/public/crud_app/store/actions/refresh_jobs.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/store/actions/refresh_jobs.js rename to x-pack/plugins/rollup/public/crud_app/store/actions/refresh_jobs.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/store/actions/table_state.js b/x-pack/plugins/rollup/public/crud_app/store/actions/table_state.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/store/actions/table_state.js rename to x-pack/plugins/rollup/public/crud_app/store/actions/table_state.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/store/index.js b/x-pack/plugins/rollup/public/crud_app/store/index.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/store/index.js rename to x-pack/plugins/rollup/public/crud_app/store/index.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/store/middleware/clone_job.js b/x-pack/plugins/rollup/public/crud_app/store/middleware/clone_job.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/store/middleware/clone_job.js rename to x-pack/plugins/rollup/public/crud_app/store/middleware/clone_job.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/store/middleware/detail_panel.js b/x-pack/plugins/rollup/public/crud_app/store/middleware/detail_panel.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/store/middleware/detail_panel.js rename to x-pack/plugins/rollup/public/crud_app/store/middleware/detail_panel.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/store/middleware/index.js b/x-pack/plugins/rollup/public/crud_app/store/middleware/index.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/store/middleware/index.js rename to x-pack/plugins/rollup/public/crud_app/store/middleware/index.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/store/reducers/clone_job.js b/x-pack/plugins/rollup/public/crud_app/store/reducers/clone_job.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/store/reducers/clone_job.js rename to x-pack/plugins/rollup/public/crud_app/store/reducers/clone_job.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/store/reducers/create_job.js b/x-pack/plugins/rollup/public/crud_app/store/reducers/create_job.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/store/reducers/create_job.js rename to x-pack/plugins/rollup/public/crud_app/store/reducers/create_job.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/store/reducers/detail_panel.js b/x-pack/plugins/rollup/public/crud_app/store/reducers/detail_panel.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/store/reducers/detail_panel.js rename to x-pack/plugins/rollup/public/crud_app/store/reducers/detail_panel.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/store/reducers/index.js b/x-pack/plugins/rollup/public/crud_app/store/reducers/index.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/store/reducers/index.js rename to x-pack/plugins/rollup/public/crud_app/store/reducers/index.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/store/reducers/jobs.js b/x-pack/plugins/rollup/public/crud_app/store/reducers/jobs.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/store/reducers/jobs.js rename to x-pack/plugins/rollup/public/crud_app/store/reducers/jobs.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/store/reducers/table_state.js b/x-pack/plugins/rollup/public/crud_app/store/reducers/table_state.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/store/reducers/table_state.js rename to x-pack/plugins/rollup/public/crud_app/store/reducers/table_state.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/store/reducers/update_job.js b/x-pack/plugins/rollup/public/crud_app/store/reducers/update_job.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/store/reducers/update_job.js rename to x-pack/plugins/rollup/public/crud_app/store/reducers/update_job.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/store/selectors/index.js b/x-pack/plugins/rollup/public/crud_app/store/selectors/index.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/store/selectors/index.js rename to x-pack/plugins/rollup/public/crud_app/store/selectors/index.js diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/store/store.js b/x-pack/plugins/rollup/public/crud_app/store/store.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/crud_app/store/store.js rename to x-pack/plugins/rollup/public/crud_app/store/store.js diff --git a/x-pack/legacy/plugins/rollup/public/extend_index_management/index.ts b/x-pack/plugins/rollup/public/extend_index_management/index.ts similarity index 100% rename from x-pack/legacy/plugins/rollup/public/extend_index_management/index.ts rename to x-pack/plugins/rollup/public/extend_index_management/index.ts diff --git a/x-pack/legacy/plugins/rollup/public/index.scss b/x-pack/plugins/rollup/public/index.scss similarity index 67% rename from x-pack/legacy/plugins/rollup/public/index.scss rename to x-pack/plugins/rollup/public/index.scss index 0ad0eac50f7b93..cbbedcebb043e1 100644 --- a/x-pack/legacy/plugins/rollup/public/index.scss +++ b/x-pack/plugins/rollup/public/index.scss @@ -1,6 +1,3 @@ -// Import the EUI global scope so we can use EUI constants -@import 'src/legacy/ui/public/styles/_styling_constants'; - // Index management plugin styles // Prefix all styles with "rollup" to avoid conflicts. diff --git a/x-pack/plugins/rollup/public/index.ts b/x-pack/plugins/rollup/public/index.ts new file mode 100644 index 00000000000000..4c965fc38f4e7d --- /dev/null +++ b/x-pack/plugins/rollup/public/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { RollupPlugin } from './plugin'; + +export const plugin = () => new RollupPlugin(); diff --git a/x-pack/legacy/plugins/rollup/public/index_pattern_creation/components/rollup_prompt/index.js b/x-pack/plugins/rollup/public/index_pattern_creation/components/rollup_prompt/index.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/index_pattern_creation/components/rollup_prompt/index.js rename to x-pack/plugins/rollup/public/index_pattern_creation/components/rollup_prompt/index.js diff --git a/x-pack/legacy/plugins/rollup/public/index_pattern_creation/components/rollup_prompt/rollup_prompt.js b/x-pack/plugins/rollup/public/index_pattern_creation/components/rollup_prompt/rollup_prompt.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/index_pattern_creation/components/rollup_prompt/rollup_prompt.js rename to x-pack/plugins/rollup/public/index_pattern_creation/components/rollup_prompt/rollup_prompt.js diff --git a/x-pack/legacy/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js b/x-pack/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js similarity index 97% rename from x-pack/legacy/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js rename to x-pack/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js index f4de2a30981276..c29fba44285be0 100644 --- a/x-pack/legacy/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js +++ b/x-pack/plugins/rollup/public/index_pattern_creation/rollup_index_pattern_creation_config.js @@ -8,7 +8,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { RollupPrompt } from './components/rollup_prompt'; -import { IndexPatternCreationConfig } from '../../../../../../src/plugins/index_pattern_management/public'; +import { IndexPatternCreationConfig } from '../../../../../src/plugins/index_pattern_management/public'; const rollupIndexPatternTypeName = i18n.translate( 'xpack.rollupJobs.editRollupIndexPattern.createIndex.defaultTypeName', diff --git a/x-pack/legacy/plugins/rollup/public/index_pattern_list/rollup_index_pattern_list_config.js b/x-pack/plugins/rollup/public/index_pattern_list/rollup_index_pattern_list_config.js similarity index 93% rename from x-pack/legacy/plugins/rollup/public/index_pattern_list/rollup_index_pattern_list_config.js rename to x-pack/plugins/rollup/public/index_pattern_list/rollup_index_pattern_list_config.js index 809a76d1868b22..e61287d303643c 100644 --- a/x-pack/legacy/plugins/rollup/public/index_pattern_list/rollup_index_pattern_list_config.js +++ b/x-pack/plugins/rollup/public/index_pattern_list/rollup_index_pattern_list_config.js @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { IndexPatternListConfig } from '../../../../../../src/plugins/index_pattern_management/public'; +import { IndexPatternListConfig } from '../../../../../src/plugins/index_pattern_management/public'; function isRollup(indexPattern) { return ( diff --git a/x-pack/legacy/plugins/rollup/public/kibana_services.ts b/x-pack/plugins/rollup/public/kibana_services.ts similarity index 57% rename from x-pack/legacy/plugins/rollup/public/kibana_services.ts rename to x-pack/plugins/rollup/public/kibana_services.ts index 335eeb90282ca9..edbf69568f5e50 100644 --- a/x-pack/legacy/plugins/rollup/public/kibana_services.ts +++ b/x-pack/plugins/rollup/public/kibana_services.ts @@ -4,7 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { NotificationsStart, FatalErrorsSetup } from 'src/core/public'; +import { NotificationsStart, FatalErrorsSetup } from 'kibana/public'; +import { UiStatsMetricType } from '@kbn/analytics'; +import { createGetterSetter } from '../../../../src/plugins/kibana_utils/common'; let notifications: NotificationsStart | null = null; let fatalErrors: FatalErrorsSetup | null = null; @@ -28,3 +30,18 @@ export function getFatalErrors() { export function setFatalErrors(newFatalErrors: FatalErrorsSetup) { fatalErrors = newFatalErrors; } + +export const [getUiStatsReporter, setUiStatsReporter] = createGetterSetter< + (type: UiStatsMetricType, eventNames: string | string[], count?: number) => void +>('uiMetric'); + +// default value if usageCollection is not available +setUiStatsReporter(() => {}); + +export function trackUiMetric( + type: UiStatsMetricType, + eventNames: string | string[], + count?: number +) { + getUiStatsReporter()(type, eventNames, count); +} diff --git a/x-pack/legacy/plugins/rollup/public/plugin.ts b/x-pack/plugins/rollup/public/plugin.ts similarity index 73% rename from x-pack/legacy/plugins/rollup/public/plugin.ts rename to x-pack/plugins/rollup/public/plugin.ts index 17ec8a5a4aedf1..fd1b90fbc98557 100644 --- a/x-pack/legacy/plugins/rollup/public/plugin.ts +++ b/x-pack/plugins/rollup/public/plugin.ts @@ -6,7 +6,6 @@ import { i18n } from '@kbn/i18n'; import { CoreSetup, CoreStart, Plugin } from 'kibana/public'; -import { PluginsStart } from './legacy_imports'; import { rollupBadgeExtension, rollupToggleExtension } from './extend_index_management'; // @ts-ignore import { RollupIndexPatternCreationConfig } from './index_pattern_creation/rollup_index_pattern_creation_config'; @@ -16,35 +15,49 @@ import { RollupIndexPatternListConfig } from './index_pattern_list/rollup_index_ import { initAggTypeFilter } from './visualize/agg_type_filter'; // @ts-ignore import { initAggTypeFieldFilter } from './visualize/agg_type_field_filter'; -import { CONFIG_ROLLUPS } from '../common'; +import { CONFIG_ROLLUPS, UIM_APP_NAME } from '../common'; import { FeatureCatalogueCategory, HomePublicPluginSetup, -} from '../../../../../src/plugins/home/public'; +} from '../../../../src/plugins/home/public'; // @ts-ignore import { CRUD_APP_BASE_PATH } from './crud_app/constants'; -import { ManagementSetup } from '../../../../../src/plugins/management/public'; -import { IndexManagementPluginSetup } from '../../../../plugins/index_management/public'; -import { IndexPatternManagementSetup } from '../../../../../src/plugins/index_pattern_management/public'; -import { search } from '../../../../../src/plugins/data/public'; +import { ManagementSetup } from '../../../../src/plugins/management/public'; +import { IndexManagementPluginSetup } from '../../index_management/public'; +import { IndexPatternManagementSetup } from '../../../../src/plugins/index_pattern_management/public'; +import { DataPublicPluginStart, search } from '../../../../src/plugins/data/public'; // @ts-ignore -import { setEsBaseAndXPackBase, setHttp } from './crud_app/services'; -import { setNotifications, setFatalErrors } from './kibana_services'; -import { renderApp } from './application'; +import { setEsBaseAndXPackBase, setHttp } from './crud_app/services/index'; +import { setNotifications, setFatalErrors, setUiStatsReporter } from './kibana_services'; +import { UsageCollectionSetup } from '../../../../src/plugins/usage_collection/public'; export interface RollupPluginSetupDependencies { home?: HomePublicPluginSetup; management: ManagementSetup; indexManagement?: IndexManagementPluginSetup; indexPatternManagement: IndexPatternManagementSetup; + usageCollection?: UsageCollectionSetup; +} + +export interface RollupPluginStartDependencies { + data: DataPublicPluginStart; } export class RollupPlugin implements Plugin { setup( core: CoreSetup, - { home, management, indexManagement, indexPatternManagement }: RollupPluginSetupDependencies + { + home, + management, + indexManagement, + indexPatternManagement, + usageCollection, + }: RollupPluginSetupDependencies ) { setFatalErrors(core.fatalErrors); + if (usageCollection) { + setUiStatsReporter(usageCollection.reportUiStats.bind(usageCollection, UIM_APP_NAME)); + } if (indexManagement) { indexManagement.extensionsService.addBadge(rollupBadgeExtension); @@ -79,7 +92,7 @@ export class RollupPlugin implements Plugin { id: 'rollup_jobs', title: i18n.translate('xpack.rollupJobs.appTitle', { defaultMessage: 'Rollup Jobs' }), order: 3, - mount(params) { + async mount(params) { params.setBreadcrumbs([ { text: i18n.translate('xpack.rollupJobs.breadcrumbsTitle', { @@ -87,6 +100,7 @@ export class RollupPlugin implements Plugin { }), }, ]); + const { renderApp } = await import('./application'); return renderApp(core, params); }, @@ -94,7 +108,7 @@ export class RollupPlugin implements Plugin { } } - start(core: CoreStart, plugins: PluginsStart) { + start(core: CoreStart, plugins: RollupPluginStartDependencies) { setHttp(core.http); setNotifications(core.notifications); setEsBaseAndXPackBase(core.docLinks.ELASTIC_WEBSITE_URL, core.docLinks.DOC_LINK_VERSION); diff --git a/x-pack/legacy/plugins/rollup/public/shared_imports.ts b/x-pack/plugins/rollup/public/shared_imports.ts similarity index 76% rename from x-pack/legacy/plugins/rollup/public/shared_imports.ts rename to x-pack/plugins/rollup/public/shared_imports.ts index 6bf74da6db6fe5..1ac25a1a0e5f8e 100644 --- a/x-pack/legacy/plugins/rollup/public/shared_imports.ts +++ b/x-pack/plugins/rollup/public/shared_imports.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { indices } from '../../../../../src/plugins/es_ui_shared/public'; +export { indices } from '../../../../src/plugins/es_ui_shared/public'; diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/constants.js b/x-pack/plugins/rollup/public/test/client_integration/helpers/constants.js similarity index 100% rename from x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/constants.js rename to x-pack/plugins/rollup/public/test/client_integration/helpers/constants.js diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/index.js b/x-pack/plugins/rollup/public/test/client_integration/helpers/index.js similarity index 100% rename from x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/index.js rename to x-pack/plugins/rollup/public/test/client_integration/helpers/index.js diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/job_clone.helpers.js b/x-pack/plugins/rollup/public/test/client_integration/helpers/job_clone.helpers.js similarity index 83% rename from x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/job_clone.helpers.js rename to x-pack/plugins/rollup/public/test/client_integration/helpers/job_clone.helpers.js index a8376bb31b23ff..fa9929a2076158 100644 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/job_clone.helpers.js +++ b/x-pack/plugins/rollup/public/test/client_integration/helpers/job_clone.helpers.js @@ -5,10 +5,10 @@ */ import { registerTestBed } from '../../../../../../test_utils'; -import { createRollupJobsStore } from '../../../public/crud_app/store'; -import { JobCreate } from '../../../public/crud_app/sections'; +import { createRollupJobsStore } from '../../../crud_app/store'; +import { JobCreate } from '../../../crud_app/sections'; import { JOB_TO_CLONE } from './constants'; -import { deserializeJob } from '../../../public/crud_app/services'; +import { deserializeJob } from '../../../crud_app/services'; import { wrapComponent } from './setup_context'; diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/job_create.helpers.js b/x-pack/plugins/rollup/public/test/client_integration/helpers/job_create.helpers.js similarity index 96% rename from x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/job_create.helpers.js rename to x-pack/plugins/rollup/public/test/client_integration/helpers/job_create.helpers.js index 2395fd014dd1e5..7ddcfa9eb83ff5 100644 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/job_create.helpers.js +++ b/x-pack/plugins/rollup/public/test/client_integration/helpers/job_create.helpers.js @@ -5,8 +5,8 @@ */ import { registerTestBed } from '../../../../../../test_utils'; -import { rollupJobsStore } from '../../../public/crud_app/store'; -import { JobCreate } from '../../../public/crud_app/sections'; +import { rollupJobsStore } from '../../../crud_app/store'; +import { JobCreate } from '../../../crud_app/sections'; import { JOB_TO_CREATE } from './constants'; diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/job_list.helpers.js b/x-pack/plugins/rollup/public/test/client_integration/helpers/job_list.helpers.js similarity index 74% rename from x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/job_list.helpers.js rename to x-pack/plugins/rollup/public/test/client_integration/helpers/job_list.helpers.js index bcad8c29c87c03..fda1ec8cfed22d 100644 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/job_list.helpers.js +++ b/x-pack/plugins/rollup/public/test/client_integration/helpers/job_list.helpers.js @@ -5,9 +5,9 @@ */ import { registerTestBed } from '../../../../../../test_utils'; -import { registerRouter } from '../../../public/crud_app/services'; -import { createRollupJobsStore } from '../../../public/crud_app/store'; -import { JobList } from '../../../public/crud_app/sections/job_list'; +import { registerRouter } from '../../../crud_app/services'; +import { createRollupJobsStore } from '../../../crud_app/store'; +import { JobList } from '../../../crud_app/sections/job_list'; import { wrapComponent } from './setup_context'; diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/setup_context.tsx b/x-pack/plugins/rollup/public/test/client_integration/helpers/setup_context.tsx similarity index 100% rename from x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/setup_context.tsx rename to x-pack/plugins/rollup/public/test/client_integration/helpers/setup_context.tsx diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/setup_environment.ts b/x-pack/plugins/rollup/public/test/client_integration/helpers/setup_environment.ts similarity index 100% rename from x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/setup_environment.ts rename to x-pack/plugins/rollup/public/test/client_integration/helpers/setup_environment.ts diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_clone.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_clone.test.js similarity index 93% rename from x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_clone.test.js rename to x-pack/plugins/rollup/public/test/client_integration/job_create_clone.test.js index b7c98ed179c7ab..7b61a03dcde456 100644 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_clone.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_clone.test.js @@ -4,11 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import { setHttp } from '../../public/crud_app/services'; +import { setHttp } from '../../crud_app/services'; import { mockHttpRequest, pageHelpers, nextTick } from './helpers'; import { JOB_TO_CLONE, JOB_CLONE_INDEX_PATTERN_CHECK } from './helpers/constants'; - -jest.mock('ui/new_platform'); +import { coreMock } from '../../../../../../src/core/public/mocks'; jest.mock('lodash/function/debounce', () => fn => fn); @@ -23,23 +22,23 @@ describe('Cloning a rollup job through create job wizard', () => { let form; let table; let actions; - let npStart; + let startMock; beforeAll(() => { - npStart = require('ui/new_platform').npStart; // eslint-disable-line - setHttp(npStart.core.http); + startMock = coreMock.createStart(); + setHttp(startMock.http); }); beforeEach(() => { - mockHttpRequest(npStart.core.http, { indxPatternVldtResp: JOB_CLONE_INDEX_PATTERN_CHECK }); + mockHttpRequest(startMock.http, { indxPatternVldtResp: JOB_CLONE_INDEX_PATTERN_CHECK }); ({ exists, find, form, actions, table } = setup()); }); afterEach(() => { - npStart.core.http.get.mockClear(); - npStart.core.http.post.mockClear(); - npStart.core.http.put.mockClear(); + startMock.http.get.mockClear(); + startMock.http.post.mockClear(); + startMock.http.put.mockClear(); }); it('should have fields correctly pre-populated', async () => { diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_date_histogram.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_date_histogram.test.js similarity index 88% rename from x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_date_histogram.test.js rename to x-pack/plugins/rollup/public/test/client_integration/job_create_date_histogram.test.js index b8ec7d9f85d009..095609ac2b2d77 100644 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_date_histogram.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_date_histogram.test.js @@ -6,10 +6,9 @@ import moment from 'moment-timezone'; -import { setHttp } from '../../public/crud_app/services'; +import { setHttp } from '../../crud_app/services'; import { mockHttpRequest, pageHelpers } from './helpers'; - -jest.mock('ui/new_platform'); +import { coreMock } from '../../../../../../src/core/public/mocks'; jest.mock('lodash/function/debounce', () => fn => fn); @@ -22,23 +21,23 @@ describe('Create Rollup Job, step 2: Date histogram', () => { let goToStep; let form; let getEuiStepsHorizontalActive; - let npStart; + let startMock; beforeAll(() => { - npStart = require('ui/new_platform').npStart; // eslint-disable-line - setHttp(npStart.core.http); + startMock = coreMock.createStart(); + setHttp(startMock.http); }); beforeEach(() => { // Set "default" mock responses by not providing any arguments - mockHttpRequest(npStart.core.http); + mockHttpRequest(startMock.http); ({ find, exists, actions, form, getEuiStepsHorizontalActive, goToStep } = setup()); }); afterEach(() => { - npStart.core.http.get.mockClear(); - npStart.core.http.post.mockClear(); - npStart.core.http.put.mockClear(); + startMock.http.get.mockClear(); + startMock.http.post.mockClear(); + startMock.http.put.mockClear(); }); describe('layout', () => { @@ -73,7 +72,7 @@ describe('Create Rollup Job, step 2: Date histogram', () => { describe('Date field select', () => { it('should set the options value from the index pattern', async () => { const dateFields = ['field1', 'field2', 'field3']; - mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { dateFields } }); + mockHttpRequest(startMock.http, { indxPatternVldtResp: { dateFields } }); await goToStep(2); @@ -85,7 +84,7 @@ describe('Create Rollup Job, step 2: Date histogram', () => { it('should sort the options in ascending order', async () => { const dateFields = ['field3', 'field2', 'field1']; - mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { dateFields } }); + mockHttpRequest(startMock.http, { indxPatternVldtResp: { dateFields } }); await goToStep(2); diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_histogram.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_histogram.test.js similarity index 91% rename from x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_histogram.test.js rename to x-pack/plugins/rollup/public/test/client_integration/job_create_histogram.test.js index c4b5d753f1a262..141aa068435567 100644 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_histogram.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_histogram.test.js @@ -4,10 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { setHttp } from '../../public/crud_app/services'; +import { setHttp } from '../../crud_app/services'; import { mockHttpRequest, pageHelpers } from './helpers'; - -jest.mock('ui/new_platform'); +import { coreMock } from '../../../../../../src/core/public/mocks'; jest.mock('lodash/function/debounce', () => fn => fn); @@ -21,24 +20,24 @@ describe('Create Rollup Job, step 4: Histogram', () => { let goToStep; let table; let form; - let npStart; + let startMock; beforeAll(() => { - npStart = require('ui/new_platform').npStart; // eslint-disable-line - setHttp(npStart.core.http); + startMock = coreMock.createStart(); + setHttp(startMock.http); }); beforeEach(() => { // Set "default" mock responses by not providing any arguments - mockHttpRequest(npStart.core.http); + mockHttpRequest(startMock.http); ({ find, exists, actions, getEuiStepsHorizontalActive, goToStep, table, form } = setup()); }); afterEach(() => { - npStart.core.http.get.mockClear(); - npStart.core.http.post.mockClear(); - npStart.core.http.put.mockClear(); + startMock.http.get.mockClear(); + startMock.http.post.mockClear(); + startMock.http.put.mockClear(); }); const numericFields = ['a-numericField', 'b-numericField']; @@ -111,7 +110,7 @@ describe('Create Rollup Job, step 4: Histogram', () => { describe('when no histogram fields are availalbe', () => { it('should indicate it to the user', async () => { - mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { numericFields: [] } }); + mockHttpRequest(startMock.http, { indxPatternVldtResp: { numericFields: [] } }); await goToStepAndOpenFieldChooser(); const { tableCellsValues } = table.getMetaData('rollupJobHistogramFieldChooser-table'); @@ -122,7 +121,7 @@ describe('Create Rollup Job, step 4: Histogram', () => { describe('when histogram fields are available', () => { beforeEach(async () => { - mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { numericFields } }); + mockHttpRequest(startMock.http, { indxPatternVldtResp: { numericFields } }); await goToStepAndOpenFieldChooser(); }); @@ -156,7 +155,7 @@ describe('Create Rollup Job, step 4: Histogram', () => { it('should have a delete button on each row to remove an histogram field', async () => { // First let's add a term to the list - mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { numericFields } }); + mockHttpRequest(startMock.http, { indxPatternVldtResp: { numericFields } }); await goToStepAndOpenFieldChooser(); const { rows: fieldChooserRows } = table.getMetaData('rollupJobHistogramFieldChooser-table'); fieldChooserRows[0].reactWrapper.simulate('click'); @@ -183,7 +182,7 @@ describe('Create Rollup Job, step 4: Histogram', () => { }; beforeEach(async () => { - mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { numericFields } }); + mockHttpRequest(startMock.http, { indxPatternVldtResp: { numericFields } }); await goToStep(4); addHistogramFieldToList(); }); diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_logistics.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_logistics.test.js similarity index 96% rename from x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_logistics.test.js rename to x-pack/plugins/rollup/public/test/client_integration/job_create_logistics.test.js index a032adacdda433..c66b3a698a0f95 100644 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_logistics.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_logistics.test.js @@ -13,10 +13,9 @@ import { YEAR, } from '../../../../../../src/plugins/es_ui_shared/public'; import { indexPatterns } from '../../../../../../src/plugins/data/public'; -import { setHttp } from '../../public/crud_app/services'; +import { setHttp } from '../../crud_app/services'; import { mockHttpRequest, pageHelpers } from './helpers'; - -jest.mock('ui/new_platform'); +import { coreMock } from '../../../../../../src/core/public/mocks'; jest.mock('lodash/function/debounce', () => fn => fn); @@ -28,24 +27,24 @@ describe('Create Rollup Job, step 1: Logistics', () => { let actions; let form; let getEuiStepsHorizontalActive; - let npStart; + let startMock; beforeAll(() => { - npStart = require('ui/new_platform').npStart; // eslint-disable-line - setHttp(npStart.core.http); + startMock = coreMock.createStart(); + setHttp(startMock.http); }); beforeEach(() => { // Set "default" mock responses by not providing any arguments - mockHttpRequest(npStart.core.http); + mockHttpRequest(startMock.http); ({ find, exists, actions, form, getEuiStepsHorizontalActive } = setup()); }); afterEach(() => { - npStart.core.http.get.mockClear(); - npStart.core.http.post.mockClear(); - npStart.core.http.put.mockClear(); + startMock.http.get.mockClear(); + startMock.http.post.mockClear(); + startMock.http.put.mockClear(); }); it('should have the horizontal step active on "Logistics"', () => { @@ -97,14 +96,14 @@ describe('Create Rollup Job, step 1: Logistics', () => { }); it('should not allow an unknown index pattern', async () => { - mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { doesMatchIndices: false } }); + mockHttpRequest(startMock.http, { indxPatternVldtResp: { doesMatchIndices: false } }); await form.setInputValue('rollupIndexPattern', 'unknown', true); actions.clickNextStep(); expect(form.getErrorsMessages()).toContain("Index pattern doesn't match any indices."); }); it('should not allow an index pattern without time fields', async () => { - mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { dateFields: [] } }); + mockHttpRequest(startMock.http, { indxPatternVldtResp: { dateFields: [] } }); await form.setInputValue('rollupIndexPattern', 'abc', true); actions.clickNextStep(); expect(form.getErrorsMessages()).toContain( @@ -113,7 +112,7 @@ describe('Create Rollup Job, step 1: Logistics', () => { }); it('should not allow an index pattern that matches a rollup index', async () => { - mockHttpRequest(npStart.core.http, { + mockHttpRequest(startMock.http, { indxPatternVldtResp: { doesMatchRollupIndices: true }, }); await form.setInputValue('rollupIndexPattern', 'abc', true); diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_metrics.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_metrics.test.js similarity index 95% rename from x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_metrics.test.js rename to x-pack/plugins/rollup/public/test/client_integration/job_create_metrics.test.js index a72dc8b25c0839..1e9dd88648da65 100644 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_metrics.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_metrics.test.js @@ -4,10 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { setHttp } from '../../public/crud_app/services'; +import { setHttp } from '../../crud_app/services'; import { mockHttpRequest, pageHelpers } from './helpers'; - -jest.mock('ui/new_platform'); +import { coreMock } from '../../../../../../src/core/public/mocks'; jest.mock('lodash/function/debounce', () => fn => fn); @@ -21,24 +20,24 @@ describe('Create Rollup Job, step 5: Metrics', () => { let goToStep; let table; let metrics; - let npStart; + let startMock; beforeAll(() => { - npStart = require('ui/new_platform').npStart; // eslint-disable-line - setHttp(npStart.core.http); + startMock = coreMock.createStart(); + setHttp(startMock.http); }); beforeEach(() => { // Set "default" mock responses by not providing any arguments - mockHttpRequest(npStart.core.http); + mockHttpRequest(startMock.http); ({ find, exists, actions, getEuiStepsHorizontalActive, goToStep, table, metrics } = setup()); }); afterEach(() => { - npStart.core.http.get.mockClear(); - npStart.core.http.post.mockClear(); - npStart.core.http.put.mockClear(); + startMock.http.get.mockClear(); + startMock.http.post.mockClear(); + startMock.http.put.mockClear(); }); const numericFields = ['a-numericField', 'c-numericField']; @@ -112,7 +111,7 @@ describe('Create Rollup Job, step 5: Metrics', () => { describe('table', () => { beforeEach(async () => { - mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { numericFields, dateFields } }); + mockHttpRequest(startMock.http, { indxPatternVldtResp: { numericFields, dateFields } }); await goToStepAndOpenFieldChooser(); }); @@ -169,7 +168,7 @@ describe('Create Rollup Job, step 5: Metrics', () => { describe('when fields are added', () => { beforeEach(async () => { - mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { numericFields, dateFields } }); + mockHttpRequest(startMock.http, { indxPatternVldtResp: { numericFields, dateFields } }); await goToStepAndOpenFieldChooser(); }); @@ -260,7 +259,7 @@ describe('Create Rollup Job, step 5: Metrics', () => { let getFieldListTableRows; beforeEach(async () => { - mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { numericFields, dateFields } }); + mockHttpRequest(startMock.http, { indxPatternVldtResp: { numericFields, dateFields } }); await goToStep(5); await addFieldToList('numeric'); diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_review.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_review.test.js similarity index 71% rename from x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_review.test.js rename to x-pack/plugins/rollup/public/test/client_integration/job_create_review.test.js index 0fa9509368d3f7..d625b8f11208f7 100644 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_review.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_review.test.js @@ -6,13 +6,20 @@ import { pageHelpers, mockHttpRequest } from './helpers'; import { first } from 'lodash'; -import { setHttp } from '../../public/crud_app/services'; +import { setHttp } from '../../crud_app/services'; import { JOBS } from './helpers/constants'; - -jest.mock('ui/new_platform'); +import { coreMock } from '../../../../../../src/core/public/mocks'; jest.mock('lodash/function/debounce', () => fn => fn); +jest.mock('../../kibana_services', () => { + const services = require.requireActual('../../kibana_services'); + return { + ...services, + getUiStatsReporter: jest.fn(() => () => {}), + }; +}); + const { setup } = pageHelpers.jobCreate; describe('Create Rollup Job, step 6: Review', () => { @@ -23,23 +30,23 @@ describe('Create Rollup Job, step 6: Review', () => { let goToStep; let table; let form; - let npStart; + let startMock; beforeAll(() => { - npStart = require('ui/new_platform').npStart; // eslint-disable-line - setHttp(npStart.core.http); + startMock = coreMock.createStart(); + setHttp(startMock.http); }); beforeEach(() => { // Set "default" mock responses by not providing any arguments - mockHttpRequest(npStart.core.http); + mockHttpRequest(startMock.http); ({ find, exists, actions, getEuiStepsHorizontalActive, goToStep, table, form } = setup()); }); afterEach(() => { - npStart.core.http.get.mockClear(); - npStart.core.http.post.mockClear(); - npStart.core.http.put.mockClear(); + startMock.http.get.mockClear(); + startMock.http.post.mockClear(); + startMock.http.put.mockClear(); }); describe('layout', () => { @@ -84,7 +91,7 @@ describe('Create Rollup Job, step 6: Review', () => { }); it('should have a "Summary", "Terms" & "Request" tab if a term aggregation was added', async () => { - mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { numericFields: ['my-field'] } }); + mockHttpRequest(startMock.http, { indxPatternVldtResp: { numericFields: ['my-field'] } }); await goToStep(3); selectFirstField('Terms'); @@ -96,7 +103,7 @@ describe('Create Rollup Job, step 6: Review', () => { }); it('should have a "Summary", "Histogram" & "Request" tab if a histogram field was added', async () => { - mockHttpRequest(npStart.core.http, { indxPatternVldtResp: { numericFields: ['a-field'] } }); + mockHttpRequest(startMock.http, { indxPatternVldtResp: { numericFields: ['a-field'] } }); await goToStep(4); selectFirstField('Histogram'); form.setInputValue('rollupJobCreateHistogramInterval', 3); // set an interval @@ -108,7 +115,7 @@ describe('Create Rollup Job, step 6: Review', () => { }); it('should have a "Summary", "Metrics" & "Request" tab if a histogram field was added', async () => { - mockHttpRequest(npStart.core.http, { + mockHttpRequest(startMock.http, { indxPatternVldtResp: { numericFields: ['a-field'], dateFields: ['b-field'], @@ -130,28 +137,28 @@ describe('Create Rollup Job, step 6: Review', () => { describe('without starting job after creation', () => { it('should call the "create" Api server endpoint', async () => { - mockHttpRequest(npStart.core.http, { + mockHttpRequest(startMock.http, { createdJob: first(JOBS.jobs), }); await goToStep(6); - expect(npStart.core.http.put).not.toHaveBeenCalledWith(jobCreateApiPath); // make sure it hasn't been called - expect(npStart.core.http.get).not.toHaveBeenCalledWith(jobStartApiPath); // make sure it hasn't been called + expect(startMock.http.put).not.toHaveBeenCalledWith(jobCreateApiPath); // make sure it hasn't been called + expect(startMock.http.get).not.toHaveBeenCalledWith(jobStartApiPath); // make sure it hasn't been called actions.clickSave(); - // Given the following anti-jitter sleep x-pack/legacy/plugins/rollup/public/crud_app/store/actions/create_job.js + // Given the following anti-jitter sleep x-pack/plugins/rollup/public/crud_app/store/actions/create_job.js // we add a longer sleep here :( await new Promise(res => setTimeout(res, 750)); - expect(npStart.core.http.put).toHaveBeenCalledWith(jobCreateApiPath, expect.anything()); // It has been called! - expect(npStart.core.http.get).not.toHaveBeenCalledWith(jobStartApiPath); // It has still not been called! + expect(startMock.http.put).toHaveBeenCalledWith(jobCreateApiPath, expect.anything()); // It has been called! + expect(startMock.http.get).not.toHaveBeenCalledWith(jobStartApiPath); // It has still not been called! }); }); describe('with starting job after creation', () => { it('should call the "create" and "start" Api server endpoints', async () => { - mockHttpRequest(npStart.core.http, { + mockHttpRequest(startMock.http, { createdJob: first(JOBS.jobs), }); @@ -161,14 +168,14 @@ describe('Create Rollup Job, step 6: Review', () => { target: { checked: true }, }); - expect(npStart.core.http.post).not.toHaveBeenCalledWith(jobStartApiPath); // make sure it hasn't been called + expect(startMock.http.post).not.toHaveBeenCalledWith(jobStartApiPath); // make sure it hasn't been called actions.clickSave(); - // Given the following anti-jitter sleep x-pack/legacy/plugins/rollup/public/crud_app/store/actions/create_job.js + // Given the following anti-jitter sleep x-pack/plugins/rollup/public/crud_app/store/actions/create_job.js // we add a longer sleep here :( await new Promise(res => setTimeout(res, 750)); - expect(npStart.core.http.post).toHaveBeenCalledWith(jobStartApiPath, expect.anything()); // It has been called! + expect(startMock.http.post).toHaveBeenCalledWith(jobStartApiPath, expect.anything()); // It has been called! }); }); }); diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_terms.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_create_terms.test.js similarity index 93% rename from x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_terms.test.js rename to x-pack/plugins/rollup/public/test/client_integration/job_create_terms.test.js index f111a7df2c2501..61993f30928400 100644 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_terms.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_create_terms.test.js @@ -4,10 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { setHttp } from '../../public/crud_app/services'; +import { setHttp } from '../../crud_app/services'; import { pageHelpers, mockHttpRequest } from './helpers'; - -jest.mock('ui/new_platform'); +import { coreMock } from '../../../../../../src/core/public/mocks'; jest.mock('lodash/function/debounce', () => fn => fn); @@ -20,22 +19,22 @@ describe('Create Rollup Job, step 3: Terms', () => { let getEuiStepsHorizontalActive; let goToStep; let table; - let npStart; + let startMock; beforeAll(() => { - npStart = require('ui/new_platform').npStart; // eslint-disable-line - setHttp(npStart.core.http); + startMock = coreMock.createStart(); + setHttp(startMock.http); }); beforeEach(() => { // Set "default" mock responses by not providing any arguments - mockHttpRequest(npStart.core.http); + mockHttpRequest(startMock.http); ({ find, exists, actions, getEuiStepsHorizontalActive, goToStep, table } = setup()); }); afterEach(() => { - npStart.core.http.get.mockClear(); + startMock.http.get.mockClear(); }); const numericFields = ['a-numericField', 'c-numericField']; @@ -109,7 +108,7 @@ describe('Create Rollup Job, step 3: Terms', () => { describe('when no terms are available', () => { it('should indicate it to the user', async () => { - mockHttpRequest(npStart.core.http, { + mockHttpRequest(startMock.http, { indxPatternVldtResp: { numericFields: [], keywordFields: [], @@ -125,7 +124,7 @@ describe('Create Rollup Job, step 3: Terms', () => { describe('when terms are available', () => { beforeEach(async () => { - mockHttpRequest(npStart.core.http, { + mockHttpRequest(startMock.http, { indxPatternVldtResp: { numericFields, keywordFields, @@ -171,7 +170,7 @@ describe('Create Rollup Job, step 3: Terms', () => { it('should have a delete button on each row to remove a term', async () => { // First let's add a term to the list - mockHttpRequest(npStart.core.http, { + mockHttpRequest(startMock.http, { indxPatternVldtResp: { numericFields, keywordFields, diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_list.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_list.test.js similarity index 77% rename from x-pack/legacy/plugins/rollup/__jest__/client_integration/job_list.test.js rename to x-pack/plugins/rollup/public/test/client_integration/job_list.test.js index a9e474cf0b5598..c6988236d6b7c9 100644 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_list.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_list.test.js @@ -4,20 +4,27 @@ * you may not use this file except in compliance with the Elastic License. */ -import { getRouter, setHttp } from '../../public/crud_app/services'; +import { getRouter, setHttp } from '../../crud_app/services'; import { mockHttpRequest, pageHelpers, nextTick } from './helpers'; import { JOBS } from './helpers/constants'; +import { coreMock } from '../../../../../../src/core/public/mocks'; -jest.mock('ui/new_platform'); - -jest.mock('../../public/crud_app/services', () => { - const services = require.requireActual('../../public/crud_app/services'); +jest.mock('../../crud_app/services', () => { + const services = require.requireActual('../../crud_app/services'); return { ...services, getRouterLinkProps: link => ({ href: link }), }; }); +jest.mock('../../kibana_services', () => { + const services = require.requireActual('../../kibana_services'); + return { + ...services, + getUiStatsReporter: jest.fn(() => () => {}), + }; +}); + const { setup } = pageHelpers.jobList; describe('', () => { @@ -25,15 +32,15 @@ describe('', () => { let component; let table; let exists; - let npStart; + let startMock; beforeAll(() => { - npStart = require('ui/new_platform').npStart; // eslint-disable-line - setHttp(npStart.core.http); + startMock = coreMock.createStart(); + setHttp(startMock.http); }); beforeEach(async () => { - mockHttpRequest(npStart.core.http, { jobs: JOBS }); + mockHttpRequest(startMock.http, { jobs: JOBS }); ({ component, exists, table } = setup()); @@ -42,7 +49,7 @@ describe('', () => { }); afterEach(() => { - npStart.core.http.get.mockClear(); + startMock.http.get.mockClear(); }); test('should open the detail panel when clicking on a job in the table', () => { diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_list_clone.test.js b/x-pack/plugins/rollup/public/test/client_integration/job_list_clone.test.js similarity index 74% rename from x-pack/legacy/plugins/rollup/__jest__/client_integration/job_list_clone.test.js rename to x-pack/plugins/rollup/public/test/client_integration/job_list_clone.test.js index 8a36af83def4c8..bdf57a555cdad6 100644 --- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_list_clone.test.js +++ b/x-pack/plugins/rollup/public/test/client_integration/job_list_clone.test.js @@ -6,14 +6,21 @@ import { mockHttpRequest, pageHelpers, nextTick } from './helpers'; import { JOB_TO_CLONE, JOB_CLONE_INDEX_PATTERN_CHECK } from './helpers/constants'; -import { getRouter } from '../../public/crud_app/services/routing'; -import { setHttp } from '../../public/crud_app/services'; -import { CRUD_APP_BASE_PATH } from '../../public/crud_app/constants'; - -jest.mock('ui/new_platform'); +import { getRouter } from '../../crud_app/services/routing'; +import { setHttp } from '../../crud_app/services'; +import { CRUD_APP_BASE_PATH } from '../../crud_app/constants'; +import { coreMock } from '../../../../../../src/core/public/mocks'; jest.mock('lodash/function/debounce', () => fn => fn); +jest.mock('../../kibana_services', () => { + const services = require.requireActual('../../kibana_services'); + return { + ...services, + getUiStatsReporter: jest.fn(() => () => {}), + }; +}); + const { setup } = pageHelpers.jobList; describe('Smoke test cloning an existing rollup job from job list', () => { @@ -21,15 +28,15 @@ describe('Smoke test cloning an existing rollup job from job list', () => { let find; let component; let exists; - let npStart; + let startMock; beforeAll(() => { - npStart = require('ui/new_platform').npStart; // eslint-disable-line - setHttp(npStart.core.http); + startMock = coreMock.createStart(); + setHttp(startMock.http); }); beforeEach(async () => { - mockHttpRequest(npStart.core.http, { + mockHttpRequest(startMock.http, { jobs: JOB_TO_CLONE, indxPatternVldtResp: JOB_CLONE_INDEX_PATTERN_CHECK, }); @@ -41,7 +48,7 @@ describe('Smoke test cloning an existing rollup job from job list', () => { }); afterEach(() => { - npStart.core.http.get.mockClear(); + startMock.http.get.mockClear(); }); it('should navigate to create view with default values set', async () => { diff --git a/x-pack/legacy/plugins/rollup/public/visualize/agg_type_field_filter.js b/x-pack/plugins/rollup/public/visualize/agg_type_field_filter.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/visualize/agg_type_field_filter.js rename to x-pack/plugins/rollup/public/visualize/agg_type_field_filter.js diff --git a/x-pack/legacy/plugins/rollup/public/visualize/agg_type_filter.js b/x-pack/plugins/rollup/public/visualize/agg_type_filter.js similarity index 100% rename from x-pack/legacy/plugins/rollup/public/visualize/agg_type_filter.js rename to x-pack/plugins/rollup/public/visualize/agg_type_filter.js diff --git a/x-pack/plugins/rollup/server/plugin.ts b/x-pack/plugins/rollup/server/plugin.ts index fa05b8d1307d61..ea6d197e22029d 100644 --- a/x-pack/plugins/rollup/server/plugin.ts +++ b/x-pack/plugins/rollup/server/plugin.ts @@ -4,7 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Plugin, PluginInitializerContext } from 'src/core/server'; +import { CoreSetup, Plugin, PluginInitializerContext } from 'src/core/server'; +import { i18n } from '@kbn/i18n'; +import { schema } from '@kbn/config-schema'; +import { CONFIG_ROLLUPS } from '../common'; export class RollupPlugin implements Plugin { private readonly initContext: PluginInitializerContext; @@ -13,7 +16,23 @@ export class RollupPlugin implements Plugin { this.initContext = initContext; } - public setup() { + public setup(core: CoreSetup) { + core.uiSettings.register({ + [CONFIG_ROLLUPS]: { + name: i18n.translate('xpack.rollupJobs.rollupIndexPatternsTitle', { + defaultMessage: 'Enable rollup index patterns', + }), + value: true, + description: i18n.translate('xpack.rollupJobs.rollupIndexPatternsDescription', { + defaultMessage: `Enable the creation of index patterns which capture rollup indices, + which in turn enable visualizations based on rollup data. Refresh + the page to apply the changes.`, + }), + category: ['rollups'], + schema: schema.boolean(), + }, + }); + return { __legacy: { config: this.initContext.config, diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts index 469f91c8211cc7..8c97d4436a561f 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -448,7 +448,7 @@ export const getResult = (): RuleAlertType => ({ references: ['http://www.example.com', 'https://ww.example.com'], note: '# Investigative notes', version: 1, - lists: [ + exceptions_list: [ { field: 'source.ip', values_operator: 'included', diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/__mocks__/utils.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/__mocks__/utils.ts index c929b0718207d6..6f628170271f31 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/__mocks__/utils.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/__mocks__/utils.ts @@ -138,7 +138,7 @@ export const getOutputRuleAlertForRest = (): Omit< ], }, ], - lists: [ + exceptions_list: [ { field: 'source.ip', values_operator: 'included', diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts index a40952c078a379..2d7ddb79e5af55 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts @@ -86,7 +86,7 @@ export const createRulesBulkRoute = (router: IRouter) => { timeline_id: timelineId, timeline_title: timelineTitle, version, - lists, + exceptions_list, } = payloadRule; const ruleIdOrUuid = ruleId ?? uuid.v4(); try { @@ -143,7 +143,7 @@ export const createRulesBulkRoute = (router: IRouter) => { references, note, version, - lists, + exceptions_list, actions: throttle === 'rule' ? actions : [], // Only enable actions if throttle is set to rule, otherwise we are a notification and should not enable it, }); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts index 19c5d479deb720..1f0896686aca05 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/create_rules_route.ts @@ -66,7 +66,7 @@ export const createRulesRoute = (router: IRouter): void => { type, references, note, - lists, + exceptions_list, } = request.body; const siemResponse = buildSiemResponse(response); @@ -131,7 +131,7 @@ export const createRulesRoute = (router: IRouter): void => { references, note, version: 1, - lists, + exceptions_list, actions: throttle === 'rule' ? actions : [], // Only enable actions if throttle is rule, otherwise we are a notification and should not enable it, }); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.ts index 58da27916c1985..527fab786910fc 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.ts @@ -138,7 +138,7 @@ export const importRulesRoute = (router: IRouter, config: ConfigType) => { timeline_id: timelineId, timeline_title: timelineTitle, version, - lists, + exceptions_list, } = parsedRule; try { @@ -195,7 +195,7 @@ export const importRulesRoute = (router: IRouter, config: ConfigType) => { references, note, version, - lists, + exceptions_list, actions: [], // Actions are not imported nor exported at this time }); resolve({ rule_id: ruleId, status_code: 200 }); @@ -232,7 +232,7 @@ export const importRulesRoute = (router: IRouter, config: ConfigType) => { references, note, version, - lists, + exceptions_list, anomalyThreshold, machineLearningJobId, }); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts index 8f319063b2a9a9..6db91d74294fc6 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts @@ -81,7 +81,7 @@ export const updateRulesBulkRoute = (router: IRouter) => { references, note, version, - lists, + exceptions_list, } = payloadRule; const finalIndex = outputIndex ?? siemClient.signalsIndex; const idOrRuleIdOrUnknown = id ?? ruleId ?? '(unknown id)'; @@ -121,7 +121,7 @@ export const updateRulesBulkRoute = (router: IRouter) => { references, note, version, - lists, + exceptions_list, actions, }); if (rule != null) { diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts index 7d69af4bcbd9bf..7dbbe5a22ab46a 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/update_rules_route.ts @@ -67,7 +67,7 @@ export const updateRulesRoute = (router: IRouter) => { references, note, version, - lists, + exceptions_list, } = request.body; const siemResponse = buildSiemResponse(response); @@ -117,7 +117,7 @@ export const updateRulesRoute = (router: IRouter) => { references, note, version, - lists, + exceptions_list, actions: throttle === 'rule' ? actions : [], // Only enable actions if throttle is rule, otherwise we are a notification and should not enable it }); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts index 49d40354e68afa..67b0c4462655c2 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/utils.ts @@ -148,7 +148,7 @@ export const transformAlertToRule = ( last_failure_message: ruleStatus?.attributes.lastFailureMessage, last_success_message: ruleStatus?.attributes.lastSuccessMessage, // TODO: (LIST-FEATURE) Remove hasListsFeature() check once we have lists available for a release - lists: hasListsFeature() ? alert.params.lists : null, + exceptions_list: hasListsFeature() ? alert.params.exceptions_list : null, }); }; diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/validate.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/validate.test.ts index 3de801a5b6b173..9069202d4d3aa5 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/validate.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/validate.test.ts @@ -71,7 +71,7 @@ export const ruleOutput: RulesSchema = { }, }, ], - lists: [ + exceptions_list: [ { field: 'source.ip', values_operator: 'included', diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/validate.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/validate.ts index c207d075331b6e..cfba40fc225a24 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/validate.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/rules/validate.ts @@ -9,8 +9,9 @@ import { fold } from 'fp-ts/lib/Either'; import { pipe } from 'fp-ts/lib/pipeable'; import * as t from 'io-ts'; +import { formatErrors } from '../../../../utils/build_validation/format_errors'; +import { exactCheck } from '../../../../utils/build_validation/exact_check'; import { PartialAlert, FindResult } from '../../../../../../alerting/server'; -import { formatErrors } from '../schemas/response/utils'; import { isAlertType, IRuleSavedAttributesSavedObjectAttributes, @@ -19,7 +20,6 @@ import { import { OutputRuleAlertRest } from '../../types'; import { createBulkErrorObject, BulkError } from '../utils'; import { rulesSchema, RulesSchema } from '../schemas/response/rules_schema'; -import { exactCheck } from '../schemas/response/exact_check'; import { transformFindAlerts, transform, transformAlertToRule } from './utils'; import { findRulesSchema } from '../schemas/response/find_rules_schema'; import { RuleActions } from '../../rule_actions/types'; diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts index 346da53736ad6c..226dea7c20344b 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.test.ts @@ -1542,8 +1542,8 @@ describe('add prepackaged rules schema', () => { // on demand. Since they are per module, we have a an issue where the ENV variables do not take effect. It is better we change all the // schema's to be function calls to avoid global side effects or just wait until the feature is available. If you want to test this early, // you can remove the .skip and set your env variable of export ELASTIC_XPACK_SIEM_LISTS_FEATURE=true locally - describe.skip('lists', () => { - test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and lists] does validate', () => { + describe.skip('exceptions_list', () => { + test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and exceptions_list] does validate', () => { expect( addPrepackagedRulesSchema.validate>({ rule_id: 'rule-1', @@ -1558,7 +1558,7 @@ describe('add prepackaged rules schema', () => { risk_score: 50, note: '# some markdown', version: 1, - lists: [ + exceptions_list: [ { field: 'source.ip', values_operator: 'included', @@ -1594,7 +1594,7 @@ describe('add prepackaged rules schema', () => { ).toBeFalsy(); }); - test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and empty lists] does validate', () => { + test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and empty exceptions_list] does validate', () => { expect( addPrepackagedRulesSchema.validate>({ rule_id: 'rule-1', @@ -1608,15 +1608,15 @@ describe('add prepackaged rules schema', () => { type: 'query', risk_score: 50, note: '# some markdown', - lists: [], + exceptions_list: [], version: 1, }).error ).toBeFalsy(); }); - test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and invalid lists] does NOT validate', () => { + test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and invalid exceptions_list] does NOT validate', () => { expect( - addPrepackagedRulesSchema.validate>>({ + addPrepackagedRulesSchema.validate>>({ rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1628,17 +1628,17 @@ describe('add prepackaged rules schema', () => { type: 'query', risk_score: 50, note: '# some markdown', - lists: [{ invalid_value: 'invalid value' }], + exceptions_list: [{ invalid_value: 'invalid value' }], version: 1, }).error.message ).toEqual( - 'child "lists" fails because ["lists" at position 0 fails because [child "field" fails because ["field" is required]]]' + 'child "exceptions_list" fails because ["exceptions_list" at position 0 fails because [child "field" fails because ["field" is required]]]' ); }); - test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and non-existent lists] does validate with empty lists', () => { + test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and non-existent exceptions_list] does validate with empty exceptions_list', () => { expect( - addPrepackagedRulesSchema.validate>>({ + addPrepackagedRulesSchema.validate>>({ rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1651,7 +1651,7 @@ describe('add prepackaged rules schema', () => { risk_score: 50, note: '# some markdown', version: 1, - }).value.lists + }).value.exceptions_list ).toEqual([]); }); }); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.ts index 006fc81e3ee87a..0e82a9b979c7b9 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/add_prepackaged_rules_schema.ts @@ -114,5 +114,5 @@ export const addPrepackagedRulesSchema = Joi.object({ version: version.required(), // TODO: (LIST-FEATURE) Remove the hasListsFeatures once this is ready for release - lists: hasListsFeature() ? lists.default([]) : lists.forbidden().default([]), + exceptions_list: hasListsFeature() ? lists.default([]) : lists.forbidden().default([]), }); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts index 0d7b562b97b2cc..1e2941015b7355 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.test.ts @@ -1510,8 +1510,8 @@ describe('create rules schema', () => { // on demand. Since they are per module, we have a an issue where the ENV variables do not take effect. It is better we change all the // schema's to be function calls to avoid global side effects or just wait until the feature is available. If you want to test this early, // you can remove the .skip and set your env variable of export ELASTIC_XPACK_SIEM_LISTS_FEATURE=true locally - describe.skip('lists', () => { - test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and lists] does validate', () => { + describe.skip('exceptions_list', () => { + test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and exceptions_list] does validate', () => { expect( createRulesSchema.validate>({ rule_id: 'rule-1', @@ -1525,7 +1525,7 @@ describe('create rules schema', () => { type: 'query', risk_score: 50, note: '# some markdown', - lists: [ + exceptions_list: [ { field: 'source.ip', values_operator: 'included', @@ -1561,7 +1561,7 @@ describe('create rules schema', () => { ).toBeFalsy(); }); - test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and empty lists] does validate', () => { + test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and empty exceptions_list] does validate', () => { expect( createRulesSchema.validate>({ rule_id: 'rule-1', @@ -1575,14 +1575,14 @@ describe('create rules schema', () => { type: 'query', risk_score: 50, note: '# some markdown', - lists: [], + exceptions_list: [], }).error ).toBeFalsy(); }); - test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and invalid lists] does NOT validate', () => { + test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and invalid exceptions_list] does NOT validate', () => { expect( - createRulesSchema.validate>>({ + createRulesSchema.validate>>({ rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1594,16 +1594,16 @@ describe('create rules schema', () => { type: 'query', risk_score: 50, note: '# some markdown', - lists: [{ invalid_value: 'invalid value' }], + exceptions_list: [{ invalid_value: 'invalid value' }], }).error.message ).toEqual( - 'child "lists" fails because ["lists" at position 0 fails because [child "field" fails because ["field" is required]]]' + 'child "exceptions_list" fails because ["exceptions_list" at position 0 fails because [child "field" fails because ["field" is required]]]' ); }); - test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and non-existent lists] does validate with empty lists', () => { + test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and non-existent exceptions_list] does validate with empty exceptions_list', () => { expect( - createRulesSchema.validate>>({ + createRulesSchema.validate>>({ rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1615,7 +1615,7 @@ describe('create rules schema', () => { type: 'query', risk_score: 50, note: '# some markdown', - }).value.lists + }).value.exceptions_list ).toEqual([]); }); }); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.ts index 5213f3faaf4865..dec8b5ccbc790e 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/create_rules_schema.ts @@ -98,5 +98,5 @@ export const createRulesSchema = Joi.object({ version: version.default(1), // TODO: (LIST-FEATURE) Remove the hasListsFeatures once this is ready for release - lists: hasListsFeature() ? lists.default([]) : lists.forbidden().default([]), + exceptions_list: hasListsFeature() ? lists.default([]) : lists.forbidden().default([]), }); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts index b8d601b7438954..d28530ffb789e3 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.test.ts @@ -1729,8 +1729,8 @@ describe('import rules schema', () => { // on demand. Since they are per module, we have a an issue where the ENV variables do not take effect. It is better we change all the // schema's to be function calls to avoid global side effects or just wait until the feature is available. If you want to test this early, // you can remove the .skip and set your env variable of export ELASTIC_XPACK_SIEM_LISTS_FEATURE=true locally - describe.skip('lists', () => { - test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and lists] does validate', () => { + describe.skip('exceptions_list', () => { + test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and exceptions_list] does validate', () => { expect( importRulesSchema.validate>({ rule_id: 'rule-1', @@ -1744,7 +1744,7 @@ describe('import rules schema', () => { type: 'query', risk_score: 50, note: '# some markdown', - lists: [ + exceptions_list: [ { field: 'source.ip', values_operator: 'included', @@ -1780,7 +1780,7 @@ describe('import rules schema', () => { ).toBeFalsy(); }); - test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and empty lists] does validate', () => { + test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and empty exceptions_list] does validate', () => { expect( importRulesSchema.validate>({ rule_id: 'rule-1', @@ -1794,14 +1794,14 @@ describe('import rules schema', () => { type: 'query', risk_score: 50, note: '# some markdown', - lists: [], + exceptions_list: [], }).error ).toBeFalsy(); }); - test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and invalid lists] does NOT validate and lists is empty', () => { + test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and invalid exceptions_list] does NOT validate and exceptions_list is empty', () => { expect( - importRulesSchema.validate>>({ + importRulesSchema.validate>>({ rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1813,16 +1813,16 @@ describe('import rules schema', () => { type: 'query', risk_score: 50, note: '# some markdown', - lists: [{ invalid_value: 'invalid value' }], + exceptions_list: [{ invalid_value: 'invalid value' }], }).error.message ).toEqual( - 'child "lists" fails because ["lists" at position 0 fails because [child "field" fails because ["field" is required]]]' + 'child "exceptions_list" fails because ["exceptions_list" at position 0 fails because [child "field" fails because ["field" is required]]]' ); }); - test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and non-existent lists] does validate', () => { + test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and non-existent exceptions_list] does validate', () => { expect( - importRulesSchema.validate>>({ + importRulesSchema.validate>>({ rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1834,7 +1834,7 @@ describe('import rules schema', () => { type: 'query', risk_score: 50, note: '# some markdown', - }).value.lists + }).value.exceptions_list ).toEqual([]); }); }); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.ts index 56aa45659fda7e..d3c728ebac1a9d 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/import_rules_schema.ts @@ -119,7 +119,7 @@ export const importRulesSchema = Joi.object({ updated_by, // TODO: (LIST-FEATURE) Remove the hasListsFeatures once this is ready for release - lists: hasListsFeature() ? lists.default([]) : lists.forbidden().default([]), + exceptions_list: hasListsFeature() ? lists.default([]) : lists.forbidden().default([]), }); export const importRulesQuerySchema = Joi.object({ diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts index 02655e3972d819..755c0b2ccaa3f9 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.test.ts @@ -1213,8 +1213,8 @@ describe('patch rules schema', () => { // on demand. Since they are per module, we have a an issue where the ENV variables do not take effect. It is better we change all the // schema's to be function calls to avoid global side effects or just wait until the feature is available. If you want to test this early, // you can remove the .skip and set your env variable of export ELASTIC_XPACK_SIEM_LISTS_FEATURE=true locally - describe.skip('lists', () => { - test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and lists] does validate', () => { + describe.skip('exceptions_list', () => { + test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and exceptions_list] does validate', () => { expect( patchRulesSchema.validate>({ rule_id: 'rule-1', @@ -1228,7 +1228,7 @@ describe('patch rules schema', () => { type: 'query', risk_score: 50, note: '# some markdown', - lists: [ + exceptions_list: [ { field: 'source.ip', values_operator: 'included', @@ -1264,11 +1264,11 @@ describe('patch rules schema', () => { ).toBeFalsy(); }); - test('lists can be patched', () => { + test('exceptions_list can be patched', () => { expect( patchRulesSchema.validate>({ rule_id: 'some id', - lists: [ + exceptions_list: [ { field: 'source.ip', values_operator: 'included', @@ -1301,7 +1301,7 @@ describe('patch rules schema', () => { ).toBeFalsy(); }); - test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and empty lists] does validate', () => { + test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and empty exceptions_list] does validate', () => { expect( patchRulesSchema.validate>({ rule_id: 'rule-1', @@ -1315,14 +1315,14 @@ describe('patch rules schema', () => { type: 'query', risk_score: 50, note: '# some markdown', - lists: [], + exceptions_list: [], }).error ).toBeFalsy(); }); - test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and invalid lists] does NOT validate', () => { + test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and invalid exceptions_list] does NOT validate', () => { expect( - patchRulesSchema.validate>>({ + patchRulesSchema.validate>>({ rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1334,16 +1334,16 @@ describe('patch rules schema', () => { type: 'query', risk_score: 50, note: '# some markdown', - lists: [{ invalid_value: 'invalid value' }], + exceptions_list: [{ invalid_value: 'invalid value' }], }).error.message ).toEqual( - 'child "lists" fails because ["lists" at position 0 fails because [child "field" fails because ["field" is required]]]' + 'child "exceptions_list" fails because ["exceptions_list" at position 0 fails because [child "field" fails because ["field" is required]]]' ); }); - test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and non-existent lists] does validate with empty lists', () => { + test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and non-existent exceptions_list] does validate with empty exceptions_list', () => { expect( - patchRulesSchema.validate>>({ + patchRulesSchema.validate>>({ rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1355,7 +1355,7 @@ describe('patch rules schema', () => { type: 'query', risk_score: 50, note: '# some markdown', - }).value.lists + }).value.exceptions_list ).toEqual([]); }); }); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.ts index 52aefa29884c3d..503bc64df237c8 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/patch_rules_schema.ts @@ -78,5 +78,5 @@ export const patchRulesSchema = Joi.object({ version, // TODO: (LIST-FEATURE) Remove the hasListsFeatures once this is ready for release - lists: hasListsFeature() ? lists.default([]) : lists.forbidden().default([]), + exceptions_list: hasListsFeature() ? lists.default([]) : lists.forbidden().default([]), }).xor('id', 'rule_id'); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/__mocks__/utils.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/__mocks__/utils.ts index d5ea950d163f57..fef6bcf42e49f0 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/__mocks__/utils.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/__mocks__/utils.ts @@ -4,32 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import * as t from 'io-ts'; -import { fold } from 'fp-ts/lib/Either'; import { RulesSchema } from '../rules_schema'; import { RulesBulkSchema } from '../rules_bulk_schema'; import { ErrorSchema } from '../error_schema'; import { FindRulesSchema } from '../find_rules_schema'; -import { formatErrors } from '../utils'; -import { pipe } from 'fp-ts/lib/pipeable'; - -interface Message { - errors: t.Errors; - schema: T | {}; -} - -const onLeft = (errors: t.Errors): Message => { - return { schema: {}, errors }; -}; - -const onRight = (schema: T): Message => { - return { - schema, - errors: [], - }; -}; - -export const foldLeftRight = fold(onLeft, onRight); export const ANCHOR_DATE = '2020-02-20T03:57:54.037Z'; @@ -63,7 +41,7 @@ export const getBaseResponsePayload = (anchorDate: string = ANCHOR_DATE): RulesS language: 'kuery', rule_id: 'query-rule-id', interval: '5m', - lists: [ + exceptions_list: [ { field: 'source.ip', values_operator: 'included', @@ -127,18 +105,3 @@ export const getFindResponseSingle = (): FindRulesSchema => ({ total: 1, data: [getBaseResponsePayload()], }); - -/** - * Convenience utility to keep the error message handling within tests to be - * very concise. - * @param validation The validation to get the errors from - */ -export const getPaths = (validation: t.Validation): string[] => { - return pipe( - validation, - fold( - errors => formatErrors(errors), - () => ['no errors'] - ) - ); -}; diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/check_type_dependents.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/check_type_dependents.test.ts index 0eda2a7a13d96f..fbd2382e2826d4 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/check_type_dependents.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/check_type_dependents.test.ts @@ -15,17 +15,13 @@ import { addQueryFields, addMlFields, } from './check_type_dependents'; -import { - foldLeftRight, - getBaseResponsePayload, - getPaths, - getMlRuleResponsePayload, -} from './__mocks__/utils'; +import { getBaseResponsePayload, getMlRuleResponsePayload } from './__mocks__/utils'; import { left } from 'fp-ts/lib/Either'; -import { exactCheck } from './exact_check'; import { RulesSchema } from './rules_schema'; import { TypeAndTimelineOnly } from './type_timeline_only_schema'; import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../../feature_flags'; +import { foldLeftRight, getPaths } from '../../../../../utils/build_validation/__mocks__/utils'; +import { exactCheck } from '../../../../../utils/build_validation/exact_check'; describe('check_type_dependents', () => { beforeAll(() => { diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/error_schema.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/error_schema.test.ts index 11d8b85f259206..6e159a792edb66 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/error_schema.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/error_schema.test.ts @@ -7,10 +7,11 @@ import { left } from 'fp-ts/lib/Either'; import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck } from './exact_check'; -import { foldLeftRight, getErrorPayload, getPaths } from './__mocks__/utils'; +import { getErrorPayload } from './__mocks__/utils'; import { errorSchema, ErrorSchema } from './error_schema'; import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../../feature_flags'; +import { exactCheck } from '../../../../../utils/build_validation/exact_check'; +import { foldLeftRight, getPaths } from '../../../../../utils/build_validation/__mocks__/utils'; describe('error_schema', () => { beforeAll(() => { diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/find_rules_schema.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/find_rules_schema.test.ts index f5c1970ee8c55c..68b67db595d76d 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/find_rules_schema.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/find_rules_schema.test.ts @@ -5,17 +5,13 @@ */ import { findRulesSchema, FindRulesSchema } from './find_rules_schema'; -import { exactCheck } from './exact_check'; import { pipe } from 'fp-ts/lib/pipeable'; -import { - foldLeftRight, - getFindResponseSingle, - getBaseResponsePayload, - getPaths, -} from './__mocks__/utils'; +import { getFindResponseSingle, getBaseResponsePayload } from './__mocks__/utils'; import { left } from 'fp-ts/lib/Either'; import { RulesSchema } from './rules_schema'; import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../../feature_flags'; +import { getPaths, foldLeftRight } from '../../../../../utils/build_validation/__mocks__/utils'; +import { exactCheck } from '../../../../../utils/build_validation/exact_check'; describe('find_rules_schema', () => { beforeAll(() => { diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/import_rules_schema.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/import_rules_schema.test.ts index ce4bbf420a634b..b0b863ebbbc0b2 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/import_rules_schema.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/import_rules_schema.test.ts @@ -4,13 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { exactCheck } from './exact_check'; import { pipe } from 'fp-ts/lib/pipeable'; -import { foldLeftRight, getPaths } from './__mocks__/utils'; -import { left } from 'fp-ts/lib/Either'; +import { left, Either } from 'fp-ts/lib/Either'; import { ImportRulesSchema, importRulesSchema } from './import_rules_schema'; import { ErrorSchema } from './error_schema'; import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../../feature_flags'; +import { exactCheck } from '../../../../../utils/build_validation/exact_check'; +import { getPaths, foldLeftRight } from '../../../../../utils/build_validation/__mocks__/utils'; +import { Errors } from 'io-ts'; describe('import_rules_schema', () => { beforeAll(() => { @@ -79,13 +80,31 @@ describe('import_rules_schema', () => { }); test('it should NOT validate a success that is not a boolean', () => { + type UnsafeCastForTest = Either< + Errors, + { + success: string; + success_count: number; + errors: Array< + { + id?: string | undefined; + rule_id?: string | undefined; + } & { + error: { + status_code: number; + message: string; + }; + } + >; + } + >; const payload: Omit & { success: string } = { success: 'hello', success_count: 0, errors: [], }; const decoded = importRulesSchema.decode(payload); - const checked = exactCheck(payload, decoded); + const checked = exactCheck(payload, decoded as UnsafeCastForTest); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual(['Invalid value "hello" supplied to "success"']); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/prepackaged_rules_schema.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/prepackaged_rules_schema.test.ts index 46667826416e1f..827167c63fd58e 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/prepackaged_rules_schema.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/prepackaged_rules_schema.test.ts @@ -4,12 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import { exactCheck } from './exact_check'; import { pipe } from 'fp-ts/lib/pipeable'; -import { foldLeftRight, getPaths } from './__mocks__/utils'; import { left } from 'fp-ts/lib/Either'; import { PrePackagedRulesSchema, prePackagedRulesSchema } from './prepackaged_rules_schema'; import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../../feature_flags'; +import { exactCheck } from '../../../../../utils/build_validation/exact_check'; +import { foldLeftRight, getPaths } from '../../../../../utils/build_validation/__mocks__/utils'; describe('prepackaged_rules_schema', () => { beforeAll(() => { diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/prepackaged_rules_status_schema.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/prepackaged_rules_status_schema.test.ts index 1c270ff402f75e..a864667583c0a8 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/prepackaged_rules_status_schema.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/prepackaged_rules_status_schema.test.ts @@ -4,15 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import { exactCheck } from './exact_check'; import { pipe } from 'fp-ts/lib/pipeable'; -import { foldLeftRight, getPaths } from './__mocks__/utils'; import { left } from 'fp-ts/lib/Either'; import { PrePackagedRulesStatusSchema, prePackagedRulesStatusSchema, } from './prepackaged_rules_status_schema'; import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../../feature_flags'; +import { exactCheck } from '../../../../../utils/build_validation/exact_check'; +import { foldLeftRight, getPaths } from '../../../../../utils/build_validation/__mocks__/utils'; describe('prepackaged_rules_schema', () => { beforeAll(() => { diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/rules_bulk_schema.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/rules_bulk_schema.test.ts index 8dc97d727c4d1d..9a7cf5e2c2871c 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/rules_bulk_schema.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/rules_bulk_schema.test.ts @@ -7,17 +7,13 @@ import { left } from 'fp-ts/lib/Either'; import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck } from './exact_check'; -import { - foldLeftRight, - getBaseResponsePayload, - getErrorPayload, - getPaths, -} from './__mocks__/utils'; +import { getBaseResponsePayload, getErrorPayload } from './__mocks__/utils'; import { RulesBulkSchema, rulesBulkSchema } from './rules_bulk_schema'; import { RulesSchema } from './rules_schema'; import { ErrorSchema } from './error_schema'; import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../../feature_flags'; +import { exactCheck } from '../../../../../utils/build_validation/exact_check'; +import { foldLeftRight, getPaths } from '../../../../../utils/build_validation/__mocks__/utils'; describe('prepackaged_rule_schema', () => { beforeAll(() => { diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/rules_schema.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/rules_schema.test.ts index fb9ff2c28dc44e..82a6682e6461f9 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/rules_schema.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/rules_schema.test.ts @@ -7,10 +7,11 @@ import { left } from 'fp-ts/lib/Either'; import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck } from './exact_check'; import { rulesSchema, RulesSchema, removeList } from './rules_schema'; -import { foldLeftRight, getBaseResponsePayload, getPaths } from './__mocks__/utils'; +import { getBaseResponsePayload } from './__mocks__/utils'; import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../../feature_flags'; +import { exactCheck } from '../../../../../utils/build_validation/exact_check'; +import { foldLeftRight, getPaths } from '../../../../../utils/build_validation/__mocks__/utils'; export const ANCHOR_DATE = '2020-02-20T03:57:54.037Z'; @@ -207,7 +208,7 @@ describe('rules_schema', () => { }); // TODO: (LIST-FEATURE) Remove this test once the feature flag is deployed - test('it should remove lists when we need it to be removed because the feature is off but there exists a list in the data', () => { + test('it should remove exceptions_list when we need it to be removed because the feature is off but there exists a list in the data', () => { const payload = getBaseResponsePayload(); const decoded = rulesSchema.decode(payload); const listRemoved = removeList(decoded); @@ -246,9 +247,9 @@ describe('rules_schema', () => { }); }); - test('it should work with lists that are not there and not cause invalidation or errors', () => { + test('it should work with exceptions_list that are not there and not cause invalidation or errors', () => { const payload = getBaseResponsePayload(); - const { lists, ...payloadWithoutLists } = payload; + const { exceptions_list, ...payloadWithoutLists } = payload; const decoded = rulesSchema.decode(payloadWithoutLists); const listRemoved = removeList(decoded); const message = pipe(listRemoved, foldLeftRight); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/rules_schema.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/rules_schema.ts index 1574e8f5aa6e1c..fb1ee8e670e312 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/rules_schema.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/rules_schema.ts @@ -87,7 +87,7 @@ export const requiredRulesSchema = t.type({ updated_at, created_by, version, - lists: ListsDefaultArray, + exceptions_list: ListsDefaultArray, }); export type RequiredRulesSchema = t.TypeOf; @@ -172,7 +172,7 @@ export const removeList = ( ): Either => { const onLeft = (errors: t.Errors): Either => left(errors); const onRight = (decodedValue: RequiredRulesSchema): Either => { - delete decodedValue.lists; + delete decodedValue.exceptions_list; return right(decodedValue); }; const folded = fold(onLeft, onRight); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/type_timeline_only_schema.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/type_timeline_only_schema.test.ts index 68a3c8b3038239..85fb124464487a 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/type_timeline_only_schema.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/type_timeline_only_schema.test.ts @@ -7,10 +7,10 @@ import { left } from 'fp-ts/lib/Either'; import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck } from './exact_check'; -import { foldLeftRight, getPaths } from './__mocks__/utils'; import { TypeAndTimelineOnly, typeAndTimelineOnlySchema } from './type_timeline_only_schema'; import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../../feature_flags'; +import { exactCheck } from '../../../../../utils/build_validation/exact_check'; +import { foldLeftRight, getPaths } from '../../../../../utils/build_validation/__mocks__/utils'; describe('prepackaged_rule_schema', () => { beforeAll(() => { diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/iso_date_string.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/iso_date_string.test.ts index fbafaf7f52ecb6..ff62ea4443f3f6 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/iso_date_string.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/iso_date_string.test.ts @@ -6,8 +6,8 @@ import { IsoDateString } from './iso_date_string'; import { pipe } from 'fp-ts/lib/pipeable'; -import { foldLeftRight, getPaths } from '../response/__mocks__/utils'; import { left } from 'fp-ts/lib/Either'; +import { foldLeftRight, getPaths } from '../../../../../utils/build_validation/__mocks__/utils'; describe('ios_date_string', () => { test('it should validate a iso string', () => { diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/lists_default_array.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/lists_default_array.test.ts index e8a9c7b0886a19..2a97c8a4a143e8 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/lists_default_array.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/lists_default_array.test.ts @@ -6,8 +6,8 @@ import { ListsDefaultArray } from './lists_default_array'; import { pipe } from 'fp-ts/lib/pipeable'; -import { foldLeftRight, getPaths } from '../response/__mocks__/utils'; import { left } from 'fp-ts/lib/Either'; +import { foldLeftRight, getPaths } from '../../../../../utils/build_validation/__mocks__/utils'; describe('lists_default_array', () => { test('it should validate an empty array', () => { diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/positive_integer_greater_than_zero.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/positive_integer_greater_than_zero.test.ts index bc17303f242038..d6f21681df88fe 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/positive_integer_greater_than_zero.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/positive_integer_greater_than_zero.test.ts @@ -6,8 +6,8 @@ import { PositiveIntegerGreaterThanZero } from './positive_integer_greater_than_zero'; import { pipe } from 'fp-ts/lib/pipeable'; -import { foldLeftRight, getPaths } from '../response/__mocks__/utils'; import { left } from 'fp-ts/lib/Either'; +import { foldLeftRight, getPaths } from '../../../../../utils/build_validation/__mocks__/utils'; describe('positive_integer_greater_than_zero', () => { test('it should validate a positive number', () => { diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/postive_integer.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/postive_integer.test.ts index cee451279663a7..26441745a7f29e 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/postive_integer.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/postive_integer.test.ts @@ -6,8 +6,8 @@ import { PositiveInteger } from './positive_integer'; import { pipe } from 'fp-ts/lib/pipeable'; -import { foldLeftRight, getPaths } from '../response/__mocks__/utils'; import { left } from 'fp-ts/lib/Either'; +import { foldLeftRight, getPaths } from '../../../../../utils/build_validation/__mocks__/utils'; describe('positive_integer_greater_than_zero', () => { test('it should validate a positive number', () => { diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/references_default_array.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/references_default_array.test.ts index 3ae8415b4f170f..76f722274ce23a 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/references_default_array.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/references_default_array.test.ts @@ -6,8 +6,8 @@ import { ReferencesDefaultArray } from './references_default_array'; import { pipe } from 'fp-ts/lib/pipeable'; -import { foldLeftRight, getPaths } from '../response/__mocks__/utils'; import { left } from 'fp-ts/lib/Either'; +import { foldLeftRight, getPaths } from '../../../../../utils/build_validation/__mocks__/utils'; describe('references_default_array', () => { test('it should validate an empty array', () => { diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/risk_score.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/risk_score.test.ts index ab3f80944489fe..76e3445358dd9b 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/risk_score.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/risk_score.test.ts @@ -6,8 +6,8 @@ import { RiskScore } from './risk_score'; import { pipe } from 'fp-ts/lib/pipeable'; -import { foldLeftRight, getPaths } from '../response/__mocks__/utils'; import { left } from 'fp-ts/lib/Either'; +import { foldLeftRight, getPaths } from '../../../../../utils/build_validation/__mocks__/utils'; describe('risk_score', () => { test('it should validate a positive number', () => { diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/uuid.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/uuid.test.ts index 342e6f2db2e16d..7b68dbcef2d7ed 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/uuid.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/types/uuid.test.ts @@ -6,8 +6,8 @@ import { UUID } from './uuid'; import { pipe } from 'fp-ts/lib/pipeable'; -import { foldLeftRight, getPaths } from '../response/__mocks__/utils'; import { left } from 'fp-ts/lib/Either'; +import { foldLeftRight, getPaths } from '../../../../../utils/build_validation/__mocks__/utils'; describe('uuid', () => { test('it should validate a uuid', () => { diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts index 78fa7d6cc71add..b89df0fc0f3ab2 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.test.ts @@ -1536,8 +1536,8 @@ describe('create rules schema', () => { // on demand. Since they are per module, we have a an issue where the ENV variables do not take effect. It is better we change all the // schema's to be function calls to avoid global side effects or just wait until the feature is available. If you want to test this early, // you can remove the .skip and set your env variable of export ELASTIC_XPACK_SIEM_LISTS_FEATURE=true locally - describe.skip('lists', () => { - test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and lists] does validate', () => { + describe.skip('exceptions_list', () => { + test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and exceptions_list] does validate', () => { expect( updateRulesSchema.validate>({ rule_id: 'rule-1', @@ -1551,7 +1551,7 @@ describe('create rules schema', () => { type: 'query', risk_score: 50, note: '# some markdown', - lists: [ + exceptions_list: [ { field: 'source.ip', values_operator: 'included', @@ -1584,7 +1584,7 @@ describe('create rules schema', () => { ).toBeFalsy(); }); - test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and empty lists] does validate', () => { + test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and empty exceptions_list] does validate', () => { expect( updateRulesSchema.validate>({ rule_id: 'rule-1', @@ -1598,14 +1598,14 @@ describe('create rules schema', () => { type: 'query', risk_score: 50, note: '# some markdown', - lists: [], + exceptions_list: [], }).error ).toBeFalsy(); }); - test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and invalid lists] does NOT validate', () => { + test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and invalid exceptions_list] does NOT validate', () => { expect( - updateRulesSchema.validate>>({ + updateRulesSchema.validate>>({ rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1617,16 +1617,16 @@ describe('create rules schema', () => { type: 'query', risk_score: 50, note: '# some markdown', - lists: [{ invalid_value: 'invalid value' }], + exceptions_list: [{ invalid_value: 'invalid value' }], }).error.message ).toEqual( - 'child "lists" fails because ["lists" at position 0 fails because [child "field" fails because ["field" is required]]]' + 'child "exceptions_list" fails because ["exceptions_list" at position 0 fails because [child "field" fails because ["field" is required]]]' ); }); - test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and non-existent lists] does validate with empty lists', () => { + test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and non-existent exceptions_list] does validate with empty exceptions_list', () => { expect( - updateRulesSchema.validate>>({ + updateRulesSchema.validate>>({ rule_id: 'rule-1', description: 'some description', from: 'now-5m', @@ -1638,7 +1638,7 @@ describe('create rules schema', () => { type: 'query', risk_score: 50, note: '# some markdown', - }).value.lists + }).value.exceptions_list ).toEqual([]); }); }); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.ts b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.ts index f842c14f41ae6b..b1b37801b644f5 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/update_rules_schema.ts @@ -107,5 +107,5 @@ export const updateRulesSchema = Joi.object({ version, // TODO: (LIST-FEATURE) Remove the hasListsFeatures once this is ready for release - lists: hasListsFeature() ? lists.default([]) : lists.forbidden().default([]), + exceptions_list: hasListsFeature() ? lists.default([]) : lists.forbidden().default([]), }).xor('id', 'rule_id'); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/rules/create_rules.ts b/x-pack/plugins/siem/server/lib/detection_engine/rules/create_rules.ts index 76cfffdfe9f408..a007fe35b407ed 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/rules/create_rules.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/rules/create_rules.ts @@ -42,11 +42,11 @@ export const createRules = async ({ references, note, version, - lists, + exceptions_list, actions, }: CreateRuleParams): Promise => { - // TODO: Remove this and use regular lists once the feature is stable for a release - const listsParam = hasListsFeature() ? { lists } : {}; + // TODO: Remove this and use regular exceptions_list once the feature is stable for a release + const exceptionsListParam = hasListsFeature() ? { exceptions_list } : {}; return alertsClient.create({ data: { name, @@ -79,7 +79,7 @@ export const createRules = async ({ references, note, version, - ...listsParam, + ...exceptionsListParam, }, schedule: { interval }, enabled, diff --git a/x-pack/plugins/siem/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.test.ts index 695057ccc2f70c..8044692ab90b15 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/rules/create_rules_stream_from_ndjson.test.ts @@ -66,7 +66,7 @@ describe('create_rules_stream_from_ndjson', () => { immutable: false, query: '', language: 'kuery', - lists: [], + exceptions_list: [], max_signals: 100, tags: [], threat: [], @@ -92,7 +92,7 @@ describe('create_rules_stream_from_ndjson', () => { immutable: false, query: '', language: 'kuery', - lists: [], + exceptions_list: [], max_signals: 100, tags: [], threat: [], @@ -158,7 +158,7 @@ describe('create_rules_stream_from_ndjson', () => { language: 'kuery', max_signals: 100, tags: [], - lists: [], + exceptions_list: [], threat: [], throttle: null, references: [], @@ -183,7 +183,7 @@ describe('create_rules_stream_from_ndjson', () => { query: '', language: 'kuery', max_signals: 100, - lists: [], + exceptions_list: [], tags: [], threat: [], throttle: null, @@ -230,7 +230,7 @@ describe('create_rules_stream_from_ndjson', () => { query: '', language: 'kuery', max_signals: 100, - lists: [], + exceptions_list: [], tags: [], threat: [], throttle: null, @@ -256,7 +256,7 @@ describe('create_rules_stream_from_ndjson', () => { query: '', language: 'kuery', max_signals: 100, - lists: [], + exceptions_list: [], tags: [], threat: [], throttle: null, @@ -303,7 +303,7 @@ describe('create_rules_stream_from_ndjson', () => { query: '', language: 'kuery', max_signals: 100, - lists: [], + exceptions_list: [], tags: [], threat: [], throttle: null, @@ -330,7 +330,7 @@ describe('create_rules_stream_from_ndjson', () => { query: '', language: 'kuery', max_signals: 100, - lists: [], + exceptions_list: [], tags: [], threat: [], throttle: null, @@ -376,7 +376,7 @@ describe('create_rules_stream_from_ndjson', () => { query: '', language: 'kuery', max_signals: 100, - lists: [], + exceptions_list: [], tags: [], threat: [], throttle: null, @@ -405,7 +405,7 @@ describe('create_rules_stream_from_ndjson', () => { query: '', language: 'kuery', max_signals: 100, - lists: [], + exceptions_list: [], tags: [], threat: [], throttle: null, diff --git a/x-pack/plugins/siem/server/lib/detection_engine/rules/get_export_all.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/rules/get_export_all.test.ts index df902854962b13..6df250f1cf513f 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/rules/get_export_all.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/rules/get_export_all.test.ts @@ -79,7 +79,7 @@ describe('getExportAll', () => { throttle: 'no_actions', note: '# Investigative notes', version: 1, - lists: [ + exceptions_list: [ { field: 'source.ip', values_operator: 'included', diff --git a/x-pack/plugins/siem/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts index ce6819462aa276..092a9a8faf395b 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/rules/get_export_by_object_ids.test.ts @@ -87,7 +87,7 @@ describe('get_export_by_object_ids', () => { throttle: 'no_actions', note: '# Investigative notes', version: 1, - lists: [ + exceptions_list: [ { field: 'source.ip', values_operator: 'included', @@ -215,7 +215,7 @@ describe('get_export_by_object_ids', () => { throttle: 'no_actions', note: '# Investigative notes', version: 1, - lists: [ + exceptions_list: [ { field: 'source.ip', values_operator: 'included', diff --git a/x-pack/plugins/siem/server/lib/detection_engine/rules/install_prepacked_rules.ts b/x-pack/plugins/siem/server/lib/detection_engine/rules/install_prepacked_rules.ts index 46d5b5fdf452e5..3d3ed52b2feb2f 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/rules/install_prepacked_rules.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/rules/install_prepacked_rules.ts @@ -46,7 +46,7 @@ export const installPrepackagedRules = ( references, note, version, - lists, + exceptions_list, } = rule; return [ ...acc, @@ -82,7 +82,7 @@ export const installPrepackagedRules = ( references, note, version, - lists, + exceptions_list, actions: [], // At this time there is no pre-packaged actions }), ]; diff --git a/x-pack/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts b/x-pack/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts index 347b370c89e077..c23f539b581606 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/rules/patch_rules.ts @@ -44,7 +44,7 @@ export const patchRules = async ({ references, note, version, - lists, + exceptions_list, anomalyThreshold, machineLearningJobId, }: PatchRuleParams): Promise => { @@ -78,7 +78,7 @@ export const patchRules = async ({ references, version, note, - lists, + exceptions_list, anomalyThreshold, machineLearningJobId, }); @@ -110,7 +110,7 @@ export const patchRules = async ({ references, note, version: calculatedVersion, - lists, + exceptions_list, anomalyThreshold, machineLearningJobId, } diff --git a/x-pack/plugins/siem/server/lib/detection_engine/rules/update_rules.ts b/x-pack/plugins/siem/server/lib/detection_engine/rules/update_rules.ts index 183b81f3a3c77e..7ddbbd76b06618 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/rules/update_rules.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/rules/update_rules.ts @@ -44,7 +44,7 @@ export const updateRules = async ({ references, version, note, - lists, + exceptions_list, anomalyThreshold, machineLearningJobId, actions, @@ -83,8 +83,8 @@ export const updateRules = async ({ machineLearningJobId, }); - // TODO: Remove this and use regular lists once the feature is stable for a release - const listsParam = hasListsFeature() ? { lists } : {}; + // TODO: Remove this and use regular exceptions_list once the feature is stable for a release + const exceptionsListParam = hasListsFeature() ? { exceptions_list } : {}; const update = await alertsClient.update({ id: rule.id, @@ -120,7 +120,7 @@ export const updateRules = async ({ version: calculatedVersion, anomalyThreshold, machineLearningJobId, - ...listsParam, + ...exceptionsListParam, }, }, }); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/patches/update_list.json b/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/patches/update_list.json index 4db8724db4e13d..8d831f3a961d8d 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/patches/update_list.json +++ b/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/patches/update_list.json @@ -1,6 +1,6 @@ { "rule_id": "query-with-list", - "lists": [ + "exceptions_list": [ { "field": "source.ip", "values_operator": "excluded", diff --git a/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_and.json b/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_and.json index 33ae8df87e3c82..1575a712e2cbaa 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_and.json +++ b/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_and.json @@ -8,7 +8,7 @@ "query": "host.name: *", "interval": "30s", "language": "kuery", - "lists": [ + "exceptions_list": [ { "field": "event.module", "values_operator": "excluded", diff --git a/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_excluded.json b/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_excluded.json index 8ce9440fce2193..4e6d9403a276f4 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_excluded.json +++ b/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_excluded.json @@ -8,7 +8,7 @@ "query": "host.name: *", "interval": "30s", "language": "kuery", - "lists": [ + "exceptions_list": [ { "field": "event.module", "values_operator": "excluded", diff --git a/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_exists.json b/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_exists.json index 4ec014422a61b2..97beace37633fd 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_exists.json +++ b/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_exists.json @@ -8,7 +8,7 @@ "query": "host.name: *", "interval": "30s", "language": "kuery", - "lists": [ + "exceptions_list": [ { "field": "event.action", "values_operator": "included", diff --git a/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_list.json b/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_list.json index ce4bf80b0a7222..ad0585b5a2ec50 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_list.json +++ b/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_list.json @@ -8,7 +8,7 @@ "query": "host.name: *", "interval": "30s", "language": "kuery", - "lists": [ + "exceptions_list": [ { "field": "event.module", "values_operator": "excluded", diff --git a/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_match.json b/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_match.json index e1abac19b51e5a..6e6880cc28f24a 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_match.json +++ b/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_match.json @@ -8,7 +8,7 @@ "query": "host.name: *", "interval": "30s", "language": "kuery", - "lists": [ + "exceptions_list": [ { "field": "event.module", "values_operator": "included", diff --git a/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_match_all.json b/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_match_all.json index 1afbb1fee4785d..44cc26ac3315e4 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_match_all.json +++ b/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_match_all.json @@ -8,7 +8,7 @@ "query": "host.name: *", "interval": "30s", "language": "kuery", - "lists": [ + "exceptions_list": [ { "field": "event.module", "values_operator": "included", diff --git a/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_or.json b/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_or.json index 08e38e9ffa53d3..9c4eda559d5bc0 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_or.json +++ b/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/queries/lists/query_with_or.json @@ -7,7 +7,7 @@ "type": "query", "query": "host.name: *", "interval": "30s", - "lists": [ + "exceptions_list": [ { "field": "event.module", "values_operator": "excluded", diff --git a/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_list.json b/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_list.json index 66b198974f5743..df22dff5c046e9 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_list.json +++ b/x-pack/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_list.json @@ -6,7 +6,7 @@ "severity": "high", "type": "query", "query": "user.name: root or user.name: admin", - "lists": [ + "exceptions_list": [ { "field": "source.ip", "values_operator": "excluded", diff --git a/x-pack/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts b/x-pack/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts index d361e424f01e3f..8a5da8e8597216 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/signals/__mocks__/es_results.ts @@ -44,7 +44,7 @@ export const sampleRuleAlertParams = ( meta: undefined, threat: undefined, version: 1, - lists: [ + exceptions_list: [ { field: 'source.ip', values_operator: 'included', diff --git a/x-pack/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.test.ts index f1729e35ce1f07..bbd01cfaafc624 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/signals/build_bulk_body.test.ts @@ -90,7 +90,7 @@ describe('buildBulkBody', () => { version: 1, created_at: fakeSignalSourceHit.signal.rule?.created_at, updated_at: fakeSignalSourceHit.signal.rule?.updated_at, - lists: [ + exceptions_list: [ { field: 'source.ip', values_operator: 'included', @@ -216,7 +216,7 @@ describe('buildBulkBody', () => { created_at: fakeSignalSourceHit.signal.rule?.created_at, updated_at: fakeSignalSourceHit.signal.rule?.updated_at, throttle: 'no_actions', - lists: [ + exceptions_list: [ { field: 'source.ip', values_operator: 'included', @@ -340,7 +340,7 @@ describe('buildBulkBody', () => { created_at: fakeSignalSourceHit.signal.rule?.created_at, updated_at: fakeSignalSourceHit.signal.rule?.updated_at, throttle: 'no_actions', - lists: [ + exceptions_list: [ { field: 'source.ip', values_operator: 'included', @@ -457,7 +457,7 @@ describe('buildBulkBody', () => { updated_at: fakeSignalSourceHit.signal.rule?.updated_at, created_at: fakeSignalSourceHit.signal.rule?.created_at, throttle: 'no_actions', - lists: [ + exceptions_list: [ { field: 'source.ip', values_operator: 'included', diff --git a/x-pack/plugins/siem/server/lib/detection_engine/signals/build_exceptions_query.ts b/x-pack/plugins/siem/server/lib/detection_engine/signals/build_exceptions_query.ts index 22a57db87afb03..7a1564bb695467 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/signals/build_exceptions_query.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/signals/build_exceptions_query.ts @@ -185,7 +185,7 @@ export const buildQueryExceptions = ({ }: { query: string; language: Language; - lists: RuleAlertParams['lists']; + lists: RuleAlertParams['exceptions_list']; }): Query[] => { if (lists && lists !== null) { const exceptions = buildExceptions({ lists, language, query }); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts b/x-pack/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts index e5183ed4df7bd9..b3586c884d0c7f 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/signals/build_rule.test.ts @@ -79,7 +79,7 @@ describe('buildRule', () => { query: 'host.name: Braden', }, ], - lists: [ + exceptions_list: [ { field: 'source.ip', values_operator: 'included', @@ -162,7 +162,7 @@ describe('buildRule', () => { updated_at: rule.updated_at, created_at: rule.created_at, throttle: 'no_actions', - lists: [ + exceptions_list: [ { field: 'source.ip', values_operator: 'included', @@ -244,7 +244,7 @@ describe('buildRule', () => { updated_at: rule.updated_at, created_at: rule.created_at, throttle: 'no_actions', - lists: [ + exceptions_list: [ { field: 'source.ip', values_operator: 'included', diff --git a/x-pack/plugins/siem/server/lib/detection_engine/signals/build_rule.ts b/x-pack/plugins/siem/server/lib/detection_engine/signals/build_rule.ts index 9c375d7d45d5e7..93d4e5e7719b22 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/signals/build_rule.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/signals/build_rule.ts @@ -72,7 +72,7 @@ export const buildRule = ({ version: ruleParams.version, created_at: createdAt, updated_at: updatedAt, - lists: ruleParams.lists, + exceptions_list: ruleParams.exceptions_list, machine_learning_job_id: ruleParams.machineLearningJobId, anomaly_threshold: ruleParams.anomalyThreshold, }); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/signals/get_filter.ts b/x-pack/plugins/siem/server/lib/detection_engine/signals/get_filter.ts index c685ce4567afa3..d8fdab55bddebc 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/signals/get_filter.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/signals/get_filter.ts @@ -22,7 +22,7 @@ export const getQueryFilter = ( language: Language, filters: PartialFilter[], index: string[], - lists: RuleAlertParams['lists'] + lists: RuleAlertParams['exceptions_list'] ) => { const indexPattern = { fields: [], @@ -53,7 +53,7 @@ interface GetFilterArgs { savedId: string | undefined | null; services: AlertServices; index: string[] | undefined | null; - lists: RuleAlertParams['lists']; + lists: RuleAlertParams['exceptions_list']; } interface QueryAttributes { diff --git a/x-pack/plugins/siem/server/lib/detection_engine/signals/signal_params_schema.ts b/x-pack/plugins/siem/server/lib/detection_engine/signals/signal_params_schema.ts index 58dd53b6447c51..81a6ce9b08f02d 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/signals/signal_params_schema.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/signals/signal_params_schema.ts @@ -39,5 +39,5 @@ export const signalParamsSchema = () => type: schema.string(), references: schema.arrayOf(schema.string(), { defaultValue: [] }), version: schema.number({ defaultValue: 1 }), - lists: schema.maybe(schema.arrayOf(schema.object({}, { unknowns: 'allow' }))), + exceptions_list: schema.maybe(schema.arrayOf(schema.object({}, { unknowns: 'allow' }))), }); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts b/x-pack/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts index efb1338fd480ee..137603741dc8f2 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/signals/signal_rule_alert_type.ts @@ -66,7 +66,7 @@ export const signalRulesAlertType = ({ query, to, type, - lists, + exceptions_list, } = params; const searchAfterSize = Math.min(maxSignals, DEFAULT_SEARCH_AFTER_PAGE_SIZE); let hasError: boolean = false; @@ -201,7 +201,7 @@ export const signalRulesAlertType = ({ savedId, services, index: inputIndex, - lists, + lists: exceptions_list, }); const noReIndex = buildEventsSearchQuery({ diff --git a/x-pack/plugins/siem/server/lib/detection_engine/types.ts b/x-pack/plugins/siem/server/lib/detection_engine/types.ts index 357a2ab39e3fb4..f2026804da51ab 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/types.ts +++ b/x-pack/plugins/siem/server/lib/detection_engine/types.ts @@ -68,7 +68,7 @@ export interface RuleAlertParams { type: RuleType; version: number; throttle: string | undefined | null; - lists: ListsDefaultArraySchema | null | undefined; + exceptions_list: ListsDefaultArraySchema | null | undefined; } export type RuleTypeParams = Omit< diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/export_timelines_route.test.ts b/x-pack/plugins/siem/server/lib/timeline/routes/export_timelines_route.test.ts index 47ca25e16bd50d..2bccb7c393837b 100644 --- a/x-pack/plugins/siem/server/lib/timeline/routes/export_timelines_route.test.ts +++ b/x-pack/plugins/siem/server/lib/timeline/routes/export_timelines_route.test.ts @@ -85,7 +85,7 @@ describe('export timelines', () => { const result = server.validate(request); expect(result.badRequest.mock.calls[0][0]).toEqual( - 'Invalid value undefined supplied to : { ids: Array }/ids: Array' + 'Invalid value "undefined" supplied to "ids"' ); }); @@ -98,11 +98,7 @@ describe('export timelines', () => { const result = server.validate(request); expect(result.badRequest.mock.calls[1][0]).toEqual( - [ - 'Invalid value undefined supplied to : { file_name: string, exclude_export_details: ("true" | "false") }/file_name: string', - 'Invalid value undefined supplied to : { file_name: string, exclude_export_details: ("true" | "false") }/exclude_export_details: ("true" | "false")/0: "true"', - 'Invalid value undefined supplied to : { file_name: string, exclude_export_details: ("true" | "false") }/exclude_export_details: ("true" | "false")/1: "false"', - ].join('\n') + 'Invalid value "undefined" supplied to "file_name",Invalid value "undefined" supplied to "exclude_export_details",Invalid value "undefined" supplied to "exclude_export_details"' ); }); }); diff --git a/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.test.ts b/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.test.ts index 3931bf0e5bea51..9f41943cfa27f7 100644 --- a/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.test.ts +++ b/x-pack/plugins/siem/server/lib/timeline/routes/import_timelines_route.test.ts @@ -332,10 +332,7 @@ describe('import timelines', () => { const result = server.validate(request); expect(result.badRequest).toHaveBeenCalledWith( - [ - 'Invalid value undefined supplied to : { file: (ReadableRt & { hapi: { filename: string } }) }/file: (ReadableRt & { hapi: { filename: string } })/0: ReadableRt', - 'Invalid value undefined supplied to : { file: (ReadableRt & { hapi: { filename: string } }) }/file: (ReadableRt & { hapi: { filename: string } })/1: { hapi: { filename: string } }', - ].join('\n') + 'Invalid value "undefined" supplied to "file",Invalid value "undefined" supplied to "file"' ); }); }); diff --git a/x-pack/plugins/siem/server/plugin.ts b/x-pack/plugins/siem/server/plugin.ts index b9ec1c2e92438b..29a6999025e1fc 100644 --- a/x-pack/plugins/siem/server/plugin.ts +++ b/x-pack/plugins/siem/server/plugin.ts @@ -42,6 +42,7 @@ import { } from './saved_objects'; import { SiemClientFactory } from './client'; import { createConfig$, ConfigType } from './config'; +import { initUiSettings } from './ui_settings'; export { CoreSetup, CoreStart }; @@ -86,6 +87,8 @@ export class Plugin { ); } + initUiSettings(core.uiSettings); + const router = core.http.createRouter(); core.http.registerRouteHandlerContext(this.name, (context, request, response) => ({ getSiemClient: () => this.siemClientFactory.create(request), diff --git a/x-pack/plugins/siem/server/ui_settings.ts b/x-pack/plugins/siem/server/ui_settings.ts new file mode 100644 index 00000000000000..26b7fd72571afe --- /dev/null +++ b/x-pack/plugins/siem/server/ui_settings.ts @@ -0,0 +1,141 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import { schema } from '@kbn/config-schema'; + +import { CoreSetup } from '../../../../src/core/server'; +import { + DEFAULT_INDEX_KEY, + DEFAULT_INDEX_PATTERN, + DEFAULT_ANOMALY_SCORE, + DEFAULT_SIEM_TIME_RANGE, + DEFAULT_SIEM_REFRESH_INTERVAL, + DEFAULT_INTERVAL_PAUSE, + DEFAULT_INTERVAL_VALUE, + DEFAULT_FROM, + DEFAULT_TO, + ENABLE_NEWS_FEED_SETTING, + NEWS_FEED_URL_SETTING, + NEWS_FEED_URL_SETTING_DEFAULT, + IP_REPUTATION_LINKS_SETTING, + IP_REPUTATION_LINKS_SETTING_DEFAULT, +} from '../common/constants'; + +export const initUiSettings = (uiSettings: CoreSetup['uiSettings']) => { + uiSettings.register({ + [DEFAULT_SIEM_REFRESH_INTERVAL]: { + type: 'json', + name: i18n.translate('xpack.siem.uiSettings.defaultRefreshIntervalLabel', { + defaultMessage: 'Time filter refresh interval', + }), + value: `{ + "pause": ${DEFAULT_INTERVAL_PAUSE}, + "value": ${DEFAULT_INTERVAL_VALUE} +}`, + description: i18n.translate('xpack.siem.uiSettings.defaultRefreshIntervalDescription', { + defaultMessage: + '

Default refresh interval for the SIEM time filter, in milliseconds.

', + }), + category: ['siem'], + requiresPageReload: true, + schema: schema.object({ + value: schema.number(), + pause: schema.boolean(), + }), + }, + [DEFAULT_SIEM_TIME_RANGE]: { + type: 'json', + name: i18n.translate('xpack.siem.uiSettings.defaultTimeRangeLabel', { + defaultMessage: 'Time filter period', + }), + value: `{ + "from": "${DEFAULT_FROM}", + "to": "${DEFAULT_TO}" +}`, + description: i18n.translate('xpack.siem.uiSettings.defaultTimeRangeDescription', { + defaultMessage: '

Default period of time in the SIEM time filter.

', + }), + category: ['siem'], + requiresPageReload: true, + schema: schema.object({ + from: schema.string(), + to: schema.string(), + }), + }, + [DEFAULT_INDEX_KEY]: { + name: i18n.translate('xpack.siem.uiSettings.defaultIndexLabel', { + defaultMessage: 'Elasticsearch indices', + }), + value: DEFAULT_INDEX_PATTERN, + description: i18n.translate('xpack.siem.uiSettings.defaultIndexDescription', { + defaultMessage: + '

Comma-delimited list of Elasticsearch indices from which the SIEM app collects events.

', + }), + category: ['siem'], + requiresPageReload: true, + schema: schema.arrayOf(schema.string()), + }, + [DEFAULT_ANOMALY_SCORE]: { + name: i18n.translate('xpack.siem.uiSettings.defaultAnomalyScoreLabel', { + defaultMessage: 'Anomaly threshold', + }), + value: 50, + type: 'number', + description: i18n.translate('xpack.siem.uiSettings.defaultAnomalyScoreDescription', { + defaultMessage: + '

Value above which Machine Learning job anomalies are displayed in the SIEM app.

Valid values: 0 to 100.

', + }), + category: ['siem'], + requiresPageReload: true, + schema: schema.number(), + }, + [ENABLE_NEWS_FEED_SETTING]: { + name: i18n.translate('xpack.siem.uiSettings.enableNewsFeedLabel', { + defaultMessage: 'News feed', + }), + value: true, + description: i18n.translate('xpack.siem.uiSettings.enableNewsFeedDescription', { + defaultMessage: '

Enables the News feed

', + }), + type: 'boolean', + category: ['siem'], + requiresPageReload: true, + schema: schema.boolean(), + }, + [NEWS_FEED_URL_SETTING]: { + name: i18n.translate('xpack.siem.uiSettings.newsFeedUrl', { + defaultMessage: 'News feed URL', + }), + value: NEWS_FEED_URL_SETTING_DEFAULT, + description: i18n.translate('xpack.siem.uiSettings.newsFeedUrlDescription', { + defaultMessage: '

News feed content will be retrieved from this URL

', + }), + category: ['siem'], + requiresPageReload: true, + schema: schema.string(), + }, + [IP_REPUTATION_LINKS_SETTING]: { + name: i18n.translate('xpack.siem.uiSettings.ipReputationLinks', { + defaultMessage: 'IP Reputation Links', + }), + value: IP_REPUTATION_LINKS_SETTING_DEFAULT, + type: 'json', + description: i18n.translate('xpack.siem.uiSettings.ipReputationLinksDescription', { + defaultMessage: + 'Array of URL templates to build the list of reputation URLs to be displayed on the IP Details page.', + }), + category: ['siem'], + requiresPageReload: true, + schema: schema.arrayOf( + schema.object({ + name: schema.string(), + url_template: schema.string(), + }) + ), + }, + }); +}; diff --git a/x-pack/plugins/siem/server/utils/build_validation/__mocks__/utils.ts b/x-pack/plugins/siem/server/utils/build_validation/__mocks__/utils.ts new file mode 100644 index 00000000000000..578972dda5aeff --- /dev/null +++ b/x-pack/plugins/siem/server/utils/build_validation/__mocks__/utils.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; + * you may not use this file except in compliance with the Elastic License. + */ + +import * as t from 'io-ts'; +import { fold } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { formatErrors } from '../format_errors'; + +interface Message { + errors: t.Errors; + schema: T | {}; +} + +const onLeft = (errors: t.Errors): Message => { + return { schema: {}, errors }; +}; + +const onRight = (schema: T): Message => { + return { + schema, + errors: [], + }; +}; + +export const foldLeftRight = fold(onLeft, onRight); + +/** + * Convenience utility to keep the error message handling within tests to be + * very concise. + * @param validation The validation to get the errors from + */ +export const getPaths =
(validation: t.Validation): string[] => { + return pipe( + validation, + fold( + errors => formatErrors(errors), + () => ['no errors'] + ) + ); +}; diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/exact_check.test.ts b/x-pack/plugins/siem/server/utils/build_validation/exact_check.test.ts similarity index 94% rename from x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/exact_check.test.ts rename to x-pack/plugins/siem/server/utils/build_validation/exact_check.test.ts index cae4365d06856f..1e70deaeed4386 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/exact_check.test.ts +++ b/x-pack/plugins/siem/server/utils/build_validation/exact_check.test.ts @@ -5,22 +5,13 @@ */ import * as t from 'io-ts'; -import { left, right } from 'fp-ts/lib/Either'; +import { left, right, Either } from 'fp-ts/lib/Either'; import { pipe } from 'fp-ts/lib/pipeable'; import { foldLeftRight, getPaths } from './__mocks__/utils'; import { exactCheck, findDifferencesRecursive } from './exact_check'; -import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../../feature_flags'; describe('exact_check', () => { - beforeAll(() => { - setFeatureFlagsForTestsOnly(); - }); - - afterAll(() => { - unSetFeatureFlagsForTestsOnly(); - }); - test('it returns an error if given extra object properties', () => { const someType = t.exact( t.type({ @@ -36,14 +27,22 @@ describe('exact_check', () => { }); test('it returns an error if the data type is not as expected', () => { + type UnsafeCastForTest = Either< + t.Errors, + { + a: number; + } + >; + const someType = t.exact( t.type({ a: t.string, }) ); + const payload = { a: 1 }; const decoded = someType.decode(payload); - const checked = exactCheck(payload, decoded); + const checked = exactCheck(payload, decoded as UnsafeCastForTest); const message = pipe(checked, foldLeftRight); expect(getPaths(left(message.errors))).toEqual(['Invalid value "1" supplied to "a"']); expect(message.schema).toEqual({}); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/exact_check.ts b/x-pack/plugins/siem/server/utils/build_validation/exact_check.ts similarity index 59% rename from x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/exact_check.ts rename to x-pack/plugins/siem/server/utils/build_validation/exact_check.ts index 6fa04729501892..9484765f9973df 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/exact_check.ts +++ b/x-pack/plugins/siem/server/utils/build_validation/exact_check.ts @@ -25,10 +25,7 @@ import { isObject, get } from 'lodash/fp'; * @param decoded The decoded either which has either an existing error or the * decoded object which could have additional keys stripped from it. */ -export const exactCheck = ( - original: object, - decoded: Either -): Either => { +export const exactCheck = (original: T, decoded: Either): Either => { const onLeft = (errors: t.Errors): Either => left(errors); const onRight = (decodedValue: T): Either => { const differences = findDifferencesRecursive(original, decodedValue); @@ -47,7 +44,7 @@ export const exactCheck = ( return pipe(decoded, fold(onLeft, onRight)); }; -export const findDifferencesRecursive = (original: object, decodedValue: T): string[] => { +export const findDifferencesRecursive = (original: T, decodedValue: T): string[] => { if (decodedValue == null) { try { // It is null and painful when the original contains an object or an array @@ -56,29 +53,33 @@ export const findDifferencesRecursive = (original: object, decodedValue: T): } catch (err) { return ['circular reference']; } + } else if (typeof original !== 'object' || original == null) { + // We are not an object or null so do not report differences + return []; + } else { + const decodedKeys = Object.keys(decodedValue); + const differences = Object.keys(original).flatMap(originalKey => { + const foundKey = decodedKeys.some(key => key === originalKey); + const topLevelKey = foundKey ? [] : [originalKey]; + // I use lodash to cheat and get an any (not going to lie ;-)) + const valueObjectOrArrayOriginal = get(originalKey, original); + const valueObjectOrArrayDecoded = get(originalKey, decodedValue); + if (isObject(valueObjectOrArrayOriginal)) { + return [ + ...topLevelKey, + ...findDifferencesRecursive(valueObjectOrArrayOriginal, valueObjectOrArrayDecoded), + ]; + } else if (Array.isArray(valueObjectOrArrayOriginal)) { + return [ + ...topLevelKey, + ...valueObjectOrArrayOriginal.flatMap((arrayElement, index) => + findDifferencesRecursive(arrayElement, get(index, valueObjectOrArrayDecoded)) + ), + ]; + } else { + return topLevelKey; + } + }); + return differences; } - const decodedKeys = Object.keys(decodedValue); - const differences = Object.keys(original).flatMap(originalKey => { - const foundKey = decodedKeys.some(key => key === originalKey); - const topLevelKey = foundKey ? [] : [originalKey]; - // I use lodash to cheat and get an any (not going to lie ;-)) - const valueObjectOrArrayOriginal = get(originalKey, original); - const valueObjectOrArrayDecoded = get(originalKey, decodedValue); - if (isObject(valueObjectOrArrayOriginal)) { - return [ - ...topLevelKey, - ...findDifferencesRecursive(valueObjectOrArrayOriginal, valueObjectOrArrayDecoded), - ]; - } else if (Array.isArray(valueObjectOrArrayOriginal)) { - return [ - ...topLevelKey, - ...valueObjectOrArrayOriginal.flatMap((arrayElement, index) => - findDifferencesRecursive(arrayElement, get(index, valueObjectOrArrayDecoded)) - ), - ]; - } else { - return topLevelKey; - } - }); - return differences; }; diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/utils.test.ts b/x-pack/plugins/siem/server/utils/build_validation/format_errors.test.ts similarity index 94% rename from x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/utils.test.ts rename to x-pack/plugins/siem/server/utils/build_validation/format_errors.test.ts index c1eb32be4895c2..f9dd9e76a1d9c6 100644 --- a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/utils.test.ts +++ b/x-pack/plugins/siem/server/utils/build_validation/format_errors.test.ts @@ -5,18 +5,9 @@ */ import * as t from 'io-ts'; -import { formatErrors } from './utils'; -import { setFeatureFlagsForTestsOnly, unSetFeatureFlagsForTestsOnly } from '../../../feature_flags'; +import { formatErrors } from './format_errors'; describe('utils', () => { - beforeAll(() => { - setFeatureFlagsForTestsOnly(); - }); - - afterAll(() => { - unSetFeatureFlagsForTestsOnly(); - }); - test('returns an empty error message string if there are no errors', () => { const errors: t.Errors = []; const output = formatErrors(errors); diff --git a/x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/utils.ts b/x-pack/plugins/siem/server/utils/build_validation/format_errors.ts similarity index 100% rename from x-pack/plugins/siem/server/lib/detection_engine/routes/schemas/response/utils.ts rename to x-pack/plugins/siem/server/utils/build_validation/format_errors.ts diff --git a/x-pack/plugins/siem/server/utils/build_validation/route_validation.test.ts b/x-pack/plugins/siem/server/utils/build_validation/route_validation.test.ts index d17a8457ff81be..866dbe9480ca59 100644 --- a/x-pack/plugins/siem/server/utils/build_validation/route_validation.test.ts +++ b/x-pack/plugins/siem/server/utils/build_validation/route_validation.test.ts @@ -9,9 +9,33 @@ import * as rt from 'io-ts'; import { RouteValidationResultFactory } from '../../../../../../src/core/server/http'; describe('buildRouteValidation', () => { - const schema = rt.type({ - ids: rt.array(rt.string), - }); + const schema = rt.exact( + rt.type({ + ids: rt.array(rt.string), + }) + ); + type Schema = rt.TypeOf; + + /** + * If your schema is using exact all the way down then the validation will + * catch any additional keys that should not be present within the validation + * when the route_validation uses the exact check. + */ + const deepSchema = rt.exact( + rt.type({ + topLevel: rt.exact( + rt.type({ + secondLevel: rt.exact( + rt.type({ + thirdLevel: rt.string, + }) + ), + }) + ), + }) + ); + type DeepSchema = rt.TypeOf; + const validationResult: RouteValidationResultFactory = { ok: jest.fn().mockImplementation(validatedInput => validatedInput), badRequest: jest.fn().mockImplementation(e => e), @@ -22,18 +46,41 @@ describe('buildRouteValidation', () => { }); test('return validation error', () => { - const input = { id: 'someId' }; + const input: Omit & { id: string } = { id: 'someId' }; const result = buildRouteValidation(schema)(input, validationResult); - expect(result).toEqual( - 'Invalid value undefined supplied to : { ids: Array }/ids: Array' - ); + expect(result).toEqual('Invalid value "undefined" supplied to "ids"'); }); test('return validated input', () => { - const input = { ids: ['someId'] }; + const input: Schema = { ids: ['someId'] }; const result = buildRouteValidation(schema)(input, validationResult); expect(result).toEqual(input); }); + + test('returns validation error if given extra keys on input for an array', () => { + const input: Schema & { somethingExtra: string } = { + ids: ['someId'], + somethingExtra: 'hello', + }; + const result = buildRouteValidation(schema)(input, validationResult); + expect(result).toEqual('invalid keys "somethingExtra"'); + }); + + test('return validation input for a deep 3rd level object', () => { + const input: DeepSchema = { topLevel: { secondLevel: { thirdLevel: 'hello' } } }; + const result = buildRouteValidation(deepSchema)(input, validationResult); + expect(result).toEqual(input); + }); + + test('return validation error for a deep 3rd level object that has an extra key value of "somethingElse"', () => { + const input: DeepSchema & { + topLevel: { secondLevel: { thirdLevel: string; somethingElse: string } }; + } = { + topLevel: { secondLevel: { thirdLevel: 'hello', somethingElse: 'extraKey' } }, + }; + const result = buildRouteValidation(deepSchema)(input, validationResult); + expect(result).toEqual('invalid keys "somethingElse"'); + }); }); diff --git a/x-pack/plugins/siem/server/utils/build_validation/route_validation.ts b/x-pack/plugins/siem/server/utils/build_validation/route_validation.ts index bfcd0998fe6900..30b95dcfa94ee3 100644 --- a/x-pack/plugins/siem/server/utils/build_validation/route_validation.ts +++ b/x-pack/plugins/siem/server/utils/build_validation/route_validation.ts @@ -7,12 +7,13 @@ import { fold } from 'fp-ts/lib/Either'; import { pipe } from 'fp-ts/lib/pipeable'; import * as rt from 'io-ts'; -import { failure } from 'io-ts/lib/PathReporter'; import { RouteValidationFunction, RouteValidationResultFactory, RouteValidationError, } from '../../../../../../src/core/server'; +import { exactCheck } from './exact_check'; +import { formatErrors } from './format_errors'; type RequestValidationResult = | { @@ -32,8 +33,9 @@ export const buildRouteValidation = >( ) => pipe( schema.decode(inputValue), + decoded => exactCheck(inputValue, decoded), fold>( - (errors: rt.Errors) => validationResult.badRequest(failure(errors).join('\n')), + (errors: rt.Errors) => validationResult.badRequest(formatErrors(errors).join()), (validatedInput: A) => validationResult.ok(validatedInput) ) ); diff --git a/x-pack/plugins/snapshot_restore/common/types/index.ts b/x-pack/plugins/snapshot_restore/common/types/index.ts index 5cb3839fa9e01d..d52584ca737a2a 100644 --- a/x-pack/plugins/snapshot_restore/common/types/index.ts +++ b/x-pack/plugins/snapshot_restore/common/types/index.ts @@ -8,4 +8,3 @@ export * from './repository'; export * from './snapshot'; export * from './restore'; export * from './policy'; -export * from './privileges'; diff --git a/x-pack/plugins/snapshot_restore/common/types/privileges.ts b/x-pack/plugins/snapshot_restore/common/types/privileges.ts deleted file mode 100644 index bf710b8225599e..00000000000000 --- a/x-pack/plugins/snapshot_restore/common/types/privileges.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -export interface MissingPrivileges { - [key: string]: string[] | undefined; -} - -export interface Privileges { - hasAllPrivileges: boolean; - missingPrivileges: MissingPrivileges; -} diff --git a/x-pack/plugins/snapshot_restore/public/application/app.tsx b/x-pack/plugins/snapshot_restore/public/application/app.tsx index 77ef697814b2c4..350d8aec711edf 100644 --- a/x-pack/plugins/snapshot_restore/public/application/app.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/app.tsx @@ -4,13 +4,19 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useContext } from 'react'; +import React from 'react'; import { Redirect, Route, Switch } from 'react-router-dom'; import { EuiPageContent } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { APP_REQUIRED_CLUSTER_PRIVILEGES } from '../../common/constants'; -import { SectionLoading, SectionError } from './components'; +import { APP_REQUIRED_CLUSTER_PRIVILEGES } from '../../common'; +import { + useAuthorizationContext, + SectionError, + WithPrivileges, + NotAuthorizedSection, +} from '../shared_imports'; +import { SectionLoading } from './components'; import { BASE_PATH, DEFAULT_SECTION, Section } from './constants'; import { RepositoryAdd, @@ -21,11 +27,10 @@ import { PolicyEdit, } from './sections'; import { useConfig } from './app_context'; -import { AuthorizationContext, WithPrivileges, NotAuthorizedSection } from './lib/authorization'; export const App: React.FunctionComponent = () => { const { slm_ui: slmUi } = useConfig(); - const { apiError } = useContext(AuthorizationContext); + const { apiError } = useAuthorizationContext(); const sections: Section[] = ['repositories', 'snapshots', 'restore_status']; diff --git a/x-pack/plugins/snapshot_restore/public/application/app_providers.tsx b/x-pack/plugins/snapshot_restore/public/application/app_providers.tsx index e2732c0051337a..3ca25b7d32dba7 100644 --- a/x-pack/plugins/snapshot_restore/public/application/app_providers.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/app_providers.tsx @@ -5,8 +5,8 @@ */ import React from 'react'; -import { API_BASE_PATH } from '../../common/constants'; -import { AuthorizationProvider } from './lib/authorization'; +import { API_BASE_PATH } from '../../common'; +import { AuthorizationProvider } from '../shared_imports'; import { AppContextProvider, AppDependencies } from './app_context'; interface Props { @@ -18,10 +18,11 @@ export const AppProviders = ({ appDependencies, children }: Props) => { const { core } = appDependencies; const { i18n: { Context: I18nContext }, + http, } = core; return ( - + {children} diff --git a/x-pack/plugins/snapshot_restore/public/application/components/index.ts b/x-pack/plugins/snapshot_restore/public/application/components/index.ts index a7038ebd715785..f5bb8923898702 100644 --- a/x-pack/plugins/snapshot_restore/public/application/components/index.ts +++ b/x-pack/plugins/snapshot_restore/public/application/components/index.ts @@ -10,7 +10,6 @@ export { RepositoryDeleteProvider } from './repository_delete_provider'; export { RepositoryForm } from './repository_form'; export { RepositoryVerificationBadge } from './repository_verification_badge'; export { RepositoryTypeLogo } from './repository_type_logo'; -export { SectionError, Error } from './section_error'; export { SectionLoading } from './section_loading'; export { SnapshotDeleteProvider } from './snapshot_delete_provider'; export { RestoreSnapshotForm } from './restore_snapshot_form'; diff --git a/x-pack/plugins/snapshot_restore/public/application/components/policy_form/steps/step_logistics.tsx b/x-pack/plugins/snapshot_restore/public/application/components/policy_form/steps/step_logistics.tsx index f2d4e2bd74598f..105f0601e3dfbb 100644 --- a/x-pack/plugins/snapshot_restore/public/application/components/policy_form/steps/step_logistics.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/components/policy_form/steps/step_logistics.tsx @@ -21,13 +21,13 @@ import { } from '@elastic/eui'; import { Repository } from '../../../../../common/types'; -import { CronEditor } from '../../../../shared_imports'; +import { CronEditor, SectionError } from '../../../../shared_imports'; import { useServices } from '../../../app_context'; import { DEFAULT_POLICY_SCHEDULE, DEFAULT_POLICY_FREQUENCY } from '../../../constants'; import { useLoadRepositories } from '../../../services/http'; import { linkToAddRepository } from '../../../services/navigation'; import { documentationLinksService } from '../../../services/documentation'; -import { SectionLoading, SectionError } from '../../'; +import { SectionLoading } from '../../'; import { StepProps } from './'; export const PolicyStepLogistics: React.FunctionComponent = ({ diff --git a/x-pack/plugins/snapshot_restore/public/application/components/repository_form/step_one.tsx b/x-pack/plugins/snapshot_restore/public/application/components/repository_form/step_one.tsx index 3b4c9d595b9f28..34bc06343a780a 100644 --- a/x-pack/plugins/snapshot_restore/public/application/components/repository_form/step_one.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/components/repository_form/step_one.tsx @@ -23,13 +23,14 @@ import { } from '@elastic/eui'; import { Repository, RepositoryType, EmptyRepository } from '../../../../common/types'; -import { REPOSITORY_TYPES } from '../../../../common/constants'; +import { REPOSITORY_TYPES } from '../../../../common'; +import { SectionError, Error } from '../../../shared_imports'; import { documentationLinksService } from '../../services/documentation'; import { useLoadRepositoryTypes } from '../../services/http'; import { textService } from '../../services/text'; import { RepositoryValidation } from '../../services/validation'; -import { SectionError, SectionLoading, RepositoryTypeLogo, Error } from '../'; +import { SectionLoading, RepositoryTypeLogo } from '../'; interface Props { repository: Repository | EmptyRepository; diff --git a/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/index.tsx b/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/index.tsx index 75295a1205cef9..1e54868397a6da 100644 --- a/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/index.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/index.tsx @@ -6,11 +6,11 @@ import React from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import { REPOSITORY_TYPES } from '../../../../../common/constants'; +import { REPOSITORY_TYPES } from '../../../../../common'; import { Repository, RepositoryType, EmptyRepository } from '../../../../../common/types'; +import { SectionError } from '../../../../shared_imports'; import { useServices } from '../../../app_context'; import { RepositorySettingsValidation } from '../../../services/validation'; -import { SectionError } from '../../index'; import { AzureSettings } from './azure_settings'; import { FSSettings } from './fs_settings'; diff --git a/x-pack/plugins/snapshot_restore/public/application/lib/authorization/components/authorization_provider.tsx b/x-pack/plugins/snapshot_restore/public/application/lib/authorization/components/authorization_provider.tsx deleted file mode 100644 index d32fe29cc1dfa4..00000000000000 --- a/x-pack/plugins/snapshot_restore/public/application/lib/authorization/components/authorization_provider.tsx +++ /dev/null @@ -1,47 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import React, { createContext } from 'react'; -import { useRequest } from '../../../services/http/use_request'; -import { Privileges } from '../../../../../common/types'; -import { Error } from '../../../components/section_error'; - -interface Authorization { - isLoading: boolean; - apiError: Error | null; - privileges: Privileges; -} - -const initialValue: Authorization = { - isLoading: true, - apiError: null, - privileges: { - hasAllPrivileges: true, - missingPrivileges: {}, - }, -}; - -export const AuthorizationContext = createContext(initialValue); - -interface Props { - privilegesEndpoint: string; - children: React.ReactNode; -} - -export const AuthorizationProvider = ({ privilegesEndpoint, children }: Props) => { - const { isLoading, error, data: privilegesData } = useRequest({ - path: privilegesEndpoint, - method: 'get', - }); - - const value = { - isLoading, - privileges: isLoading ? { hasAllPrivileges: true, missingPrivileges: {} } : privilegesData, - apiError: error ? error : null, - } as Authorization; - - return {children}; -}; diff --git a/x-pack/plugins/snapshot_restore/public/application/lib/authorization/components/index.ts b/x-pack/plugins/snapshot_restore/public/application/lib/authorization/components/index.ts deleted file mode 100644 index ac77aa52686602..00000000000000 --- a/x-pack/plugins/snapshot_restore/public/application/lib/authorization/components/index.ts +++ /dev/null @@ -1,11 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -export { AuthorizationProvider, AuthorizationContext } from './authorization_provider'; - -export { WithPrivileges } from './with_privileges'; - -export { NotAuthorizedSection } from './not_authorized_section'; diff --git a/x-pack/plugins/snapshot_restore/public/application/lib/authorization/components/not_authorized_section.tsx b/x-pack/plugins/snapshot_restore/public/application/lib/authorization/components/not_authorized_section.tsx deleted file mode 100644 index 3fc13245708e85..00000000000000 --- a/x-pack/plugins/snapshot_restore/public/application/lib/authorization/components/not_authorized_section.tsx +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; -import { EuiEmptyPrompt } from '@elastic/eui'; - -interface Props { - title: React.ReactNode; - message: React.ReactNode | string; -} - -export const NotAuthorizedSection = ({ title, message }: Props) => ( - {title}} body={

{message}

} /> -); diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_details/policy_details.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_details/policy_details.tsx index f3110199ee17c6..03d381c9f3aa3d 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_details/policy_details.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_details/policy_details.tsx @@ -26,6 +26,7 @@ import { import { SlmPolicy } from '../../../../../../common/types'; import { useServices } from '../../../../app_context'; +import { SectionError, Error } from '../../../../../shared_imports'; import { UIM_POLICY_DETAIL_PANEL_SUMMARY_TAB, UIM_POLICY_DETAIL_PANEL_HISTORY_TAB, @@ -34,11 +35,9 @@ import { useLoadPolicy } from '../../../../services/http'; import { linkToEditPolicy, linkToSnapshot } from '../../../../services/navigation'; import { - SectionError, SectionLoading, PolicyExecuteProvider, PolicyDeleteProvider, - Error, } from '../../../../components'; import { TabSummary, TabHistory } from './tabs'; diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_list.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_list.tsx index 0122e25e5e1657..51297038b0f3fa 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_list.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_list.tsx @@ -9,13 +9,19 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { RouteComponentProps } from 'react-router-dom'; import { EuiEmptyPrompt, EuiButton, EuiCallOut, EuiSpacer } from '@elastic/eui'; +import { + SectionError, + Error, + WithPrivileges, + NotAuthorizedSection, +} from '../../../../shared_imports'; + import { SlmPolicy } from '../../../../../common/types'; -import { APP_SLM_CLUSTER_PRIVILEGES } from '../../../../../common/constants'; -import { SectionError, SectionLoading, Error } from '../../../components'; +import { APP_SLM_CLUSTER_PRIVILEGES } from '../../../../../common'; +import { SectionLoading } from '../../../components'; import { BASE_PATH, UIM_POLICY_LIST_LOAD } from '../../../constants'; import { useLoadPolicies, useLoadRetentionSettings } from '../../../services/http'; import { linkToAddPolicy, linkToPolicy } from '../../../services/navigation'; -import { WithPrivileges, NotAuthorizedSection } from '../../../lib/authorization'; import { useServices } from '../../../app_context'; import { PolicyDetails } from './policy_details'; diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_table/policy_table.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_table/policy_table.tsx index 7f9c5c5af7705c..ba28bcddf53470 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_table/policy_table.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_table/policy_table.tsx @@ -21,6 +21,7 @@ import { } from '@elastic/eui'; import { SlmPolicy } from '../../../../../../common/types'; +import { Error } from '../../../../../shared_imports'; import { UIM_POLICY_SHOW_DETAILS_CLICK } from '../../../../constants'; import { useServices } from '../../../../app_context'; import { @@ -28,7 +29,6 @@ import { PolicyExecuteProvider, PolicyDeleteProvider, } from '../../../../components'; -import { Error } from '../../../../components/section_error'; import { linkToAddPolicy, linkToEditPolicy } from '../../../../services/navigation'; import { SendRequestResponse } from '../../../../../shared_imports'; diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/home/repository_list/repository_details/repository_details.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/home/repository_list/repository_details/repository_details.tsx index d293f194f647a0..9932f146640760 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/home/repository_list/repository_details/repository_details.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/home/repository_list/repository_details/repository_details.tsx @@ -25,6 +25,8 @@ import { import 'brace/theme/textmate'; +import { SectionError, Error } from '../../../../../shared_imports'; + import { useServices } from '../../../../app_context'; import { documentationLinksService } from '../../../../services/documentation'; import { @@ -35,7 +37,8 @@ import { import { textService } from '../../../../services/text'; import { linkToSnapshots, linkToEditRepository } from '../../../../services/navigation'; -import { REPOSITORY_TYPES } from '../../../../../../common/constants'; +import { REPOSITORY_TYPES } from '../../../../../../common'; + import { Repository, RepositoryVerification, @@ -43,10 +46,8 @@ import { } from '../../../../../../common/types'; import { RepositoryDeleteProvider, - SectionError, SectionLoading, RepositoryVerificationBadge, - Error, } from '../../../../components'; import { TypeDetails } from './type_details'; diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/home/repository_list/repository_list.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/home/repository_list/repository_list.tsx index 6fa12537e9d6f8..2256fa5991decf 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/home/repository_list/repository_list.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/home/repository_list/repository_list.tsx @@ -10,7 +10,8 @@ import { RouteComponentProps } from 'react-router-dom'; import { EuiButton, EuiEmptyPrompt } from '@elastic/eui'; import { Repository } from '../../../../../common/types'; -import { SectionError, SectionLoading, Error } from '../../../components'; +import { SectionError, Error } from '../../../../shared_imports'; +import { SectionLoading } from '../../../components'; import { BASE_PATH, UIM_REPOSITORY_LIST_LOAD } from '../../../constants'; import { useServices } from '../../../app_context'; import { useLoadRepositories } from '../../../services/http'; diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/home/repository_list/repository_table/repository_table.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/home/repository_list/repository_table/repository_table.tsx index 7c0438f6b837fa..bf2643d78bca16 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/home/repository_list/repository_table/repository_table.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/home/repository_list/repository_table/repository_table.tsx @@ -15,15 +15,14 @@ import { EuiIconTip, } from '@elastic/eui'; -import { REPOSITORY_TYPES } from '../../../../../../common/constants'; +import { REPOSITORY_TYPES } from '../../../../../../common'; import { Repository, RepositoryType } from '../../../../../../common/types'; -import { Error } from '../../../../components/section_error'; +import { Error, SendRequestResponse } from '../../../../../shared_imports'; import { RepositoryDeleteProvider } from '../../../../components'; import { UIM_REPOSITORY_SHOW_DETAILS_CLICK } from '../../../../constants'; import { useServices } from '../../../../app_context'; import { textService } from '../../../../services/text'; import { linkToEditRepository, linkToAddRepository } from '../../../../services/navigation'; -import { SendRequestResponse } from '../../../../../shared_imports'; interface Props { repositories: Repository[]; diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/home/restore_list/restore_list.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/home/restore_list/restore_list.tsx index da9ce3b124a11a..0e3d9363d05359 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/home/restore_list/restore_list.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/home/restore_list/restore_list.tsx @@ -18,14 +18,19 @@ import { EuiLoadingSpinner, EuiLink, } from '@elastic/eui'; -import { APP_RESTORE_INDEX_PRIVILEGES } from '../../../../../common/constants'; -import { SectionError, SectionLoading, Error } from '../../../components'; +import { APP_RESTORE_INDEX_PRIVILEGES } from '../../../../../common'; +import { + WithPrivileges, + NotAuthorizedSection, + SectionError, + Error, +} from '../../../../shared_imports'; +import { SectionLoading } from '../../../components'; import { UIM_RESTORE_LIST_LOAD } from '../../../constants'; import { useLoadRestores } from '../../../services/http'; import { linkToSnapshots } from '../../../services/navigation'; import { useServices } from '../../../app_context'; import { RestoreTable } from './restore_table'; -import { WithPrivileges, NotAuthorizedSection } from '../../../lib/authorization'; const ONE_SECOND_MS = 1000; const TEN_SECONDS_MS = 10 * 1000; diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/snapshot_details/snapshot_details.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/snapshot_details/snapshot_details.tsx index d16545debe1ecf..1943762a3c36e9 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/snapshot_details/snapshot_details.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/snapshot_details/snapshot_details.tsx @@ -23,12 +23,8 @@ import React, { Fragment, useState, useEffect } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { SnapshotDetails as ISnapshotDetails } from '../../../../../../common/types'; -import { - SectionError, - SectionLoading, - SnapshotDeleteProvider, - Error, -} from '../../../../components'; +import { SectionError, Error } from '../../../../../shared_imports'; +import { SectionLoading, SnapshotDeleteProvider } from '../../../../components'; import { useServices } from '../../../../app_context'; import { UIM_SNAPSHOT_DETAIL_PANEL_SUMMARY_TAB, diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/snapshot_list.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/snapshot_list.tsx index fe99ccb6f596c8..30e4c771644bc0 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/snapshot_list.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/snapshot_list.tsx @@ -10,10 +10,10 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { RouteComponentProps } from 'react-router-dom'; import { EuiButton, EuiCallOut, EuiLink, EuiEmptyPrompt, EuiSpacer, EuiIcon } from '@elastic/eui'; -import { APP_SLM_CLUSTER_PRIVILEGES } from '../../../../../common/constants'; -import { SectionError, SectionLoading, Error } from '../../../components'; +import { APP_SLM_CLUSTER_PRIVILEGES } from '../../../../../common'; +import { WithPrivileges, SectionError, Error } from '../../../../shared_imports'; +import { SectionLoading } from '../../../components'; import { BASE_PATH, UIM_SNAPSHOT_LIST_LOAD } from '../../../constants'; -import { WithPrivileges } from '../../../lib/authorization'; import { documentationLinksService } from '../../../services/documentation'; import { useLoadSnapshots } from '../../../services/http'; import { diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/snapshot_table/snapshot_table.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/snapshot_table/snapshot_table.tsx index ad64dcc7adcfee..427c241970007e 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/snapshot_table/snapshot_table.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/snapshot_table/snapshot_table.tsx @@ -17,10 +17,10 @@ import { } from '@elastic/eui'; import { SnapshotDetails } from '../../../../../../common/types'; +import { Error } from '../../../../../shared_imports'; import { SNAPSHOT_STATE, UIM_SNAPSHOT_SHOW_DETAILS_CLICK } from '../../../../constants'; import { useServices } from '../../../../app_context'; import { linkToRepository, linkToRestoreSnapshot } from '../../../../services/navigation'; -import { Error } from '../../../../components/section_error'; import { DataPlaceholder, FormattedDateTime, SnapshotDeleteProvider } from '../../../../components'; import { SendRequestResponse } from '../../../../../shared_imports'; diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/policy_add/policy_add.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/policy_add/policy_add.tsx index 4eb0f54978d094..6d1a432be7f9f0 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/policy_add/policy_add.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/policy_add/policy_add.tsx @@ -9,9 +9,11 @@ import { RouteComponentProps } from 'react-router-dom'; import { EuiPageBody, EuiPageContent, EuiSpacer, EuiTitle } from '@elastic/eui'; import { SlmPolicyPayload } from '../../../../common/types'; -import { TIME_UNITS } from '../../../../common/constants'; +import { TIME_UNITS } from '../../../../common'; -import { PolicyForm, SectionError, SectionLoading, Error } from '../../components'; +import { SectionError, Error } from '../../../shared_imports'; + +import { PolicyForm, SectionLoading } from '../../components'; import { BASE_PATH, DEFAULT_POLICY_SCHEDULE } from '../../constants'; import { breadcrumbService, docTitleService } from '../../services/navigation'; import { addPolicy, useLoadIndices } from '../../services/http'; diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/policy_edit/policy_edit.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/policy_edit/policy_edit.tsx index 9ca7eba5c4eebb..0f1473fc054925 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/policy_edit/policy_edit.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/policy_edit/policy_edit.tsx @@ -9,8 +9,9 @@ import { RouteComponentProps } from 'react-router-dom'; import { EuiPageBody, EuiPageContent, EuiSpacer, EuiTitle, EuiCallOut } from '@elastic/eui'; import { SlmPolicyPayload } from '../../../../common/types'; +import { SectionError, Error } from '../../../shared_imports'; import { TIME_UNITS } from '../../../../common/constants'; -import { SectionError, SectionLoading, PolicyForm, Error } from '../../components'; +import { SectionLoading, PolicyForm } from '../../components'; import { BASE_PATH } from '../../constants'; import { useServices } from '../../app_context'; import { breadcrumbService, docTitleService } from '../../services/navigation'; diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/repository_add/repository_add.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/repository_add/repository_add.tsx index 126e04bc7dc1d7..08bfde833c3688 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/repository_add/repository_add.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/repository_add/repository_add.tsx @@ -12,7 +12,9 @@ import { RouteComponentProps } from 'react-router-dom'; import { EuiPageBody, EuiPageContent, EuiSpacer, EuiTitle } from '@elastic/eui'; import { Repository, EmptyRepository } from '../../../../common/types'; -import { RepositoryForm, SectionError } from '../../components'; +import { SectionError } from '../../../shared_imports'; + +import { RepositoryForm } from '../../components'; import { BASE_PATH, Section } from '../../constants'; import { breadcrumbService, docTitleService } from '../../services/navigation'; import { addRepository } from '../../services/http'; diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/repository_edit/repository_edit.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/repository_edit/repository_edit.tsx index aa29b8b9f05518..95f8b9b8bde7d0 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/repository_edit/repository_edit.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/repository_edit/repository_edit.tsx @@ -10,7 +10,8 @@ import { RouteComponentProps } from 'react-router-dom'; import { EuiCallOut, EuiPageBody, EuiPageContent, EuiSpacer, EuiTitle } from '@elastic/eui'; import { Repository, EmptyRepository } from '../../../../common/types'; -import { RepositoryForm, SectionError, SectionLoading, Error } from '../../components'; +import { SectionError, Error } from '../../../shared_imports'; +import { RepositoryForm, SectionLoading } from '../../components'; import { BASE_PATH, Section } from '../../constants'; import { useServices } from '../../app_context'; import { breadcrumbService, docTitleService } from '../../services/navigation'; diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/restore_snapshot/restore_snapshot.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/restore_snapshot/restore_snapshot.tsx index 252fd07a85f800..9eabed8341ee02 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/restore_snapshot/restore_snapshot.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/restore_snapshot/restore_snapshot.tsx @@ -9,8 +9,9 @@ import { RouteComponentProps } from 'react-router-dom'; import { EuiPageBody, EuiPageContent, EuiSpacer, EuiTitle } from '@elastic/eui'; import { SnapshotDetails, RestoreSettings } from '../../../../common/types'; +import { SectionError, Error } from '../../../shared_imports'; import { BASE_PATH } from '../../constants'; -import { SectionError, SectionLoading, RestoreSnapshotForm, Error } from '../../components'; +import { SectionLoading, RestoreSnapshotForm } from '../../components'; import { useServices } from '../../app_context'; import { breadcrumbService, docTitleService } from '../../services/navigation'; import { useLoadSnapshot, executeRestore } from '../../services/http'; diff --git a/x-pack/plugins/snapshot_restore/public/application/services/http/use_request.ts b/x-pack/plugins/snapshot_restore/public/application/services/http/use_request.ts index 200d601fd2ce98..27a565ccb74bc9 100644 --- a/x-pack/plugins/snapshot_restore/public/application/services/http/use_request.ts +++ b/x-pack/plugins/snapshot_restore/public/application/services/http/use_request.ts @@ -9,11 +9,10 @@ import { UseRequestConfig, sendRequest as _sendRequest, useRequest as _useRequest, + Error as CustomError, } from '../../../shared_imports'; -import { Error as CustomError } from '../../components/section_error'; - -import { httpService } from './index'; +import { httpService } from '.'; export const sendRequest = (config: SendRequestConfig) => { return _sendRequest(httpService.httpClient, config); diff --git a/x-pack/plugins/snapshot_restore/public/shared_imports.ts b/x-pack/plugins/snapshot_restore/public/shared_imports.ts index 7e7ef09d0c09dc..e0024ea8e0c126 100644 --- a/x-pack/plugins/snapshot_restore/public/shared_imports.ts +++ b/x-pack/plugins/snapshot_restore/public/shared_imports.ts @@ -12,4 +12,10 @@ export { useRequest, CronEditor, DAY, + SectionError, + Error, + WithPrivileges, + useAuthorizationContext, + NotAuthorizedSection, + AuthorizationProvider, } from '../../../../src/plugins/es_ui_shared/public'; diff --git a/x-pack/plugins/snapshot_restore/server/routes/api/app.ts b/x-pack/plugins/snapshot_restore/server/routes/api/app.ts index 5d334fddc144bc..bda64fdb665714 100644 --- a/x-pack/plugins/snapshot_restore/server/routes/api/app.ts +++ b/x-pack/plugins/snapshot_restore/server/routes/api/app.ts @@ -3,12 +3,13 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { Privileges } from '../../../common/types'; +import { Privileges } from '../../../../../../src/plugins/es_ui_shared/public'; + import { APP_REQUIRED_CLUSTER_PRIVILEGES, APP_RESTORE_INDEX_PRIVILEGES, APP_SLM_CLUSTER_PRIVILEGES, -} from '../../../common/constants'; +} from '../../../common'; import { RouteDependencies } from '../../types'; import { addBasePath } from '../helpers'; 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 f2a9995098e594..5dfe3d3e99a7f3 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 @@ -31,7 +31,6 @@ const kibana = { const getContext = () => ({ version: '8675309-snapshot', - isDev: true, logger: coreMock.createPluginInitializerContext().logger.get('test'), }); diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 7f5bd0eda809b3..877f8163c44b9c 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -850,8 +850,6 @@ "data.search.searchSource.indexPatternIdDescription": "{kibanaIndexPattern} インデックス内の ID です。", "data.search.searchSource.indexPatternIdLabel": "インデックスパターン ID", "data.search.searchSource.indexPatternLabel": "インデックスパターン", - "data.search.searchSource.noSearchStrategyRegisteredErrorMessageDescription": "検索リクエストの検索方法が見つかりませんでした", - "data.search.searchSource.noSearchStrategyRegisteredErrorMessageTitle": "検索方法が登録されていません", "data.search.searchSource.queryTimeDescription": "クエリの処理の所要時間です。リクエストの送信やブラウザでのパースの時間は含まれません。", "data.search.searchSource.queryTimeLabel": "クエリ時間", "data.search.searchSource.queryTimeValue": "{queryTime}ms", @@ -2252,7 +2250,6 @@ "kbn.management.editIndexPattern.scripted.table.nameHeader": "名前", "kbn.management.editIndexPattern.scripted.table.scriptDescription": "フィールドのスクリプトです", "kbn.management.editIndexPattern.scripted.table.scriptHeader": "スクリプト", - "kbn.management.editIndexPattern.scripted.unknownModeErrorMessage": "不明なフィールド設定モード {mode}", "kbn.management.editIndexPattern.scriptedHeader": "スクリプトフィールド", "kbn.management.editIndexPattern.scriptedLabel": "ビジュアライゼーションにスクリプトフィールドを使用し、ドキュメントに表示させることができます。但し、スクリプトフィールドは検索できません。", "kbn.management.editIndexPattern.setDefaultAria": "デフォルトのインデックスに設定", @@ -8800,8 +8797,6 @@ "xpack.logstash.idFormatErrorMessage": "パイプライン ID は文字またはアンダーラインで始まる必要があり、文字、アンダーライン、ハイフン、数字のみ使用できます", "xpack.logstash.insufficientUserPermissionsDescription": "Logstash パイプラインの管理に必要なユーザーパーミッションがありません", "xpack.logstash.kibanaManagementPipelinesTitle": "Kibana の管理で作成されたパイプラインだけがここに表示されます", - "xpack.logstash.managementSection.createPipelineTitle": "パイプラインの作成", - "xpack.logstash.managementSection.editPipelineTitle": "パイプラインの編集", "xpack.logstash.managementSection.enableSecurityDescription": "Logstash パイプライン管理機能を使用するには、セキュリティを有効にする必要があります。elasticsearch.yml で xpack.security.enabled: true に設定してください。", "xpack.logstash.managementSection.licenseDoesNotSupportDescription": "ご使用の {licenseType} ライセンスは Logstash パイプライン管理をサポートしていません。ライセンスをアップグレードしてください。", "xpack.logstash.managementSection.notPossibleToManagePipelinesMessage": "現在ライセンス情報が利用できないため Logstash パイプラインを使用できません。", @@ -9492,8 +9487,6 @@ "xpack.ml.dataframe.analytics.classificationExploration.evaluateJobIdTitle": "分類ジョブID {jobId}の評価", "xpack.ml.dataframe.analytics.classificationExploration.firstDocumentsShownHelpText": "予測がある最初の{searchSize}のドキュメントを示す", "xpack.ml.dataframe.analytics.classificationExploration.generalizationDocsCount": "{docsCount, plural, one {# doc} other {# docs}}が評価されました", - "xpack.ml.dataframe.analytics.classificationExploration.indexArrayBadgeContent": "配列", - "xpack.ml.dataframe.analytics.classificationExploration.indexArrayToolTipContent": "この配列ベースの列の完全なコンテンツは表示できません。", "xpack.ml.dataframe.analytics.classificationExploration.jobCapsFetchError": "結果を取得できません。インデックスのフィールドデータの読み込み中にエラーが発生しました。", "xpack.ml.dataframe.analytics.classificationExploration.jobConfigurationFetchError": "結果を取得できません。ジョブ構成データの読み込み中にエラーが発生しました。", "xpack.ml.dataframe.analytics.classificationExploration.jobConfigurationNoResultsMessage": "結果が見つかりませんでした。", @@ -9588,8 +9581,6 @@ "xpack.ml.dataframe.analytics.regressionExploration.generalizationDocsCount": "{docsCount, plural, one {# doc} other {# docs}}が評価されました", "xpack.ml.dataframe.analytics.regressionExploration.generalizationErrorTitle": "一般化エラー", "xpack.ml.dataframe.analytics.regressionExploration.indexError": "インデックスデータの読み込み中にエラーが発生しました。", - "xpack.ml.dataframe.analytics.regressionExploration.isTestingLabel": "テスト", - "xpack.ml.dataframe.analytics.regressionExploration.isTrainingLabel": "トレーニング", "xpack.ml.dataframe.analytics.regressionExploration.jobCapsFetchError": "結果を取得できません。インデックスのフィールドデータの読み込み中にエラーが発生しました。", "xpack.ml.dataframe.analytics.regressionExploration.jobConfigurationFetchError": "結果を取得できません。ジョブ構成データの読み込み中にエラーが発生しました。", "xpack.ml.dataframe.analytics.regressionExploration.meanSquaredErrorText": "平均二乗エラー", @@ -9601,9 +9592,6 @@ "xpack.ml.dataframe.analytics.regressionExploration.queryParsingErrorMessage": "クエリをパースできません。", "xpack.ml.dataframe.analytics.regressionExploration.rSquaredText": "R の二乗", "xpack.ml.dataframe.analytics.regressionExploration.rSquaredTooltipContent": "適合度を表します。モデルによる観察された結果の複製の効果を測定します。", - "xpack.ml.dataframe.analytics.regressionExploration.searchBoxPlaceholder": "例: 平均>0.5", - "xpack.ml.dataframe.analytics.regressionExploration.selectColumnsAriaLabel": "列を選択", - "xpack.ml.dataframe.analytics.regressionExploration.selectFieldsPopoverTitle": "フィールドを選択", "xpack.ml.dataframe.analytics.regressionExploration.tableJobIdTitle": "回帰ジョブID {jobId}のデスティネーションインデックス", "xpack.ml.dataframe.analytics.regressionExploration.trainingDocsCount": "{docsCount, plural, one {# doc} other {# docs}}が評価されました", "xpack.ml.dataframe.analytics.regressionExploration.trainingErrorTitle": "トレーニングエラー", @@ -15972,7 +15960,7 @@ "xpack.triggersActionsUI.sections.alertAdd.saveButtonLabel": "保存", "xpack.triggersActionsUI.sections.alertAdd.saveErrorNotificationText": "アラートを作成できません。", "xpack.triggersActionsUI.sections.alertAdd.saveSuccessNotificationText": "「{alertName}」 を保存しました", - "xpack.triggersActionsUI.sections.alertAdd.selectIndex": "インデックスを選択してください。", + "xpack.triggersActionsUI.sections.alertAdd.selectIndex": "インデックスを選択してください", "xpack.triggersActionsUI.sections.alertAdd.threshold.closeIndexPopoverLabel": "閉じる", "xpack.triggersActionsUI.sections.alertAdd.threshold.fixErrorInExpressionBelowValidationMessage": "下の表現のエラーを修正してください。", "xpack.triggersActionsUI.sections.alertAdd.threshold.howToBroadenSearchQueryDescription": "* で検索クエリの範囲を広げます。", @@ -16056,7 +16044,6 @@ "xpack.triggersActionsUI.sections.alertsList.bulkActionPopover.muteAllTitle": "ミュート", "xpack.triggersActionsUI.sections.alertsList.bulkActionPopover.unmuteAllTitle": "ミュート解除", "xpack.triggersActionsUI.sections.alertsList.collapsedItemActons.deleteTitle": "削除", - "xpack.triggersActionsUI.sections.alertsList.collapsedItemActons.enableTitle": "有効にする", "xpack.triggersActionsUI.sections.alertsList.collapsedItemActons.muteTitle": "ミュート", "xpack.triggersActionsUI.sections.alertsList.collapsedItemActons.popoverButtonTitle": "アクション", "xpack.triggersActionsUI.components.emptyPrompt.emptyButton": "アラートの作成", @@ -16778,4 +16765,4 @@ "xpack.watcher.watchEdit.thresholdWatchExpression.aggType.fieldIsRequiredValidationMessage": "フィールドを選択してください。", "xpack.watcher.watcherDescription": "アラートの作成、管理、監視によりデータへの変更を検知します。" } -} +} \ No newline at end of file diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 6fc2e1f146086a..2aac5dd24a1b3c 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -851,8 +851,6 @@ "data.search.searchSource.indexPatternIdDescription": "{kibanaIndexPattern} 索引中的 ID。", "data.search.searchSource.indexPatternIdLabel": "索引模式 ID", "data.search.searchSource.indexPatternLabel": "索引模式", - "data.search.searchSource.noSearchStrategyRegisteredErrorMessageDescription": "无法为该搜索请求找到搜索策略", - "data.search.searchSource.noSearchStrategyRegisteredErrorMessageTitle": "未注册任何搜索策略", "data.search.searchSource.queryTimeDescription": "处理查询所花费的时间。不包括发送请求或在浏览器中解析它的时间。", "data.search.searchSource.queryTimeLabel": "查询时间", "data.search.searchSource.queryTimeValue": "{queryTime}ms", @@ -2253,7 +2251,6 @@ "kbn.management.editIndexPattern.scripted.table.nameHeader": "名称", "kbn.management.editIndexPattern.scripted.table.scriptDescription": "字段的脚本", "kbn.management.editIndexPattern.scripted.table.scriptHeader": "脚本", - "kbn.management.editIndexPattern.scripted.unknownModeErrorMessage": "未知 fieldSettings 模式 {mode}", "kbn.management.editIndexPattern.scriptedHeader": "脚本字段", "kbn.management.editIndexPattern.scriptedLabel": "可以在可视化中使用脚本字段,并在您的文档中显示它们。但是,您不能搜索脚本字段。", "kbn.management.editIndexPattern.setDefaultAria": "设置为默认索引", @@ -8803,8 +8800,6 @@ "xpack.logstash.idFormatErrorMessage": "管道 ID 必须以字母或下划线开头,并只能包含字母、下划线、短划线和数字", "xpack.logstash.insufficientUserPermissionsDescription": "管理 Logstash 管道的用户权限不足", "xpack.logstash.kibanaManagementPipelinesTitle": "仅在 Kibana“管理”中创建的管道显示在此处", - "xpack.logstash.managementSection.createPipelineTitle": "创建管道", - "xpack.logstash.managementSection.editPipelineTitle": "编辑管道", "xpack.logstash.managementSection.enableSecurityDescription": "必须启用 Security,才能使用 Logstash 管道管理功能。请在 elasticsearch.yml 中设置 xpack.security.enabled: true。", "xpack.logstash.managementSection.licenseDoesNotSupportDescription": "您的{licenseType}许可不支持 Logstash 管道管理功能。请升级您的许可。", "xpack.logstash.managementSection.notPossibleToManagePipelinesMessage": "您不能管理 Logstash 管道,因为许可信息当前不可用。", @@ -9495,8 +9490,6 @@ "xpack.ml.dataframe.analytics.classificationExploration.evaluateJobIdTitle": "分类作业 ID {jobId} 的评估", "xpack.ml.dataframe.analytics.classificationExploration.firstDocumentsShownHelpText": "正在显示有相关预测存在的前 {searchSize} 个文档", "xpack.ml.dataframe.analytics.classificationExploration.generalizationDocsCount": "{docsCount, plural, one {# 个文档} other {# 个文档}}已评估", - "xpack.ml.dataframe.analytics.classificationExploration.indexArrayBadgeContent": "数组", - "xpack.ml.dataframe.analytics.classificationExploration.indexArrayToolTipContent": "此基于数组的列的完整内容无法显示。", "xpack.ml.dataframe.analytics.classificationExploration.jobCapsFetchError": "无法提取结果。加载索引的字段数据时发生错误。", "xpack.ml.dataframe.analytics.classificationExploration.jobConfigurationFetchError": "无法提取结果。加载作业配置数据时发生错误。", "xpack.ml.dataframe.analytics.classificationExploration.jobConfigurationNoResultsMessage": "未找到结果。", @@ -9591,8 +9584,6 @@ "xpack.ml.dataframe.analytics.regressionExploration.generalizationDocsCount": "{docsCount, plural, one {# 个文档} other {# 个文档}}已评估", "xpack.ml.dataframe.analytics.regressionExploration.generalizationErrorTitle": "泛化误差", "xpack.ml.dataframe.analytics.regressionExploration.indexError": "加载索引数据时出错。", - "xpack.ml.dataframe.analytics.regressionExploration.isTestingLabel": "测试", - "xpack.ml.dataframe.analytics.regressionExploration.isTrainingLabel": "培训", "xpack.ml.dataframe.analytics.regressionExploration.jobCapsFetchError": "无法提取结果。加载索引的字段数据时发生错误。", "xpack.ml.dataframe.analytics.regressionExploration.jobConfigurationFetchError": "无法提取结果。加载作业配置数据时发生错误。", "xpack.ml.dataframe.analytics.regressionExploration.meanSquaredErrorText": "均方误差", @@ -9604,9 +9595,6 @@ "xpack.ml.dataframe.analytics.regressionExploration.queryParsingErrorMessage": "无法解析查询。", "xpack.ml.dataframe.analytics.regressionExploration.rSquaredText": "R 平方", "xpack.ml.dataframe.analytics.regressionExploration.rSquaredTooltipContent": "表示拟合优度。度量模型复制被观察结果的优良性。", - "xpack.ml.dataframe.analytics.regressionExploration.searchBoxPlaceholder": "例如 avg>0.5", - "xpack.ml.dataframe.analytics.regressionExploration.selectColumnsAriaLabel": "选择列", - "xpack.ml.dataframe.analytics.regressionExploration.selectFieldsPopoverTitle": "选择字段", "xpack.ml.dataframe.analytics.regressionExploration.tableJobIdTitle": "回归作业 ID {jobId} 的目标索引", "xpack.ml.dataframe.analytics.regressionExploration.trainingDocsCount": "{docsCount, plural, one {# 个文档} other {# 个文档}}已评估", "xpack.ml.dataframe.analytics.regressionExploration.trainingErrorTitle": "训练误差", @@ -15969,7 +15957,7 @@ "xpack.triggersActionsUI.sections.addModalConnectorForm.updateSuccessNotificationText": "已创建“{connectorName}”", "xpack.triggersActionsUI.sections.alertAdd.betaBadgeTooltipContent": "{pluginName} 为公测版,可能会进行更改。设计和代码相对于正式发行版功能还不够成熟,将按原样提供,且不提供任何保证。公测版功能不受正式发行版功能支持 SLA 的约束。", "xpack.triggersActionsUI.sections.alertAdd.cancelButtonLabel": "取消", - "xpack.triggersActionsUI.sections.alertAdd.conditionPrompt": "定义条件。", + "xpack.triggersActionsUI.sections.alertAdd.conditionPrompt": "定义条件", "xpack.triggersActionsUI.sections.alertAdd.errorLoadingAlertVisualizationTitle": "无法加载告警可视化", "xpack.triggersActionsUI.sections.alertAdd.flyoutTitle": "创建告警", "xpack.triggersActionsUI.sections.alertAdd.loadingAlertVisualizationDescription": "正在加载告警可视化……", @@ -15977,7 +15965,7 @@ "xpack.triggersActionsUI.sections.alertAdd.saveButtonLabel": "保存", "xpack.triggersActionsUI.sections.alertAdd.saveErrorNotificationText": "无法创建告警。", "xpack.triggersActionsUI.sections.alertAdd.saveSuccessNotificationText": "已保存“{alertName}”", - "xpack.triggersActionsUI.sections.alertAdd.selectIndex": "选择索引。", + "xpack.triggersActionsUI.sections.alertAdd.selectIndex": "选择索引", "xpack.triggersActionsUI.sections.alertAdd.threshold.closeIndexPopoverLabel": "关闭", "xpack.triggersActionsUI.sections.alertAdd.threshold.fixErrorInExpressionBelowValidationMessage": "表达式包含错误。", "xpack.triggersActionsUI.sections.alertAdd.threshold.howToBroadenSearchQueryDescription": "使用 * 可扩大您的查询范围。", @@ -16061,7 +16049,6 @@ "xpack.triggersActionsUI.sections.alertsList.bulkActionPopover.muteAllTitle": "静音", "xpack.triggersActionsUI.sections.alertsList.bulkActionPopover.unmuteAllTitle": "取消静音", "xpack.triggersActionsUI.sections.alertsList.collapsedItemActons.deleteTitle": "删除", - "xpack.triggersActionsUI.sections.alertsList.collapsedItemActons.enableTitle": "启用", "xpack.triggersActionsUI.sections.alertsList.collapsedItemActons.muteTitle": "静音", "xpack.triggersActionsUI.sections.alertsList.collapsedItemActons.popoverButtonTitle": "操作", "xpack.triggersActionsUI.components.emptyPrompt.emptyButton": "创建告警", @@ -16783,4 +16770,4 @@ "xpack.watcher.watchEdit.thresholdWatchExpression.aggType.fieldIsRequiredValidationMessage": "此字段必填。", "xpack.watcher.watcherDescription": "通过创建、管理和监测警报来检测数据中的更改。" } -} +} \ No newline at end of file diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_alert_types/threshold/expression.scss b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_alert_types/threshold/expression.scss index d0a7039ae24e17..3734cf5d5218bf 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_alert_types/threshold/expression.scss +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_alert_types/threshold/expression.scss @@ -1,3 +1,13 @@ .actAlertVisualization__chart { - height: $euiSize * 15; + height: $euiSize * 14; +} + +.actAddAlertSteps { + .euiStep__titleWrapper { + align-items: center; + } + + .euiStep__title { + @include euiTitle('xs'); + } } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_alert_types/threshold/expression.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_alert_types/threshold/expression.tsx index 7557b17f5b67dd..43955db97f2957 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_alert_types/threshold/expression.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_alert_types/threshold/expression.tsx @@ -283,7 +283,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent @@ -396,7 +396,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent @@ -445,12 +445,10 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent ) : null} - - +
{canShowVizualization ? ( - void }) => ( data-test-subj="createFirstAlertButton" key="create-action" fill - iconType="plusInCircle" - iconSide="left" onClick={onCTAClicked} > - - - - - -
- - - - - - {checkEnabledResult.isEnabled === false && ( - - - - )} - - -
-
-
- - } - extraAction={ - { - const updatedActions = actions.filter((_item: AlertAction, i: number) => i !== index); - setAlertProperty(updatedActions); - setIsAddActionPanelOpen( - updatedActions.filter((item: AlertAction) => item.id !== actionItem.id).length === 0 - ); - setActiveActionItem(undefined); - }} - /> - } - paddingSize="l" - > - {accordionContent} - + + + + + + + +

+ + + + + + {checkEnabledResult.isEnabled === false && ( + + + + )} + + +

+
+
+ + } + extraAction={ + { + const updatedActions = actions.filter( + (_item: AlertAction, i: number) => i !== index + ); + setAlertProperty(updatedActions); + setIsAddActionPanelOpen( + updatedActions.filter((item: AlertAction) => item.id !== actionItem.id).length === + 0 + ); + setActiveActionItem(undefined); + }} + /> + } + paddingSize="l" + > + {accordionContent} +
+ +
); }; @@ -341,96 +349,103 @@ export const ActionForm = ({ const actionTypeRegistered = actionTypeRegistry.get(actionItem.actionTypeId); if (!actionTypeRegistered || actionItem.group !== defaultActionGroupId) return null; return ( - - - - - - -
- -
-
-
- - } - extraAction={ - { - const updatedActions = actions.filter((_item: AlertAction, i: number) => i !== index); - setAlertProperty(updatedActions); - setIsAddActionPanelOpen( - updatedActions.filter((item: AlertAction) => item.id !== actionItem.id).length === 0 - ); - setActiveActionItem(undefined); - }} - /> - } - paddingSize="l" - > - actionItem.id === emptyId) ? ( - - ) : ( - - ) + + + + + + + +

+ +

+
+
+ } - actions={[ - { - setActiveActionItem({ actionTypeId: actionItem.actionTypeId, index }); - setAddModalVisibility(true); + const updatedActions = actions.filter( + (_item: AlertAction, i: number) => i !== index + ); + setAlertProperty(updatedActions); + setIsAddActionPanelOpen( + updatedActions.filter((item: AlertAction) => item.id !== actionItem.id).length === + 0 + ); + setActiveActionItem(undefined); }} - > - - , - ]} - /> -
+ /> + } + paddingSize="l" + > + actionItem.id === emptyId) ? ( + + ) : ( + + ) + } + actions={[ + { + setActiveActionItem({ actionTypeId: actionItem.actionTypeId, index }); + setAddModalVisibility(true); + }} + > + + , + ]} + /> +
+ +
); }; @@ -537,19 +552,34 @@ export const ActionForm = ({ ) : ( - {alertActionsList} - - {isAddActionPanelOpen === false ? ( - setIsAddActionPanelOpen(true)} - > + +

- +

+
+ + {alertActionsList} + {isAddActionPanelOpen === false ? ( +
+ + + + setIsAddActionPanelOpen(true)} + > + + + + +
) : null} {isAddActionPanelOpen ? ( @@ -558,7 +588,7 @@ export const ActionForm = ({
@@ -571,6 +601,7 @@ export const ActionForm = ({ - + {isLoadingActionTypes ? ( { data-test-subj="createActionButton" key="create-action" fill - iconType="plusInCircle" - iconSide="left" onClick={() => setAddFlyoutVisibility(true)} > { key="create-alert" data-test-subj="createAlertButton" fill - iconType="plusInCircle" - iconSide="left" onClick={() => setAlertFlyoutVisibility(true)} > = ({ isOpen={isPopoverOpen} closePopover={() => setIsPopoverOpen(false)} ownFocus + panelPaddingSize="none" data-test-subj="collapsedItemActions" > - - { - if (item.enabled) { - await disableAlert(item); - } else { - await enableAlert(item); + +
+ { + if (item.enabled) { + await disableAlert(item); + } else { + await enableAlert(item); + } + onAlertChanged(); + }} + label={ + } - onAlertChanged(); - }} - label={ + /> + + - } - /> - - - { - if (item.muteAll) { - await unmuteAlert(item); - } else { - await muteAlert(item); + +
+
+ { + if (item.muteAll) { + await unmuteAlert(item); + } else { + await muteAlert(item); + } + onAlertChanged(); + }} + label={ + } - onAlertChanged(); - }} - label={ + /> + + - } - /> - - - - setAlertsToDelete([item.id])} - > - - - - + +
+ + setAlertsToDelete([item.id])} + > +
+
+ +
+
+ +

+ +

+
+
+
+
+
); }; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/alert_quick_edit_buttons.scss b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/alert_quick_edit_buttons.scss new file mode 100644 index 00000000000000..a5b4cc258c1b59 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/alert_quick_edit_buttons.scss @@ -0,0 +1,5 @@ +.actBulkActionPopover__deleteAll { + .euiButtonEmpty__text { + padding-top: $euiSizeXS; + } +} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/alert_quick_edit_buttons.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/alert_quick_edit_buttons.tsx index eeae0cf54f1a19..26bc8b869a06bd 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/alert_quick_edit_buttons.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/alert_quick_edit_buttons.tsx @@ -5,9 +5,9 @@ */ import { i18n } from '@kbn/i18n'; -import React, { useState, Fragment } from 'react'; +import React, { useState } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiButtonEmpty } from '@elastic/eui'; +import { EuiButtonEmpty, EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; import { Alert } from '../../../../types'; import { useAppDependencies } from '../../../app_context'; @@ -15,6 +15,7 @@ import { withBulkAlertOperations, ComponentOpts as BulkOperationsComponentOpts, } from './with_bulk_alert_api_operations'; +import './alert_quick_edit_buttons.scss'; export type ComponentOpts = { selectedItems: Alert[]; @@ -147,72 +148,84 @@ export const AlertQuickEditButtons: React.FunctionComponent = ({ } return ( - + {!allAlertsMuted && ( - - - + + + + + )} {allAlertsMuted && ( - - - + + + + + )} {allAlertsDisabled && ( - - - + + + + + )} {!allAlertsDisabled && ( + + + + + + )} + - )} - - - - - + +
); }; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/bulk_operation_popover.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/bulk_operation_popover.tsx index d0fd0e17928183..935b0bd8985ca8 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/bulk_operation_popover.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/bulk_operation_popover.tsx @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useState } from 'react'; +import React, { useState, Fragment } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiButton, EuiFormRow, EuiPopover } from '@elastic/eui'; +import { EuiButton, EuiPopover } from '@elastic/eui'; export const BulkOperationPopover: React.FunctionComponent = ({ children }) => { const [isPopoverOpen, setIsPopoverOpen] = useState(false); @@ -16,6 +16,7 @@ export const BulkOperationPopover: React.FunctionComponent = ({ children }) => { isOpen={isPopoverOpen} closePopover={() => setIsPopoverOpen(false)} data-test-subj="bulkAction" + panelPaddingSize="s" button={ { > {children && React.Children.map(children, child => - React.isValidElement(child) ? ( - {React.cloneElement(child, {})} - ) : ( - child - ) + React.isValidElement(child) ? {React.cloneElement(child, {})} : child )} ); diff --git a/x-pack/test/api_integration/apis/logstash/pipeline/delete.ts b/x-pack/test/api_integration/apis/logstash/pipeline/delete.ts index cdbf5a3e6a1fea..2463dbe4500b5f 100644 --- a/x-pack/test/api_integration/apis/logstash/pipeline/delete.ts +++ b/x-pack/test/api_integration/apis/logstash/pipeline/delete.ts @@ -20,7 +20,6 @@ export default function({ getService }: FtrProviderContext) { .send({ id: 'fast_generator', description: 'foobar baz', - username: 'seger', pipeline: 'input { generator {} }\n\n output { stdout {} }', }) .expect(204); diff --git a/x-pack/test/api_integration/apis/logstash/pipeline/save.ts b/x-pack/test/api_integration/apis/logstash/pipeline/save.ts index 2ca9fbe7d68e00..ca0cfb19b9454d 100644 --- a/x-pack/test/api_integration/apis/logstash/pipeline/save.ts +++ b/x-pack/test/api_integration/apis/logstash/pipeline/save.ts @@ -28,7 +28,6 @@ export default function({ getService }: FtrProviderContext) { .send({ id: 'fast_generator', description: 'foobar baz', - username: 'seger', pipeline: 'input { generator {} }\n\n output { stdout {} }', }) .expect(204); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/utils.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/utils.ts index cebe24dc5ccc28..e508cf1aaa2e03 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/utils.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/utils.ts @@ -154,7 +154,7 @@ export const getSimpleRuleOutput = (ruleId = 'rule-1'): Partial { await testSubjects.click('collapsedItemActions'); - await pageObjects.triggersActionsUI.toggleSwitch('enableSwitch'); + await pageObjects.triggersActionsUI.toggleSwitch('disableSwitch'); await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); await testSubjects.click('collapsedItemActions'); - const enableSwitchAfterDisable = await testSubjects.find('enableSwitch'); - const isChecked = await enableSwitchAfterDisable.getAttribute('aria-checked'); - expect(isChecked).to.eql('false'); + const disableSwitchAfterDisable = await testSubjects.find('disableSwitch'); + const isChecked = await disableSwitchAfterDisable.getAttribute('aria-checked'); + expect(isChecked).to.eql('true'); }); it('should re-enable single alert', async () => { @@ -361,21 +361,21 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.click('collapsedItemActions'); - await pageObjects.triggersActionsUI.toggleSwitch('enableSwitch'); + await pageObjects.triggersActionsUI.toggleSwitch('disableSwitch'); await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); await testSubjects.click('collapsedItemActions'); - await pageObjects.triggersActionsUI.toggleSwitch('enableSwitch'); + await pageObjects.triggersActionsUI.toggleSwitch('disableSwitch'); await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); await testSubjects.click('collapsedItemActions'); - const enableSwitchAfterReEnable = await testSubjects.find('enableSwitch'); - const isChecked = await enableSwitchAfterReEnable.getAttribute('aria-checked'); - expect(isChecked).to.eql('true'); + const disableSwitchAfterReEnable = await testSubjects.find('disableSwitch'); + const isChecked = await disableSwitchAfterReEnable.getAttribute('aria-checked'); + expect(isChecked).to.eql('false'); }); it('should mute single alert', async () => { @@ -504,9 +504,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.click('collapsedItemActions'); - const enableSwitch = await testSubjects.find('enableSwitch'); - const isChecked = await enableSwitch.getAttribute('aria-checked'); - expect(isChecked).to.eql('false'); + const disableSwitch = await testSubjects.find('disableSwitch'); + const isChecked = await disableSwitch.getAttribute('aria-checked'); + expect(isChecked).to.eql('true'); }); it('should enable all selection', async () => { @@ -529,9 +529,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.click('collapsedItemActions'); - const enableSwitch = await testSubjects.find('enableSwitch'); - const isChecked = await enableSwitch.getAttribute('aria-checked'); - expect(isChecked).to.eql('true'); + const disableSwitch = await testSubjects.find('disableSwitch'); + const isChecked = await disableSwitch.getAttribute('aria-checked'); + expect(isChecked).to.eql('false'); }); it('should delete all selection', async () => { diff --git a/x-pack/test/reporting/functional/reporting.js b/x-pack/test/reporting/functional/reporting.js index b3ef1ab2b54b4f..86fe2fd0393efc 100644 --- a/x-pack/test/reporting/functional/reporting.js +++ b/x-pack/test/reporting/functional/reporting.js @@ -14,6 +14,7 @@ export default function({ getService, getPageObjects }) { const esArchiver = getService('esArchiver'); const browser = getService('browser'); const log = getService('log'); + const filterBar = getService('filterBar'); const PageObjects = getPageObjects([ 'reporting', 'common', @@ -123,7 +124,27 @@ export default function({ getService, getPageObjects }) { expect(await PageObjects.reporting.isGenerateReportButtonDisabled()).to.be(null); }); + it('becomes available/not available when a saved search is created, changed and saved again', async () => { + // create new search, csv export is not available + await PageObjects.discover.clickNewSearchButton(); + await PageObjects.reporting.openCsvReportingPanel(); + expect(await PageObjects.reporting.isGenerateReportButtonDisabled()).to.be('true'); + // save search, csv export is available + await PageObjects.discover.saveSearch('my search - expectEnabledGenerateReportButton 2'); + await PageObjects.reporting.openCsvReportingPanel(); + expect(await PageObjects.reporting.isGenerateReportButtonDisabled()).to.be(null); + // add filter, csv export is not available + await filterBar.addFilter('currency', 'is', 'EUR'); + await PageObjects.reporting.openCsvReportingPanel(); + expect(await PageObjects.reporting.isGenerateReportButtonDisabled()).to.be('true'); + // save search again, csv export is available + await PageObjects.discover.saveSearch('my search - expectEnabledGenerateReportButton 2'); + await PageObjects.reporting.openCsvReportingPanel(); + expect(await PageObjects.reporting.isGenerateReportButtonDisabled()).to.be(null); + }); + it('generates a report with data', async () => { + await PageObjects.discover.clickNewSearchButton(); await PageObjects.reporting.setTimepickerInDataRange(); await PageObjects.discover.saveSearch('my search - with data - expectReportCanBeCreated'); await PageObjects.reporting.openCsvReportingPanel(); diff --git a/yarn.lock b/yarn.lock index 260ba05a3d2b44..a7f5ca0cc388b7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1172,30 +1172,29 @@ debug "^3.1.0" lodash.once "^4.1.1" -"@elastic/apm-rum-core@^4.7.0": - version "4.7.0" - resolved "https://registry.yarnpkg.com/@elastic/apm-rum-core/-/apm-rum-core-4.7.0.tgz#b00b58bf7380f2e36652e5333e3ca97608986e40" - integrity sha512-/lTZWfA3ces3qoKCx72Sc+w43lZkyktaQlbYoYO86h3tNX7tScc/7YBBHI9oxKMcXweqkKOcpnwNZFy71bb86w== +"@elastic/apm-rum-core@^5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@elastic/apm-rum-core/-/apm-rum-core-5.2.0.tgz#2ed30dc226c9b5779532ab2e6065a155587bcea4" + integrity sha512-3ti2dhrqfxjHFXgArQI/sVAG2AgZH0kB1nx+2WjLpuAh8gGS4R772M5VXcWcGQb8UW9jrANwwbW2hT2GKv+uOA== dependencies: error-stack-parser "^1.3.5" - es6-promise "^4.2.8" opentracing "^0.14.3" - uuid "^3.1.0" + promise-polyfill "^8.1.3" -"@elastic/apm-rum-react@^0.3.2": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@elastic/apm-rum-react/-/apm-rum-react-0.3.2.tgz#134634643e15ebcf97b6f17b2c74a50afdbe1c64" - integrity sha512-hU1srW9noygppyrLmipulu30c+LWEie8V/dQjEqLYMx2mRZRwNIue3midYgWa6qrWqgYZhwpAtWrWcXc+AWk2Q== +"@elastic/apm-rum-react@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@elastic/apm-rum-react/-/apm-rum-react-1.1.1.tgz#3a2ba91efc9260da55ef6c31cce642a476eba828" + integrity sha512-ZMixw+82VbZIDBnz0dj5Fo4PZ7pnXlLjAA7XTi3AtSIEjpsZa7YIuCFzJdrgb/nOq7MOFkODkFPTiIYAM/yCqg== dependencies: - "@elastic/apm-rum" "^4.6.0" + "@elastic/apm-rum" "^5.1.1" hoist-non-react-statics "^3.3.0" -"@elastic/apm-rum@^4.6.0": - version "4.6.0" - resolved "https://registry.yarnpkg.com/@elastic/apm-rum/-/apm-rum-4.6.0.tgz#e2ac560dd4a4761c0e9b08c301418b1d4063bdd2" - integrity sha512-hsqvyTm5rT6lKgV06wvm8ID9aMsuJyw8wIOPjRwKmvzlTjayabxKTcr50lJJV8jY9OWfDkqymIqpHyCEChQAHQ== +"@elastic/apm-rum@^5.1.1": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@elastic/apm-rum/-/apm-rum-5.1.1.tgz#02d29fa606e66f9a3a88f629d468b02457b1b183" + integrity sha512-A0O/0ZffcHm1taLuXyFoUmV2+aARr+9+xbmsEDIExLV0yKaNlaLl3UaZrodSOZ1ijlCEsRRS+y2i0md93YKQTA== dependencies: - "@elastic/apm-rum-core" "^4.7.0" + "@elastic/apm-rum-core" "^5.2.0" "@elastic/charts@18.3.0": version "18.3.0" @@ -4415,10 +4414,10 @@ dependencies: "@types/node" "*" -"@types/papaparse@^4.5.11": - version "4.5.11" - resolved "https://registry.yarnpkg.com/@types/papaparse/-/papaparse-4.5.11.tgz#dcd4f64da55f768c2e2cf92ccac1973c67a73890" - integrity sha512-zOw6K7YyA/NuZ2yZ8lzZFe2U3fn+vFfcRfiQp4ZJHG6y8WYWy2SYFbq6mp4yUgpIruJHBjKZtgyE0vvCoWEq+A== +"@types/papaparse@^5.0.3": + version "5.0.3" + resolved "https://registry.yarnpkg.com/@types/papaparse/-/papaparse-5.0.3.tgz#7cedc1ebc9484819af8306a8b42f9f08ca9bdb44" + integrity sha512-SgWGWnBGxl6XgjKDM2eoDg163ZFQtH6m6C2aOuaAf1T2gUB3rjaiPDDARbY9WlacRgZqieRG9imAfJaJ+5ouDA== dependencies: "@types/node" "*" @@ -12205,7 +12204,7 @@ es6-promise@^4.2.5: resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.6.tgz#b685edd8258886365ea62b57d30de28fadcd974f" integrity sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q== -es6-promise@^4.2.8, es6-promise@~4.2.4: +es6-promise@~4.2.4: version "4.2.8" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== @@ -22446,10 +22445,10 @@ pako@~1.0.5: resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" integrity sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg== -papaparse@^4.6.3: - version "4.6.3" - resolved "https://registry.yarnpkg.com/papaparse/-/papaparse-4.6.3.tgz#742e5eaaa97fa6c7e1358d2934d8f18f44aee781" - integrity sha512-LRq7BrHC2kHPBYSD50aKuw/B/dGcg29omyJbKWY3KsYUZU69RKwaBHu13jGmCYBtOc4odsLCrFyk6imfyNubJQ== +papaparse@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/papaparse/-/papaparse-5.2.0.tgz#97976a1b135c46612773029153dc64995caa3b7b" + integrity sha512-ylq1wgUSnagU+MKQtNeVqrPhZuMYBvOSL00DHycFTCxownF95gpLAk1HiHdUW77N8yxRq1qHXLdlIPyBSG9NSA== parallel-transform@^1.1.0: version "1.1.0" @@ -23440,6 +23439,11 @@ promise-inflight@^1.0.1: resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= +promise-polyfill@^8.1.3: + version "8.1.3" + resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-8.1.3.tgz#8c99b3cf53f3a91c68226ffde7bde81d7f904116" + integrity sha512-MG5r82wBzh7pSKDRa9y+vllNHz3e3d4CNj1PQE4BQYxLme0gKYYBm9YENq+UkEikyZ0XbiGWxYlVw3Rl9O/U8g== + promise.prototype.finally@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/promise.prototype.finally/-/promise.prototype.finally-3.1.0.tgz#66f161b1643636e50e7cf201dc1b84a857f3864e" @@ -30693,7 +30697,7 @@ utils-regex-from-string@^1.0.0: regex-regex "^1.0.0" validate.io-string-primitive "^1.0.0" -uuid@3.3.2, uuid@^3.0.1, uuid@^3.1.0, uuid@^3.3.2: +uuid@3.3.2, uuid@^3.0.1, uuid@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== @@ -30708,6 +30712,11 @@ uuid@^3.0.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" integrity sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g== +uuid@^3.1.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + v8-compile-cache@2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe"