diff --git a/.eslintrc.js b/.eslintrc.js index 60d26cbfbab738..3d6a5c262c453d 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -142,7 +142,7 @@ module.exports = { }, }, { - files: ['x-pack/legacy/plugins/ml/**/*.{js,ts,tsx}'], + files: ['x-pack/plugins/ml/**/*.{js,ts,tsx}'], rules: { 'react-hooks/exhaustive-deps': 'off', }, @@ -322,6 +322,7 @@ module.exports = { 'x-pack/test/functional/apps/**/*.js', 'x-pack/legacy/plugins/apm/**/*.js', 'test/*/config.ts', + 'test/*/config_open.ts', 'test/*/{tests,test_suites,apis,apps}/**/*', 'test/visual_regression/tests/**/*', 'x-pack/test/*/{tests,test_suites,apis,apps}/**/*', diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a9af160d020841..accc99170bb709 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -26,7 +26,7 @@ /src/plugins/kibana_legacy/ @elastic/kibana-app /src/plugins/timelion/ @elastic/kibana-app /src/plugins/dev_tools/ @elastic/kibana-app -/src/plugins/dashboard_embeddable_container/ @elastic/kibana-app +/src/plugins/dashboard/ @elastic/kibana-app # App Architecture /packages/kbn-interpreter/ @elastic/kibana-app-arch diff --git a/.i18nrc.json b/.i18nrc.json index 6874d02304e490..07878ed3c15fb4 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -3,7 +3,7 @@ "common.ui": "src/legacy/ui", "console": "src/plugins/console", "core": "src/core", - "dashboardEmbeddableContainer": "src/plugins/dashboard_embeddable_container", + "dashboard": "src/plugins/dashboard", "data": [ "src/legacy/core_plugins/data", "src/plugins/data" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index aec6d44ad4abfb..5c745f1611cce9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -171,6 +171,8 @@ Bootstrap Kibana and install all the dependencies yarn kbn bootstrap ``` +> Node.js native modules could be in use and node-gyp is the tool used to build them. There are tools you need to install per platform and python versions you need to be using. Please see https://github.com/nodejs/node-gyp#installation and follow the guide according your platform. + (You can also run `yarn kbn` to see the other available commands. For more info about this tool, see https://github.com/elastic/kibana/tree/master/packages/kbn-pm.) When switching branches which use different versions of npm packages you may need to run; diff --git a/docs/apm/advanced-queries.asciidoc b/docs/apm/advanced-queries.asciidoc index ed77ebb4c49306..add6f601489e1e 100644 --- a/docs/apm/advanced-queries.asciidoc +++ b/docs/apm/advanced-queries.asciidoc @@ -5,7 +5,7 @@ When querying in the APM app, you're simply searching and selecting data from fi Queries entered into the query bar are also added as parameters to the URL, so it's easy to share a specific query or view with others. -In the screenshot below, you can begin to see some of the transaction fields available for filtering on: +You can begin to see some of the transaction fields available for filtering: [role="screenshot"] image::apm/images/apm-query-bar.png[Example of the Kibana Query bar in APM app in Kibana] diff --git a/docs/apm/spans.asciidoc b/docs/apm/spans.asciidoc index b1d54ce49c7cdc..b09de576f2d4ac 100644 --- a/docs/apm/spans.asciidoc +++ b/docs/apm/spans.asciidoc @@ -12,12 +12,12 @@ This makes it useful for visualizing where the selected transaction spent most o image::apm/images/apm-transaction-sample.png[Example of distributed trace colors in the APM app in Kibana] View a span in detail by clicking on it in the timeline waterfall. -For example, in the below screenshot we've clicked on an SQL Select database query. -The information displayed includes the actual SQL that was executed, how long it took, +When you click on an SQL Select database query, +the information displayed includes the actual SQL that was executed, how long it took, and the percentage of the trace's total time. You also get a stack trace, which shows the SQL query in your code. Finally, APM knows which files are your code and which are just modules or libraries that you've installed. -These library frames will be minimized by default in order to show you the most relevant stack trace. +These library frames will be minimized by default in order to show you the most relevant stack trace. [role="screenshot"] image::apm/images/apm-span-detail.png[Example view of a span detail in the APM app in Kibana] diff --git a/docs/apm/transactions.asciidoc b/docs/apm/transactions.asciidoc index 9c21a569f152c3..536ab2ec29c80f 100644 --- a/docs/apm/transactions.asciidoc +++ b/docs/apm/transactions.asciidoc @@ -50,7 +50,7 @@ If there's a particular endpoint you're worried about, you can click on it to vi [IMPORTANT] ==== If you only see one route in the Transactions table, or if you have transactions named "unknown route", -it could be a symptom that the agent either wasn't installed correctly or doesn't support your framework. +it could be a symptom that the agent either wasn't installed correctly or doesn't support your framework. For further details, including troubleshooting and custom implementation instructions, refer to the documentation for each {apm-agents-ref}[APM Agent] you've implemented. @@ -103,9 +103,7 @@ The number of requests per bucket is displayed when hovering over the graph, and [role="screenshot"] image::apm/images/apm-transaction-duration-dist.png[Example view of transactions duration distribution graph] -Let's look at an example. -In the screenshot below, -you'll notice most of the requests fall into buckets on the left side of the graph, +Most of the requests fall into buckets on the left side of the graph, with a long tail of smaller buckets to the right. This is a typical distribution, and indicates most of our requests were served quickly - awesome! It's the requests on the right, the ones taking longer than average, that we probably want to focus on. @@ -133,4 +131,4 @@ For a particular transaction sample, we can get even more information in the *me * Custom - You can configure your agent to add custom contextual information on transactions. TIP: All of this data is stored in documents in Elasticsearch. -This means you can select "Actions - View sample document" to see the actual Elasticsearch document under the discover tab. \ No newline at end of file +This means you can select "Actions - View sample document" to see the actual Elasticsearch document under the discover tab. diff --git a/docs/canvas/canvas-tinymath-functions.asciidoc b/docs/canvas/canvas-tinymath-functions.asciidoc index 8c9f445b052a3d..73808fc6625d12 100644 --- a/docs/canvas/canvas-tinymath-functions.asciidoc +++ b/docs/canvas/canvas-tinymath-functions.asciidoc @@ -3,21 +3,21 @@ === TinyMath functions TinyMath provides a set of functions that can be used with the Canvas expression -language to perform complex math calculations. Read on for detailed information about -the functions available in TinyMath, including what parameters each function accepts, +language to perform complex math calculations. Read on for detailed information about +the functions available in TinyMath, including what parameters each function accepts, the return value of that function, and examples of how each function behaves. -Most of the functions below accept arrays and apply JavaScript Math methods to -each element of that array. For the functions that accept multiple arrays as -parameters, the function generally does the calculation index by index. +Most of the functions accept arrays and apply JavaScript Math methods to +each element of that array. For the functions that accept multiple arrays as +parameters, the function generally does the calculation index by index. -Any function below can be wrapped by another function as long as the return type +Any function can be wrapped by another function as long as the return type of the inner function matches the acceptable parameter type of the outer function. [float] === abs( a ) -Calculates the absolute value of a number. For arrays, the function will be +Calculates the absolute value of a number. For arrays, the function will be applied index-wise to each element. [cols="3*^<"] @@ -29,7 +29,7 @@ applied index-wise to each element. |a number or an array of numbers |=== -*Returns*: `number` | `Array.`. The absolute value of `a`. Returns +*Returns*: `number` | `Array.`. The absolute value of `a`. Returns an array with the absolute values of each element if `a` is an array. *Example* @@ -43,7 +43,7 @@ abs([-1 , -2, 3, -4]) // returns [1, 2, 3, 4] [float] === add( ...args ) -Calculates the sum of one or more numbers/arrays passed into the function. If at +Calculates the sum of one or more numbers/arrays passed into the function. If at least one array of numbers is passed into the function, the function will calculate the sum by index. [cols="3*^<"] @@ -55,9 +55,9 @@ least one array of numbers is passed into the function, the function will calcul |one or more numbers or arrays of numbers |=== -*Returns*: `number` | `Array.`. The sum of all numbers in `args` if `args` -contains only numbers. Returns an array of sums of the elements at each index, -including all scalar numbers in `args` in the calculation at each index if `args` +*Returns*: `number` | `Array.`. The sum of all numbers in `args` if `args` +contains only numbers. Returns an array of sums of the elements at each index, +including all scalar numbers in `args` in the calculation at each index if `args` contains at least one array. *Throws*: `'Array length mismatch'` if `args` contains arrays of different lengths @@ -73,7 +73,7 @@ add([1, 2], 3, [4, 5], 6) // returns [(1 + 3 + 4 + 6), (2 + 3 + 5 + 6)] = [14, 1 [float] === cbrt( a ) -Calculates the cube root of a number. For arrays, the function will be applied +Calculates the cube root of a number. For arrays, the function will be applied index-wise to each element. [cols="3*^<"] @@ -85,7 +85,7 @@ index-wise to each element. |a number or an array of numbers |=== -*Returns*: `number` | `Array.`. The cube root of `a`. Returns an array with +*Returns*: `number` | `Array.`. The cube root of `a`. Returns an array with the cube roots of each element if `a` is an array. *Example* @@ -99,7 +99,7 @@ cbrt([27, 64, 125]) // returns [3, 4, 5] [float] === ceil( a ) -Calculates the ceiling of a number, i.e., rounds a number towards positive infinity. +Calculates the ceiling of a number, i.e., rounds a number towards positive infinity. For arrays, the function will be applied index-wise to each element. [cols="3*^<"] @@ -111,7 +111,7 @@ For arrays, the function will be applied index-wise to each element. |a number or an array of numbers |=== -*Returns*: `number` | `Array.`. The ceiling of `a`. Returns an array with +*Returns*: `number` | `Array.`. The ceiling of `a`. Returns an array with the ceilings of each element if `a` is an array. *Example* @@ -125,7 +125,7 @@ ceil([1.1, 2.2, 3.3]) // returns [2, 3, 4] [float] === clamp( ...a, min, max ) -Restricts value to a given range and returns closed available value. If only `min` +Restricts value to a given range and returns closed available value. If only `min` is provided, values are restricted to only a lower bound. [cols="3*^<"] @@ -145,11 +145,11 @@ is provided, values are restricted to only a lower bound. |(optional) The maximum value this function will return. |=== -*Returns*: `number` | `Array.`. The closest value between `min` (inclusive) -and `max` (inclusive). Returns an array with values greater than or equal to `min` +*Returns*: `number` | `Array.`. The closest value between `min` (inclusive) +and `max` (inclusive). Returns an array with values greater than or equal to `min` and less than or equal to `max` (if provided) at each index. -*Throws*: +*Throws*: - `'Array length mismatch'` if a `min` and/or `max` are arrays of different lengths @@ -194,7 +194,7 @@ count(100) // returns 1 [float] === cube( a ) -Calculates the cube of a number. For arrays, the function will be applied +Calculates the cube of a number. For arrays, the function will be applied index-wise to each element. [cols="3*^<"] @@ -206,7 +206,7 @@ index-wise to each element. |a number or an array of numbers |=== -*Returns*: `number` | `Array.`. The cube of `a`. Returns an array +*Returns*: `number` | `Array.`. The cube of `a`. Returns an array with the cubes of each element if `a` is an array. *Example* @@ -219,7 +219,7 @@ cube([3, 4, 5]) // returns [27, 64, 125] [float] === divide( a, b ) -Divides two numbers. If at least one array of numbers is passed into the function, +Divides two numbers. If at least one array of numbers is passed into the function, the function will be applied index-wise to each element. [cols="3*^<"] @@ -235,8 +235,8 @@ the function will be applied index-wise to each element. |divisor, a number or an array of numbers, b != 0 |=== -*Returns*: `number` | `Array.`. Returns the quotient of `a` and `b` -if both are numbers. Returns an array with the quotients applied index-wise to +*Returns*: `number` | `Array.`. Returns the quotient of `a` and `b` +if both are numbers. Returns an array with the quotients applied index-wise to each element if `a` or `b` is an array. *Throws*: @@ -257,7 +257,7 @@ divide([14, 42, 65, 108], [2, 7, 5, 12]) // returns [7, 6, 13, 9] [float] === exp( a ) -Calculates _e^x_ where _e_ is Euler's number. For arrays, the function will be applied +Calculates _e^x_ where _e_ is Euler's number. For arrays, the function will be applied index-wise to each element. [cols="3*^<"] @@ -269,7 +269,7 @@ index-wise to each element. |a number or an array of numbers |=== -*Returns*: `number` | `Array.`. Returns an array with the values of +*Returns*: `number` | `Array.`. Returns an array with the values of `e^x` evaluated where `x` is each element of `a` if `a` is an array. *Example* @@ -282,7 +282,7 @@ exp([1, 2, 3]) // returns [e^1, e^2, e^3] = [2.718281828459045, 7.38905609893064 [float] === first( a ) -Returns the first element of an array. If anything other than an array is passed +Returns the first element of an array. If anything other than an array is passed in, the input is returned. [cols="3*^<"] @@ -306,7 +306,7 @@ first([1, 2, 3]) // returns 1 [float] === fix( a ) -Calculates the fix of a number, i.e., rounds a number towards 0. For arrays, the +Calculates the fix of a number, i.e., rounds a number towards 0. For arrays, the function will be applied index-wise to each element. [cols="3*^<"] @@ -318,7 +318,7 @@ function will be applied index-wise to each element. |a number or an array of numbers |=== -*Returns*: `number` | `Array.`. The fix of `a`. Returns an array with +*Returns*: `number` | `Array.`. The fix of `a`. Returns an array with the fixes for each element if `a` is an array. *Example* @@ -332,7 +332,7 @@ fix([1.8, 2.9, -3.7, -4.6]) // returns [1, 2, -3, -4] [float] === floor( a ) -Calculates the floor of a number, i.e., rounds a number towards negative infinity. +Calculates the floor of a number, i.e., rounds a number towards negative infinity. For arrays, the function will be applied index-wise to each element. [cols="3*^<"] @@ -344,7 +344,7 @@ For arrays, the function will be applied index-wise to each element. |a number or an array of numbers |=== -*Returns*: `number` | `Array.`. The floor of `a`. Returns an array +*Returns*: `number` | `Array.`. The floor of `a`. Returns an array with the floor of each element if `a` is an array. *Example* @@ -358,7 +358,7 @@ floor([1.7, 2.8, 3.9]) // returns [1, 2, 3] [float] === last( a ) -Returns the last element of an array. If anything other than an array is passed +Returns the last element of an array. If anything other than an array is passed in, the input is returned. [cols="3*^<"] @@ -382,7 +382,7 @@ last([1, 2, 3]) // returns 3 [float] === log( a, b ) -Calculates the logarithm of a number. For arrays, the function will be applied +Calculates the logarithm of a number. For arrays, the function will be applied index-wise to each element. [cols="3*^<"] @@ -398,7 +398,7 @@ index-wise to each element. |(optional) base for the logarithm. If not provided a value, the default base is e, and the natural log is calculated. |=== -*Returns*: `number` | `Array.`. The logarithm of `a`. Returns an array +*Returns*: `number` | `Array.`. The logarithm of `a`. Returns an array with the the logarithms of each element if `a` is an array. *Throws*: @@ -419,7 +419,7 @@ log([2, 4, 8, 16, 32], 2) // returns [1, 2, 3, 4, 5] [float] === log10( a ) -Calculates the logarithm base 10 of a number. For arrays, the function will be +Calculates the logarithm base 10 of a number. For arrays, the function will be applied index-wise to each element. [cols="3*^<"] @@ -431,7 +431,7 @@ applied index-wise to each element. |a number or an array of numbers, `a` must be greater than 0 |=== -*Returns*: `number` | `Array.`. The logarithm of `a`. Returns an array +*Returns*: `number` | `Array.`. The logarithm of `a`. Returns an array with the the logarithms base 10 of each element if `a` is an array. *Throws*: `'Must be greater than 0'` if `a` < 0 @@ -448,8 +448,8 @@ log([10, 100, 1000, 10000, 100000]) // returns [1, 2, 3, 4, 5] [float] === max( ...args ) -Finds the maximum value of one of more numbers/arrays of numbers passed into the function. -If at least one array of numbers is passed into the function, the function will +Finds the maximum value of one of more numbers/arrays of numbers passed into the function. +If at least one array of numbers is passed into the function, the function will find the maximum by index. [cols="3*^<"] @@ -461,9 +461,9 @@ find the maximum by index. |one or more numbers or arrays of numbers |=== -*Returns*: `number` | `Array.`. The maximum value of all numbers if -`args` contains only numbers. Returns an array with the the maximum values at each -index, including all scalar numbers in `args` in the calculation at each index if +*Returns*: `number` | `Array.`. The maximum value of all numbers if +`args` contains only numbers. Returns an array with the the maximum values at each +index, including all scalar numbers in `args` in the calculation at each index if `args` contains at least one array. *Throws*: `'Array length mismatch'` if `args` contains arrays of different lengths @@ -479,8 +479,8 @@ max([1, 9], 4, [3, 5]) // returns [max([1, 4, 3]), max([9, 4, 5])] = [4, 9] [float] === mean( ...args ) -Finds the mean value of one of more numbers/arrays of numbers passed into the function. -If at least one array of numbers is passed into the function, the function will +Finds the mean value of one of more numbers/arrays of numbers passed into the function. +If at least one array of numbers is passed into the function, the function will find the mean by index. [cols="3*^<"] @@ -492,9 +492,9 @@ find the mean by index. |one or more numbers or arrays of numbers |=== -*Returns*: `number` | `Array.`. The maximum value of all numbers if -`args` contains only numbers. Returns an array with the the maximum values at each -index, including all scalar numbers in `args` in the calculation at each index if +*Returns*: `number` | `Array.`. The maximum value of all numbers if +`args` contains only numbers. Returns an array with the the maximum values at each +index, including all scalar numbers in `args` in the calculation at each index if `args` contains at least one array. *Throws*: `'Array length mismatch'` if `args` contains arrays of different lengths @@ -510,8 +510,8 @@ max([1, 9], 4, [3, 5]) // returns [max([1, 4, 3]), max([9, 4, 5])] = [4, 9] [float] === mean( ...args ) -Finds the mean value of one of more numbers/arrays of numbers passed into the function. -If at least one array of numbers is passed into the function, the function will +Finds the mean value of one of more numbers/arrays of numbers passed into the function. +If at least one array of numbers is passed into the function, the function will find the mean by index. [cols="3*^<"] @@ -523,9 +523,9 @@ find the mean by index. |one or more numbers or arrays of numbers |=== -*Returns*: `number` | `Array.`. The mean value of all numbers if `args` -contains only numbers. Returns an array with the the mean values of each index, -including all scalar numbers in `args` in the calculation at each index if `args` +*Returns*: `number` | `Array.`. The mean value of all numbers if `args` +contains only numbers. Returns an array with the the mean values of each index, +including all scalar numbers in `args` in the calculation at each index if `args` contains at least one array. *Example* @@ -539,8 +539,8 @@ mean([1, 9], 5, [3, 4]) // returns [mean([1, 5, 3]), mean([9, 5, 4])] = [3, 6] [float] === median( ...args ) -Finds the median value(s) of one of more numbers/arrays of numbers passed into the function. -If at least one array of numbers is passed into the function, the function will +Finds the median value(s) of one of more numbers/arrays of numbers passed into the function. +If at least one array of numbers is passed into the function, the function will find the median by index. [cols="3*^<"] @@ -552,9 +552,9 @@ find the median by index. |one or more numbers or arrays of numbers |=== -*Returns*: `number` | `Array.`. The median value of all numbers if `args` -contains only numbers. Returns an array with the the median values of each index, -including all scalar numbers in `args` in the calculation at each index if `args` +*Returns*: `number` | `Array.`. The median value of all numbers if `args` +contains only numbers. Returns an array with the the median values of each index, +including all scalar numbers in `args` in the calculation at each index if `args` contains at least one array. *Example* @@ -569,8 +569,8 @@ median([1, 9], 2, 4, [3, 5]) // returns [median([1, 2, 4, 3]), median([9, 2, 4, [float] === min( ...args ) -Finds the minimum value of one of more numbers/arrays of numbers passed into the function. -If at least one array of numbers is passed into the function, the function will +Finds the minimum value of one of more numbers/arrays of numbers passed into the function. +If at least one array of numbers is passed into the function, the function will find the minimum by index. [cols="3*^<"] @@ -582,9 +582,9 @@ find the minimum by index. |one or more numbers or arrays of numbers |=== -*Returns*: `number` | `Array.`. The minimum value of all numbers if -`args` contains only numbers. Returns an array with the the minimum values of each -index, including all scalar numbers in `args` in the calculation at each index if `a` +*Returns*: `number` | `Array.`. The minimum value of all numbers if +`args` contains only numbers. Returns an array with the the minimum values of each +index, including all scalar numbers in `args` in the calculation at each index if `a` is an array. *Throws*: `'Array length mismatch'` if `args` contains arrays of different lengths. @@ -600,7 +600,7 @@ min([1, 9], 4, [3, 5]) // returns [min([1, 4, 3]), min([9, 4, 5])] = [1, 4] [float] === mod( a, b ) -Remainder after dividing two numbers. If at least one array of numbers is passed +Remainder after dividing two numbers. If at least one array of numbers is passed into the function, the function will be applied index-wise to each element. [cols="3*^<"] @@ -616,8 +616,8 @@ into the function, the function will be applied index-wise to each element. |divisor, a number or an array of numbers, b != 0 |=== -*Returns*: `number` | `Array.`. The remainder of `a` divided by `b` if -both are numbers. Returns an array with the the remainders applied index-wise to +*Returns*: `number` | `Array.`. The remainder of `a` divided by `b` if +both are numbers. Returns an array with the the remainders applied index-wise to each element if `a` or `b` is an array. *Throws*: @@ -638,8 +638,8 @@ mod([14, 42, 65, 108], [5, 4, 14, 2]) // returns [5, 2, 9, 0] [float] === mode( ...args ) -Finds the mode value(s) of one of more numbers/arrays of numbers passed into the function. -If at least one array of numbers is passed into the function, the function will +Finds the mode value(s) of one of more numbers/arrays of numbers passed into the function. +If at least one array of numbers is passed into the function, the function will find the mode by index. [cols="3*^<"] @@ -651,9 +651,9 @@ find the mode by index. |one or more numbers or arrays of numbers |=== -*Returns*: `number` | `Array.>`. An array of mode value(s) of all -numbers if `args` contains only numbers. Returns an array of arrays with mode value(s) -of each index, including all scalar numbers in `args` in the calculation at each index +*Returns*: `number` | `Array.>`. An array of mode value(s) of all +numbers if `args` contains only numbers. Returns an array of arrays with mode value(s) +of each index, including all scalar numbers in `args` in the calculation at each index if `args` contains at least one array. *Example* @@ -668,7 +668,7 @@ mode([1, 9], 1, 4, [3, 5]) // returns [mode([1, 1, 4, 3]), mode([9, 1, 4, 5])] = [float] === multiply( a, b ) -Multiplies two numbers. If at least one array of numbers is passed into the function, +Multiplies two numbers. If at least one array of numbers is passed into the function, the function will be applied index-wise to each element. [cols="3*^<"] @@ -684,11 +684,11 @@ the function will be applied index-wise to each element. |a number or an array of numbers |=== -*Returns*: `number` | `Array.`. The product of `a` and `b` if both are -numbers. Returns an array with the the products applied index-wise to each element +*Returns*: `number` | `Array.`. The product of `a` and `b` if both are +numbers. Returns an array with the the products applied index-wise to each element if `a` or `b` is an array. -*Throws*: `'Array length mismatch'` if `a` and `b` are arrays with different lengths +*Throws*: `'Array length mismatch'` if `a` and `b` are arrays with different lengths *Example* [source, js] @@ -702,7 +702,7 @@ multiply([1, 2, 3, 4], [2, 7, 5, 12]) // returns [2, 14, 15, 48] [float] === pow( a, b ) -Calculates the cube root of a number. For arrays, the function will be applied +Calculates the cube root of a number. For arrays, the function will be applied index-wise to each element. [cols="3*^<"] @@ -718,7 +718,7 @@ index-wise to each element. |the power that `a` is raised to |=== -*Returns*: `number` | `Array.`. `a` raised to the power of `b`. Returns +*Returns*: `number` | `Array.`. `a` raised to the power of `b`. Returns an array with the each element raised to the power of `b` if `a` is an array. *Throws*: `'Missing exponent'` if `b` is not provided @@ -733,8 +733,8 @@ pow([1, 2, 3], 4) // returns [1, 16, 81] [float] === random( a, b ) -Generates a random number within the given range where the lower bound is inclusive -and the upper bound is exclusive. If no numbers are passed in, it will return a +Generates a random number within the given range where the lower bound is inclusive +and the upper bound is exclusive. If no numbers are passed in, it will return a number between 0 and 1. If only one number is passed in, it will return a number between 0 and the number passed in. @@ -751,11 +751,11 @@ between 0 and the number passed in. |(optional) must be greater than `a` |=== -*Returns*: `number`. A random number between 0 and 1 if no numbers are passed in. -Returns a random number between 0 and `a` if only one number is passed in. Returns +*Returns*: `number`. A random number between 0 and 1 if no numbers are passed in. +Returns a random number between 0 and `a` if only one number is passed in. Returns a random number between `a` and `b` if two numbers are passed in. -*Throws*: `'Min must be greater than max'` if `a` < 0 when only `a` is passed in +*Throws*: `'Min must be greater than max'` if `a` < 0 when only `a` is passed in or if `a` > `b` when both `a` and `b` are passed in *Example* @@ -769,8 +769,8 @@ random(-10,10) // returns a random number between -10 (inclusive) and 10 (exclus [float] === range( ...args ) -Finds the range of one of more numbers/arrays of numbers passed into the function. If at -least one array of numbers is passed into the function, the function will find +Finds the range of one of more numbers/arrays of numbers passed into the function. If at +least one array of numbers is passed into the function, the function will find the range by index. [cols="3*^<"] @@ -782,9 +782,9 @@ the range by index. |one or more numbers or arrays of numbers |=== -*Returns*: `number` | `Array.`. The range value of all numbers if `args` -contains only numbers. Returns an array with the range values at each index, -including all scalar numbers in `args` in the calculation at each index if `args` +*Returns*: `number` | `Array.`. The range value of all numbers if `args` +contains only numbers. Returns an array with the range values at each index, +including all scalar numbers in `args` in the calculation at each index if `args` contains at least one array. *Example* @@ -798,8 +798,8 @@ range([1, 9], 4, [3, 5]) // returns [range([1, 4, 3]), range([9, 4, 5])] = [3, 5 [float] === range( ...args ) -Finds the range of one of more numbers/arrays of numbers into the function. If at -least one array of numbers is passed into the function, the function will find +Finds the range of one of more numbers/arrays of numbers into the function. If at +least one array of numbers is passed into the function, the function will find the range by index. [cols="3*^<"] @@ -811,9 +811,9 @@ the range by index. |one or more numbers or arrays of numbers |=== -*Returns*: `number` | `Array.`. The range value of all numbers if `args` -contains only numbers. Returns an array with the the range values at each index, -including all scalar numbers in `args` in the calculation at each index if `args` +*Returns*: `number` | `Array.`. The range value of all numbers if `args` +contains only numbers. Returns an array with the the range values at each index, +including all scalar numbers in `args` in the calculation at each index if `args` contains at least one array. *Example* @@ -827,7 +827,7 @@ range([1, 9], 4, [3, 5]) // returns [range([1, 4, 3]), range([9, 4, 5])] = [3, 5 [float] === round( a, b ) -Rounds a number towards the nearest integer by default, or decimal place (if passed in as `b`). +Rounds a number towards the nearest integer by default, or decimal place (if passed in as `b`). For arrays, the function will be applied index-wise to each element. [cols="3*^<"] @@ -843,7 +843,7 @@ For arrays, the function will be applied index-wise to each element. |(optional) number of decimal places, default value: 0 |=== -*Returns*: `number` | `Array.`. The rounded value of `a`. Returns an +*Returns*: `number` | `Array.`. The rounded value of `a`. Returns an array with the the rounded values of each element if `a` is an array. *Example* @@ -885,7 +885,7 @@ size(100) // returns 1 [float] === sqrt( a ) -Calculates the square root of a number. For arrays, the function will be applied +Calculates the square root of a number. For arrays, the function will be applied index-wise to each element. [cols="3*^<"] @@ -897,7 +897,7 @@ index-wise to each element. |a number or an array of numbers |=== -*Returns*: `number` | `Array.`. The square root of `a`. Returns an array +*Returns*: `number` | `Array.`. The square root of `a`. Returns an array with the the square roots of each element if `a` is an array. *Throws*: `'Unable find the square root of a negative number'` if `a` < 0 @@ -913,7 +913,7 @@ sqrt([9, 16, 25]) // returns [3, 4, 5] [float] === square( a ) -Calculates the square of a number. For arrays, the function will be applied +Calculates the square of a number. For arrays, the function will be applied index-wise to each element. [cols="3*^<"] @@ -925,7 +925,7 @@ index-wise to each element. |a number or an array of numbers |=== -*Returns*: `number` | `Array.`. The square of `a`. Returns an array +*Returns*: `number` | `Array.`. The square of `a`. Returns an array with the the squares of each element if `a` is an array. *Example* @@ -938,7 +938,7 @@ square([3, 4, 5]) // returns [9, 16, 25] [float] === subtract( a, b ) -Subtracts two numbers. If at least one array of numbers is passed into the function, +Subtracts two numbers. If at least one array of numbers is passed into the function, the function will be applied index-wise to each element. [cols="3*^<"] @@ -954,7 +954,7 @@ the function will be applied index-wise to each element. |a number or an array of numbers |=== -*Returns*: `number` | `Array.`. The difference of `a` and `b` if both are +*Returns*: `number` | `Array.`. The difference of `a` and `b` if both are numbers, or an array of differences applied index-wise to each element. *Throws*: `'Array length mismatch'` if `a` and `b` are arrays with different lengths @@ -971,11 +971,11 @@ subtract([14, 42, 65, 108], [2, 7, 5, 12]) // returns [12, 35, 52, 96] [float] === sum( ...args ) -Calculates the sum of one or more numbers/arrays passed into the function. If at -least one array is passed, the function will sum up one or more numbers/arrays of +Calculates the sum of one or more numbers/arrays passed into the function. If at +least one array is passed, the function will sum up one or more numbers/arrays of numbers and distinct values of an array. Sum accepts arrays of different lengths. -*Returns*: `number`. The sum of one or more numbers/arrays of numbers including +*Returns*: `number`. The sum of one or more numbers/arrays of numbers including distinct values in arrays *Example* @@ -992,7 +992,7 @@ sum([10, 20, 30, 40], 10, [1, 2, 3], 22) // returns sum(10, 20, 30, 40, 10, 1, 2 Counts the number of unique values in an array. -*Returns*: `number`. The number of unique values in the array. Returns 1 if `a` +*Returns*: `number`. The number of unique values in the array. Returns 1 if `a` is not an array. *Example* @@ -1003,4 +1003,3 @@ unique([]) // returns 0 unique([1, 2, 3, 4]) // returns 4 unique([1, 2, 3, 4, 2, 2, 2, 3, 4, 2, 4, 5, 2, 1, 4, 2]) // returns 5 ------------ - diff --git a/docs/dev-tools/searchprofiler/more-complicated.asciidoc b/docs/dev-tools/searchprofiler/more-complicated.asciidoc index a0771f4a0f240d..338341d65924dd 100644 --- a/docs/dev-tools/searchprofiler/more-complicated.asciidoc +++ b/docs/dev-tools/searchprofiler/more-complicated.asciidoc @@ -25,11 +25,11 @@ POST test/_bulk // CONSOLE -- -. From the {searchprofiler}, enter "test" in the *Index* field to restrict profiled +. From the {searchprofiler}, enter "test" in the *Index* field to restrict profiled queries to the `test` index. . Replace the default `match_all` query in the query editor with a query that has two sub-query -components and includes a simple aggregation, like the example below. +components and includes a simple aggregation: + -- [source,js] diff --git a/docs/developer/core/development-functional-tests.asciidoc b/docs/developer/core/development-functional-tests.asciidoc index 77a2bfe77b4ab5..dcb3d65b8b83fc 100644 --- a/docs/developer/core/development-functional-tests.asciidoc +++ b/docs/developer/core/development-functional-tests.asciidoc @@ -69,7 +69,7 @@ node scripts/functional_tests_server.js node ../scripts/functional_test_runner.js ---------- -** Selenium tests are run in headless mode on CI. Locally the same tests will be executed in a real browser. You can activate headless mode by setting the environment variable below: +** Selenium tests are run in headless mode on CI. Locally the same tests will be executed in a real browser. You can activate headless mode by setting the environment variable: + ["source", "shell"] ---------- @@ -181,7 +181,7 @@ node scripts/functional_test_runner --config test/functional/config.firefox.js [float] ===== Anatomy of a test file -The annotated example file below shows the basic structure every test suite uses. It starts by importing https://github.com/elastic/kibana/tree/master/packages/kbn-expect[`@kbn/expect`] and defining its default export: an anonymous Test Provider. The test provider then destructures the Provider API for the `getService()` and `getPageObjects()` functions. It uses these functions to collect the dependencies of this suite. The rest of the test file will look pretty normal to mocha.js users. `describe()`, `it()`, `before()` and the lot are used to define suites that happen to automate a browser via services and objects of type `PageObject`. +This annotated example file shows the basic structure every test suite uses. It starts by importing https://github.com/elastic/kibana/tree/master/packages/kbn-expect[`@kbn/expect`] and defining its default export: an anonymous Test Provider. The test provider then destructures the Provider API for the `getService()` and `getPageObjects()` functions. It uses these functions to collect the dependencies of this suite. The rest of the test file will look pretty normal to mocha.js users. `describe()`, `it()`, `before()` and the lot are used to define suites that happen to automate a browser via services and objects of type `PageObject`. ["source","js"] ---- diff --git a/docs/developer/plugin/development-plugin-feature-registration.asciidoc b/docs/developer/plugin/development-plugin-feature-registration.asciidoc index 2c686964d369aa..ca61e5309ce85c 100644 --- a/docs/developer/plugin/development-plugin-feature-registration.asciidoc +++ b/docs/developer/plugin/development-plugin-feature-registration.asciidoc @@ -46,7 +46,7 @@ Registering a feature consists of the following fields. For more information, co |`privileges` (required) |{repo}blob/{branch}/x-pack/plugins/features/server/feature.ts[`FeatureWithAllOrReadPrivileges`]. -|see examples below +|See <> and <> |The set of privileges this feature requires to function. |`icon` @@ -80,6 +80,7 @@ if (canUserSave) { } ----------- +[[example-1-canvas]] ==== Example 1: Canvas Application ["source","javascript"] ----------- @@ -134,6 +135,7 @@ if (canUserSave) { Because the `read` privilege does not define the `save` capability, users with read-only access will have their `uiCapabilities.canvas.save` flag set to `false`. +[[example-2-dev-tools]] ==== Example 2: Dev Tools ["source","javascript"] diff --git a/docs/developer/plugin/development-plugin-localization.asciidoc b/docs/developer/plugin/development-plugin-localization.asciidoc index 78ee933f681f48..1fb8b6aa0cbde7 100644 --- a/docs/developer/plugin/development-plugin-localization.asciidoc +++ b/docs/developer/plugin/development-plugin-localization.asciidoc @@ -161,7 +161,7 @@ Full details are {repo}tree/master/packages/kbn-i18n#angularjs[here]. To learn more about i18n tooling, see {blob}src/dev/i18n/README.md[i18n dev tooling]. -To learn more about implementing i18n in the UI, follow the links below: +To learn more about implementing i18n in the UI, use the following links: * {blob}packages/kbn-i18n/README.md[i18n plugin] * {blob}packages/kbn-i18n/GUIDELINE.md[i18n guidelines] diff --git a/docs/development/core/public/kibana-plugin-core-public.icontextprovider.md b/docs/development/core/public/kibana-plugin-core-public.icontextprovider.md index 4778415ab2391c..97f7bad8e99115 100644 --- a/docs/development/core/public/kibana-plugin-core-public.icontextprovider.md +++ b/docs/development/core/public/kibana-plugin-core-public.icontextprovider.md @@ -9,7 +9,7 @@ A function that returns a context value for a specific key of given context type Signature: ```typescript -export declare type IContextProvider, TContextName extends keyof HandlerContextType> = (context: Partial>, ...rest: HandlerParameters) => Promise[TContextName]> | HandlerContextType[TContextName]; +export declare type IContextProvider, TContextName extends keyof HandlerContextType> = (context: PartialExceptFor, 'core'>, ...rest: HandlerParameters) => Promise[TContextName]> | HandlerContextType[TContextName]; ``` ## Remarks diff --git a/docs/development/core/public/kibana-plugin-core-public.iuisettingsclient.getall.md b/docs/development/core/public/kibana-plugin-core-public.iuisettingsclient.getall.md index 805ac57b2fb9ab..004979977376e6 100644 --- a/docs/development/core/public/kibana-plugin-core-public.iuisettingsclient.getall.md +++ b/docs/development/core/public/kibana-plugin-core-public.iuisettingsclient.getall.md @@ -9,5 +9,5 @@ Gets the metadata about all uiSettings, including the type, default value, and u Signature: ```typescript -getAll: () => Readonly>; +getAll: () => Readonly>; ``` diff --git a/docs/development/core/public/kibana-plugin-core-public.iuisettingsclient.md b/docs/development/core/public/kibana-plugin-core-public.iuisettingsclient.md index da566ed25cff51..87ef5784a6c6d6 100644 --- a/docs/development/core/public/kibana-plugin-core-public.iuisettingsclient.md +++ b/docs/development/core/public/kibana-plugin-core-public.iuisettingsclient.md @@ -18,7 +18,7 @@ export interface IUiSettingsClient | --- | --- | --- | | [get](./kibana-plugin-core-public.iuisettingsclient.get.md) | <T = any>(key: string, defaultOverride?: T) => T | Gets the value for a specific uiSetting. If this setting has no user-defined value then the defaultOverride parameter is returned (and parsed if setting is of type "json" or "number). If the parameter is not defined and the key is not registered by any plugin then an error is thrown, otherwise reads the default value defined by a plugin. | | [get$](./kibana-plugin-core-public.iuisettingsclient.get_.md) | <T = any>(key: string, defaultOverride?: T) => Observable<T> | Gets an observable of the current value for a config key, and all updates to that config key in the future. Providing a defaultOverride argument behaves the same as it does in \#get() | -| [getAll](./kibana-plugin-core-public.iuisettingsclient.getall.md) | () => Readonly<Record<string, UiSettingsParams & UserProvidedValues>> | Gets the metadata about all uiSettings, including the type, default value, and user value for each key. | +| [getAll](./kibana-plugin-core-public.iuisettingsclient.getall.md) | () => Readonly<Record<string, PublicUiSettingsParams & UserProvidedValues>> | Gets the metadata about all uiSettings, including the type, default value, and user value for each key. | | [getSaved$](./kibana-plugin-core-public.iuisettingsclient.getsaved_.md) | <T = any>() => Observable<{
key: string;
newValue: T;
oldValue: T;
}> | Returns an Observable that notifies subscribers of each update to the uiSettings, including the key, newValue, and oldValue of the setting that changed. | | [getUpdate$](./kibana-plugin-core-public.iuisettingsclient.getupdate_.md) | <T = any>() => Observable<{
key: string;
newValue: T;
oldValue: T;
}> | Returns an Observable that notifies subscribers of each update to the uiSettings, including the key, newValue, and oldValue of the setting that changed. | | [getUpdateErrors$](./kibana-plugin-core-public.iuisettingsclient.getupdateerrors_.md) | () => Observable<Error> | Returns an Observable that notifies subscribers of each error while trying to update the settings, containing the actual Error class. | diff --git a/docs/development/core/public/kibana-plugin-core-public.md b/docs/development/core/public/kibana-plugin-core-public.md index bafc2eb3a4bc93..a9fbaa25ea150a 100644 --- a/docs/development/core/public/kibana-plugin-core-public.md +++ b/docs/development/core/public/kibana-plugin-core-public.md @@ -147,6 +147,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | [MountPoint](./kibana-plugin-core-public.mountpoint.md) | A function that should mount DOM content inside the provided container element and return a handler to unmount it. | | [PluginInitializer](./kibana-plugin-core-public.plugininitializer.md) | The plugin export at the root of a plugin's public directory should conform to this interface. | | [PluginOpaqueId](./kibana-plugin-core-public.pluginopaqueid.md) | | +| [PublicUiSettingsParams](./kibana-plugin-core-public.publicuisettingsparams.md) | A sub-set of [UiSettingsParams](./kibana-plugin-core-public.uisettingsparams.md) exposed to the client-side. | | [RecursiveReadonly](./kibana-plugin-core-public.recursivereadonly.md) | | | [SavedObjectAttribute](./kibana-plugin-core-public.savedobjectattribute.md) | Type definition for a Saved Object attribute value | | [SavedObjectAttributeSingle](./kibana-plugin-core-public.savedobjectattributesingle.md) | Don't use this type, it's simply a helper type for [SavedObjectAttribute](./kibana-plugin-core-public.savedobjectattribute.md) | diff --git a/docs/development/core/public/kibana-plugin-core-public.publicuisettingsparams.md b/docs/development/core/public/kibana-plugin-core-public.publicuisettingsparams.md new file mode 100644 index 00000000000000..678a69289ff235 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-core-public.publicuisettingsparams.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [PublicUiSettingsParams](./kibana-plugin-core-public.publicuisettingsparams.md) + +## PublicUiSettingsParams type + +A sub-set of [UiSettingsParams](./kibana-plugin-core-public.uisettingsparams.md) exposed to the client-side. + +Signature: + +```typescript +export declare type PublicUiSettingsParams = Omit; +``` diff --git a/docs/development/core/public/kibana-plugin-core-public.savedobject.md b/docs/development/core/public/kibana-plugin-core-public.savedobject.md index 9ced619ad4bfe2..c6bc13b98bc066 100644 --- a/docs/development/core/public/kibana-plugin-core-public.savedobject.md +++ b/docs/development/core/public/kibana-plugin-core-public.savedobject.md @@ -4,7 +4,6 @@ ## SavedObject interface - Signature: ```typescript diff --git a/docs/development/core/public/kibana-plugin-core-public.uisettingsparams.md b/docs/development/core/public/kibana-plugin-core-public.uisettingsparams.md index 00f1c0f0deca56..e7facb4a109cd8 100644 --- a/docs/development/core/public/kibana-plugin-core-public.uisettingsparams.md +++ b/docs/development/core/public/kibana-plugin-core-public.uisettingsparams.md @@ -9,7 +9,7 @@ UiSettings parameters defined by the plugins. Signature: ```typescript -export interface UiSettingsParams +export interface UiSettingsParams ``` ## Properties @@ -24,7 +24,8 @@ export interface UiSettingsParams | [options](./kibana-plugin-core-public.uisettingsparams.options.md) | string[] | array of permitted values for this setting | | [readonly](./kibana-plugin-core-public.uisettingsparams.readonly.md) | boolean | a flag indicating that value cannot be changed | | [requiresPageReload](./kibana-plugin-core-public.uisettingsparams.requirespagereload.md) | boolean | a flag indicating whether new value applying requires page reloading | +| [schema](./kibana-plugin-core-public.uisettingsparams.schema.md) | Type<T> | | | [type](./kibana-plugin-core-public.uisettingsparams.type.md) | UiSettingsType | defines a type of UI element [UiSettingsType](./kibana-plugin-core-public.uisettingstype.md) | | [validation](./kibana-plugin-core-public.uisettingsparams.validation.md) | ImageValidation | StringValidation | | -| [value](./kibana-plugin-core-public.uisettingsparams.value.md) | SavedObjectAttribute | default value to fall back to if a user doesn't provide any | +| [value](./kibana-plugin-core-public.uisettingsparams.value.md) | T | default value to fall back to if a user doesn't provide any | diff --git a/docs/development/core/public/kibana-plugin-core-public.uisettingsparams.schema.md b/docs/development/core/public/kibana-plugin-core-public.uisettingsparams.schema.md new file mode 100644 index 00000000000000..f90d5161f96a92 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-core-public.uisettingsparams.schema.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [UiSettingsParams](./kibana-plugin-core-public.uisettingsparams.md) > [schema](./kibana-plugin-core-public.uisettingsparams.schema.md) + +## UiSettingsParams.schema property + +Signature: + +```typescript +schema: Type; +``` diff --git a/docs/development/core/public/kibana-plugin-core-public.uisettingsparams.value.md b/docs/development/core/public/kibana-plugin-core-public.uisettingsparams.value.md index 8775588290d708..2740f169eeecb3 100644 --- a/docs/development/core/public/kibana-plugin-core-public.uisettingsparams.value.md +++ b/docs/development/core/public/kibana-plugin-core-public.uisettingsparams.value.md @@ -9,5 +9,5 @@ default value to fall back to if a user doesn't provide any Signature: ```typescript -value?: SavedObjectAttribute; +value?: T; ``` diff --git a/docs/development/core/server/kibana-plugin-core-server.corestart.elasticsearch.md b/docs/development/core/server/kibana-plugin-core-server.corestart.elasticsearch.md new file mode 100644 index 00000000000000..d8f518ceebd646 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.corestart.elasticsearch.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [CoreStart](./kibana-plugin-core-server.corestart.md) > [elasticsearch](./kibana-plugin-core-server.corestart.elasticsearch.md) + +## CoreStart.elasticsearch property + +[ElasticsearchServiceStart](./kibana-plugin-core-server.elasticsearchservicestart.md) + +Signature: + +```typescript +elasticsearch: ElasticsearchServiceStart; +``` diff --git a/docs/development/core/server/kibana-plugin-core-server.corestart.md b/docs/development/core/server/kibana-plugin-core-server.corestart.md index 24a5c8f213d9fc..c50e8924c9dd40 100644 --- a/docs/development/core/server/kibana-plugin-core-server.corestart.md +++ b/docs/development/core/server/kibana-plugin-core-server.corestart.md @@ -17,6 +17,7 @@ export interface CoreStart | Property | Type | Description | | --- | --- | --- | | [capabilities](./kibana-plugin-core-server.corestart.capabilities.md) | CapabilitiesStart | [CapabilitiesStart](./kibana-plugin-core-server.capabilitiesstart.md) | +| [elasticsearch](./kibana-plugin-core-server.corestart.elasticsearch.md) | ElasticsearchServiceStart | [ElasticsearchServiceStart](./kibana-plugin-core-server.elasticsearchservicestart.md) | | [savedObjects](./kibana-plugin-core-server.corestart.savedobjects.md) | SavedObjectsServiceStart | [SavedObjectsServiceStart](./kibana-plugin-core-server.savedobjectsservicestart.md) | | [uiSettings](./kibana-plugin-core-server.corestart.uisettings.md) | UiSettingsServiceStart | [UiSettingsServiceStart](./kibana-plugin-core-server.uisettingsservicestart.md) | diff --git a/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.adminclient.md b/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.adminclient.md index 24bd42e83186fd..3fcb855586129a 100644 --- a/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.adminclient.md +++ b/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.adminclient.md @@ -4,7 +4,12 @@ ## ElasticsearchServiceSetup.adminClient property -A client for the `admin` cluster. All Elasticsearch config value changes are processed under the hood. See [IClusterClient](./kibana-plugin-core-server.iclusterclient.md). +> Warning: This API is now obsolete. +> +> Use [ElasticsearchServiceStart.legacy.client](./kibana-plugin-core-server.elasticsearchservicestart.legacy.md) instead. +> +> A client for the `admin` cluster. All Elasticsearch config value changes are processed under the hood. See [IClusterClient](./kibana-plugin-core-server.iclusterclient.md). +> Signature: diff --git a/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.createclient.md b/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.createclient.md index b739578bbdd80d..75bf6c6aa461b1 100644 --- a/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.createclient.md +++ b/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.createclient.md @@ -4,7 +4,12 @@ ## ElasticsearchServiceSetup.createClient property -Create application specific Elasticsearch cluster API client with customized config. See [IClusterClient](./kibana-plugin-core-server.iclusterclient.md). +> Warning: This API is now obsolete. +> +> Use [ElasticsearchServiceStart.legacy.createClient](./kibana-plugin-core-server.elasticsearchservicestart.legacy.md) instead. +> +> Create application specific Elasticsearch cluster API client with customized config. See [IClusterClient](./kibana-plugin-core-server.iclusterclient.md). +> Signature: diff --git a/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.dataclient.md b/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.dataclient.md index fae5cee79d6e6b..867cafa957f42b 100644 --- a/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.dataclient.md +++ b/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.dataclient.md @@ -4,7 +4,12 @@ ## ElasticsearchServiceSetup.dataClient property -A client for the `data` cluster. All Elasticsearch config value changes are processed under the hood. See [IClusterClient](./kibana-plugin-core-server.iclusterclient.md). +> Warning: This API is now obsolete. +> +> Use [ElasticsearchServiceStart.legacy.client](./kibana-plugin-core-server.elasticsearchservicestart.legacy.md) instead. +> +> A client for the `data` cluster. All Elasticsearch config value changes are processed under the hood. See [IClusterClient](./kibana-plugin-core-server.iclusterclient.md). +> Signature: diff --git a/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.md b/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.md index 4e4e8b837d909c..ee56f8b4a62847 100644 --- a/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.md +++ b/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicesetup.md @@ -15,7 +15,7 @@ export interface ElasticsearchServiceSetup | Property | Type | Description | | --- | --- | --- | -| [adminClient](./kibana-plugin-core-server.elasticsearchservicesetup.adminclient.md) | IClusterClient | A client for the admin cluster. All Elasticsearch config value changes are processed under the hood. See [IClusterClient](./kibana-plugin-core-server.iclusterclient.md). | -| [createClient](./kibana-plugin-core-server.elasticsearchservicesetup.createclient.md) | (type: string, clientConfig?: Partial<ElasticsearchClientConfig>) => ICustomClusterClient | Create application specific Elasticsearch cluster API client with customized config. See [IClusterClient](./kibana-plugin-core-server.iclusterclient.md). | -| [dataClient](./kibana-plugin-core-server.elasticsearchservicesetup.dataclient.md) | IClusterClient | A client for the data cluster. All Elasticsearch config value changes are processed under the hood. See [IClusterClient](./kibana-plugin-core-server.iclusterclient.md). | +| [adminClient](./kibana-plugin-core-server.elasticsearchservicesetup.adminclient.md) | IClusterClient | | +| [createClient](./kibana-plugin-core-server.elasticsearchservicesetup.createclient.md) | (type: string, clientConfig?: Partial<ElasticsearchClientConfig>) => ICustomClusterClient | | +| [dataClient](./kibana-plugin-core-server.elasticsearchservicesetup.dataclient.md) | IClusterClient | | diff --git a/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicestart.legacy.md b/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicestart.legacy.md new file mode 100644 index 00000000000000..08765aaf93d3d5 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicestart.legacy.md @@ -0,0 +1,14 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ElasticsearchServiceStart](./kibana-plugin-core-server.elasticsearchservicestart.md) > [legacy](./kibana-plugin-core-server.elasticsearchservicestart.legacy.md) + +## ElasticsearchServiceStart.legacy property + +Signature: + +```typescript +legacy: { + readonly createClient: (type: string, clientConfig?: Partial) => ICustomClusterClient; + readonly client: IClusterClient; + }; +``` diff --git a/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicestart.md b/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicestart.md new file mode 100644 index 00000000000000..39c794af2c881f --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.elasticsearchservicestart.md @@ -0,0 +1,19 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [ElasticsearchServiceStart](./kibana-plugin-core-server.elasticsearchservicestart.md) + +## ElasticsearchServiceStart interface + + +Signature: + +```typescript +export interface ElasticsearchServiceStart +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [legacy](./kibana-plugin-core-server.elasticsearchservicestart.legacy.md) | {
readonly createClient: (type: string, clientConfig?: Partial<ElasticsearchClientConfig>) => ICustomClusterClient;
readonly client: IClusterClient;
} | | + diff --git a/docs/development/core/server/kibana-plugin-core-server.icontextprovider.md b/docs/development/core/server/kibana-plugin-core-server.icontextprovider.md index b2194c9ac0504d..7d124b266bcc1a 100644 --- a/docs/development/core/server/kibana-plugin-core-server.icontextprovider.md +++ b/docs/development/core/server/kibana-plugin-core-server.icontextprovider.md @@ -9,7 +9,7 @@ A function that returns a context value for a specific key of given context type Signature: ```typescript -export declare type IContextProvider, TContextName extends keyof HandlerContextType> = (context: Partial>, ...rest: HandlerParameters) => Promise[TContextName]> | HandlerContextType[TContextName]; +export declare type IContextProvider, TContextName extends keyof HandlerContextType> = (context: PartialExceptFor, 'core'>, ...rest: HandlerParameters) => Promise[TContextName]> | HandlerContextType[TContextName]; ``` ## Remarks diff --git a/docs/development/core/server/kibana-plugin-core-server.iuisettingsclient.getregistered.md b/docs/development/core/server/kibana-plugin-core-server.iuisettingsclient.getregistered.md index 2ca6b4cbe15896..71a2bbf88472e1 100644 --- a/docs/development/core/server/kibana-plugin-core-server.iuisettingsclient.getregistered.md +++ b/docs/development/core/server/kibana-plugin-core-server.iuisettingsclient.getregistered.md @@ -9,5 +9,5 @@ Returns registered uiSettings values [UiSettingsParams](./kibana-plugin-core-ser Signature: ```typescript -getRegistered: () => Readonly>; +getRegistered: () => Readonly>; ``` diff --git a/docs/development/core/server/kibana-plugin-core-server.iuisettingsclient.md b/docs/development/core/server/kibana-plugin-core-server.iuisettingsclient.md index 42fcc81419cbed..af99b5e5bb215e 100644 --- a/docs/development/core/server/kibana-plugin-core-server.iuisettingsclient.md +++ b/docs/development/core/server/kibana-plugin-core-server.iuisettingsclient.md @@ -18,7 +18,7 @@ export interface IUiSettingsClient | --- | --- | --- | | [get](./kibana-plugin-core-server.iuisettingsclient.get.md) | <T = any>(key: string) => Promise<T> | Retrieves uiSettings values set by the user with fallbacks to default values if not specified. | | [getAll](./kibana-plugin-core-server.iuisettingsclient.getall.md) | <T = any>() => Promise<Record<string, T>> | Retrieves a set of all uiSettings values set by the user with fallbacks to default values if not specified. | -| [getRegistered](./kibana-plugin-core-server.iuisettingsclient.getregistered.md) | () => Readonly<Record<string, UiSettingsParams>> | Returns registered uiSettings values [UiSettingsParams](./kibana-plugin-core-server.uisettingsparams.md) | +| [getRegistered](./kibana-plugin-core-server.iuisettingsclient.getregistered.md) | () => Readonly<Record<string, PublicUiSettingsParams>> | Returns registered uiSettings values [UiSettingsParams](./kibana-plugin-core-server.uisettingsparams.md) | | [getUserProvided](./kibana-plugin-core-server.iuisettingsclient.getuserprovided.md) | <T = any>() => Promise<Record<string, UserProvidedValues<T>>> | Retrieves a set of all uiSettings values set by the user. | | [isOverridden](./kibana-plugin-core-server.iuisettingsclient.isoverridden.md) | (key: string) => boolean | Shows whether the uiSettings value set by the user. | | [remove](./kibana-plugin-core-server.iuisettingsclient.remove.md) | (key: string) => Promise<void> | Removes uiSettings value by key. | diff --git a/docs/development/core/server/kibana-plugin-core-server.md b/docs/development/core/server/kibana-plugin-core-server.md index ec64851e39f784..54cf496b2d6af4 100644 --- a/docs/development/core/server/kibana-plugin-core-server.md +++ b/docs/development/core/server/kibana-plugin-core-server.md @@ -74,6 +74,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | [DiscoveredPlugin](./kibana-plugin-core-server.discoveredplugin.md) | Small container object used to expose information about discovered plugins that may or may not have been started. | | [ElasticsearchError](./kibana-plugin-core-server.elasticsearcherror.md) | | | [ElasticsearchServiceSetup](./kibana-plugin-core-server.elasticsearchservicesetup.md) | | +| [ElasticsearchServiceStart](./kibana-plugin-core-server.elasticsearchservicestart.md) | | | [EnvironmentMode](./kibana-plugin-core-server.environmentmode.md) | | | [ErrorHttpResponseOptions](./kibana-plugin-core-server.errorhttpresponseoptions.md) | HTTP response parameters | | [FakeRequest](./kibana-plugin-core-server.fakerequest.md) | Fake request object created manually by Kibana plugins. | @@ -231,6 +232,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | [PluginInitializer](./kibana-plugin-core-server.plugininitializer.md) | The plugin export at the root of a plugin's server directory should conform to this interface. | | [PluginName](./kibana-plugin-core-server.pluginname.md) | Dedicated type for plugin name/id that is supposed to make Map/Set/Arrays that use it as a key or value more obvious. | | [PluginOpaqueId](./kibana-plugin-core-server.pluginopaqueid.md) | | +| [PublicUiSettingsParams](./kibana-plugin-core-server.publicuisettingsparams.md) | A sub-set of [UiSettingsParams](./kibana-plugin-core-server.uisettingsparams.md) exposed to the client-side. | | [RecursiveReadonly](./kibana-plugin-core-server.recursivereadonly.md) | | | [RedirectResponseOptions](./kibana-plugin-core-server.redirectresponseoptions.md) | HTTP response parameters for redirection response | | [RequestHandler](./kibana-plugin-core-server.requesthandler.md) | A function executed when route path matched requested resource path. Request handler is expected to return a result of one of [KibanaResponseFactory](./kibana-plugin-core-server.kibanaresponsefactory.md) functions. | diff --git a/docs/development/core/server/kibana-plugin-core-server.publicuisettingsparams.md b/docs/development/core/server/kibana-plugin-core-server.publicuisettingsparams.md new file mode 100644 index 00000000000000..4ccc91fbe1f742 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.publicuisettingsparams.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [PublicUiSettingsParams](./kibana-plugin-core-server.publicuisettingsparams.md) + +## PublicUiSettingsParams type + +A sub-set of [UiSettingsParams](./kibana-plugin-core-server.uisettingsparams.md) exposed to the client-side. + +Signature: + +```typescript +export declare type PublicUiSettingsParams = Omit; +``` diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobject.md b/docs/development/core/server/kibana-plugin-core-server.savedobject.md index ebb105c846aff8..0df97b0d4221a2 100644 --- a/docs/development/core/server/kibana-plugin-core-server.savedobject.md +++ b/docs/development/core/server/kibana-plugin-core-server.savedobject.md @@ -4,7 +4,6 @@ ## SavedObject interface - Signature: ```typescript diff --git a/docs/development/core/server/kibana-plugin-core-server.uisettingsparams.md b/docs/development/core/server/kibana-plugin-core-server.uisettingsparams.md index fe6e5d956f3e27..f134decb5102bd 100644 --- a/docs/development/core/server/kibana-plugin-core-server.uisettingsparams.md +++ b/docs/development/core/server/kibana-plugin-core-server.uisettingsparams.md @@ -9,7 +9,7 @@ UiSettings parameters defined by the plugins. Signature: ```typescript -export interface UiSettingsParams +export interface UiSettingsParams ``` ## Properties @@ -24,7 +24,8 @@ export interface UiSettingsParams | [options](./kibana-plugin-core-server.uisettingsparams.options.md) | string[] | array of permitted values for this setting | | [readonly](./kibana-plugin-core-server.uisettingsparams.readonly.md) | boolean | a flag indicating that value cannot be changed | | [requiresPageReload](./kibana-plugin-core-server.uisettingsparams.requirespagereload.md) | boolean | a flag indicating whether new value applying requires page reloading | +| [schema](./kibana-plugin-core-server.uisettingsparams.schema.md) | Type<T> | | | [type](./kibana-plugin-core-server.uisettingsparams.type.md) | UiSettingsType | defines a type of UI element [UiSettingsType](./kibana-plugin-core-server.uisettingstype.md) | | [validation](./kibana-plugin-core-server.uisettingsparams.validation.md) | ImageValidation | StringValidation | | -| [value](./kibana-plugin-core-server.uisettingsparams.value.md) | SavedObjectAttribute | default value to fall back to if a user doesn't provide any | +| [value](./kibana-plugin-core-server.uisettingsparams.value.md) | T | default value to fall back to if a user doesn't provide any | diff --git a/docs/development/core/server/kibana-plugin-core-server.uisettingsparams.schema.md b/docs/development/core/server/kibana-plugin-core-server.uisettingsparams.schema.md new file mode 100644 index 00000000000000..f181fbd309b7fa --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.uisettingsparams.schema.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [UiSettingsParams](./kibana-plugin-core-server.uisettingsparams.md) > [schema](./kibana-plugin-core-server.uisettingsparams.schema.md) + +## UiSettingsParams.schema property + +Signature: + +```typescript +schema: Type; +``` diff --git a/docs/development/core/server/kibana-plugin-core-server.uisettingsparams.value.md b/docs/development/core/server/kibana-plugin-core-server.uisettingsparams.value.md index ca00cd0cd63962..78c8f0c8fcf8d5 100644 --- a/docs/development/core/server/kibana-plugin-core-server.uisettingsparams.value.md +++ b/docs/development/core/server/kibana-plugin-core-server.uisettingsparams.value.md @@ -9,5 +9,5 @@ default value to fall back to if a user doesn't provide any Signature: ```typescript -value?: SavedObjectAttribute; +value?: T; ``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.agggroupnames.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.agggroupnames.md new file mode 100644 index 00000000000000..b62578ef96323a --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.agggroupnames.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [AggGroupNames](./kibana-plugin-plugins-data-public.agggroupnames.md) + +## AggGroupNames variable + +Signature: + +```typescript +AggGroupNames: Readonly<{ + Buckets: "buckets"; + Metrics: "metrics"; + None: "none"; +}> +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparam.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparam.md new file mode 100644 index 00000000000000..aa9f64e4d566de --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparam.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [AggParam](./kibana-plugin-plugins-data-public.aggparam.md) + +## AggParam type + +Signature: + +```typescript +export declare type AggParam = BaseParamType; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparamoption.display.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparamoption.display.md new file mode 100644 index 00000000000000..9c6141a50c02fe --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparamoption.display.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [AggParamOption](./kibana-plugin-plugins-data-public.aggparamoption.md) > [display](./kibana-plugin-plugins-data-public.aggparamoption.display.md) + +## AggParamOption.display property + +Signature: + +```typescript +display: string; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparamoption.enabled.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparamoption.enabled.md new file mode 100644 index 00000000000000..5de2c2230d362f --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparamoption.enabled.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [AggParamOption](./kibana-plugin-plugins-data-public.aggparamoption.md) > [enabled](./kibana-plugin-plugins-data-public.aggparamoption.enabled.md) + +## AggParamOption.enabled() method + +Signature: + +```typescript +enabled?(agg: AggConfig): boolean; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| agg | AggConfig | | + +Returns: + +`boolean` + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparamoption.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparamoption.md new file mode 100644 index 00000000000000..7a38dbb0a44151 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparamoption.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [AggParamOption](./kibana-plugin-plugins-data-public.aggparamoption.md) + +## AggParamOption interface + +Signature: + +```typescript +export interface AggParamOption +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [display](./kibana-plugin-plugins-data-public.aggparamoption.display.md) | string | | +| [val](./kibana-plugin-plugins-data-public.aggparamoption.val.md) | string | | + +## Methods + +| Method | Description | +| --- | --- | +| [enabled(agg)](./kibana-plugin-plugins-data-public.aggparamoption.enabled.md) | | + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparamoption.val.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparamoption.val.md new file mode 100644 index 00000000000000..8cdf71c767211e --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparamoption.val.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [AggParamOption](./kibana-plugin-plugins-data-public.aggparamoption.md) > [val](./kibana-plugin-plugins-data-public.aggparamoption.val.md) + +## AggParamOption.val property + +Signature: + +```typescript +val: string; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparamtype._constructor_.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparamtype._constructor_.md new file mode 100644 index 00000000000000..5fdcd53d57c654 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparamtype._constructor_.md @@ -0,0 +1,20 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [AggParamType](./kibana-plugin-plugins-data-public.aggparamtype.md) > [(constructor)](./kibana-plugin-plugins-data-public.aggparamtype._constructor_.md) + +## AggParamType.(constructor) + +Constructs a new instance of the `AggParamType` class + +Signature: + +```typescript +constructor(config: Record); +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| config | Record<string, any> | | + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparamtype.allowedaggs.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparamtype.allowedaggs.md new file mode 100644 index 00000000000000..9dc0b788f29a67 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparamtype.allowedaggs.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [AggParamType](./kibana-plugin-plugins-data-public.aggparamtype.md) > [allowedAggs](./kibana-plugin-plugins-data-public.aggparamtype.allowedaggs.md) + +## AggParamType.allowedAggs property + +Signature: + +```typescript +allowedAggs: string[]; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparamtype.makeagg.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparamtype.makeagg.md new file mode 100644 index 00000000000000..43f30d73ca6df3 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparamtype.makeagg.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [AggParamType](./kibana-plugin-plugins-data-public.aggparamtype.md) > [makeAgg](./kibana-plugin-plugins-data-public.aggparamtype.makeagg.md) + +## AggParamType.makeAgg property + +Signature: + +```typescript +makeAgg: (agg: TAggConfig, state?: any) => TAggConfig; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparamtype.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparamtype.md new file mode 100644 index 00000000000000..b75065da91abda --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggparamtype.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [AggParamType](./kibana-plugin-plugins-data-public.aggparamtype.md) + +## AggParamType class + +Signature: + +```typescript +export declare class AggParamType extends BaseParamType +``` + +## Constructors + +| Constructor | Modifiers | Description | +| --- | --- | --- | +| [(constructor)(config)](./kibana-plugin-plugins-data-public.aggparamtype._constructor_.md) | | Constructs a new instance of the AggParamType class | + +## Properties + +| Property | Modifiers | Type | Description | +| --- | --- | --- | --- | +| [allowedAggs](./kibana-plugin-plugins-data-public.aggparamtype.allowedaggs.md) | | string[] | | +| [makeAgg](./kibana-plugin-plugins-data-public.aggparamtype.makeagg.md) | | (agg: TAggConfig, state?: any) => TAggConfig | | + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggtypefieldfilters.addfilter.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggtypefieldfilters.addfilter.md new file mode 100644 index 00000000000000..c9d6772a13b8d5 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggtypefieldfilters.addfilter.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [AggTypeFieldFilters](./kibana-plugin-plugins-data-public.aggtypefieldfilters.md) > [addFilter](./kibana-plugin-plugins-data-public.aggtypefieldfilters.addfilter.md) + +## AggTypeFieldFilters.addFilter() method + +Register a new with this registry. This will be used by the . + +Signature: + +```typescript +addFilter(filter: AggTypeFieldFilter): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| filter | AggTypeFieldFilter | | + +Returns: + +`void` + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggtypefieldfilters.filter.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggtypefieldfilters.filter.md new file mode 100644 index 00000000000000..038c339bf67745 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggtypefieldfilters.filter.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [AggTypeFieldFilters](./kibana-plugin-plugins-data-public.aggtypefieldfilters.md) > [filter](./kibana-plugin-plugins-data-public.aggtypefieldfilters.filter.md) + +## AggTypeFieldFilters.filter() method + +Returns the filtered by all registered filters. + +Signature: + +```typescript +filter(fields: IndexPatternField[], aggConfig: IAggConfig): IndexPatternField[]; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| fields | IndexPatternField[] | | +| aggConfig | IAggConfig | | + +Returns: + +`IndexPatternField[]` + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggtypefieldfilters.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggtypefieldfilters.md new file mode 100644 index 00000000000000..c0b386efbf9c71 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggtypefieldfilters.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [AggTypeFieldFilters](./kibana-plugin-plugins-data-public.aggtypefieldfilters.md) + +## AggTypeFieldFilters class + +A registry to store which are used to filter down available fields for a specific visualization and . + +Signature: + +```typescript +declare class AggTypeFieldFilters +``` + +## Methods + +| Method | Modifiers | Description | +| --- | --- | --- | +| [addFilter(filter)](./kibana-plugin-plugins-data-public.aggtypefieldfilters.addfilter.md) | | Register a new with this registry. This will be used by the . | +| [filter(fields, aggConfig)](./kibana-plugin-plugins-data-public.aggtypefieldfilters.filter.md) | | Returns the filtered by all registered filters. | + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggtypefilters.addfilter.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggtypefilters.addfilter.md new file mode 100644 index 00000000000000..9df003377c4a10 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggtypefilters.addfilter.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [AggTypeFilters](./kibana-plugin-plugins-data-public.aggtypefilters.md) > [addFilter](./kibana-plugin-plugins-data-public.aggtypefilters.addfilter.md) + +## AggTypeFilters.addFilter() method + +Register a new with this registry. + +Signature: + +```typescript +addFilter(filter: AggTypeFilter): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| filter | AggTypeFilter | | + +Returns: + +`void` + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggtypefilters.filter.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggtypefilters.filter.md new file mode 100644 index 00000000000000..81e6e9b95d6559 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggtypefilters.filter.md @@ -0,0 +1,27 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [AggTypeFilters](./kibana-plugin-plugins-data-public.aggtypefilters.md) > [filter](./kibana-plugin-plugins-data-public.aggtypefilters.filter.md) + +## AggTypeFilters.filter() method + +Returns the filtered by all registered filters. + +Signature: + +```typescript +filter(aggTypes: IAggType[], indexPattern: IndexPattern, aggConfig: IAggConfig, aggFilter: string[]): IAggType[]; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| aggTypes | IAggType[] | | +| indexPattern | IndexPattern | | +| aggConfig | IAggConfig | | +| aggFilter | string[] | | + +Returns: + +`IAggType[]` + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggtypefilters.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggtypefilters.md new file mode 100644 index 00000000000000..c5e24bc0a78a06 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.aggtypefilters.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [AggTypeFilters](./kibana-plugin-plugins-data-public.aggtypefilters.md) + +## AggTypeFilters class + +A registry to store which are used to filter down available aggregations for a specific visualization and . + +Signature: + +```typescript +declare class AggTypeFilters +``` + +## Methods + +| Method | Modifiers | Description | +| --- | --- | --- | +| [addFilter(filter)](./kibana-plugin-plugins-data-public.aggtypefilters.addfilter.md) | | Register a new with this registry. | +| [filter(aggTypes, indexPattern, aggConfig, aggFilter)](./kibana-plugin-plugins-data-public.aggtypefilters.filter.md) | | Returns the filtered by all registered filters. | + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.bucket_types.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.bucket_types.md new file mode 100644 index 00000000000000..4bd6070bf21255 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.bucket_types.md @@ -0,0 +1,28 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [BUCKET\_TYPES](./kibana-plugin-plugins-data-public.bucket_types.md) + +## BUCKET\_TYPES enum + +Signature: + +```typescript +export declare enum BUCKET_TYPES +``` + +## Enumeration Members + +| Member | Value | Description | +| --- | --- | --- | +| DATE\_HISTOGRAM | "date_histogram" | | +| DATE\_RANGE | "date_range" | | +| FILTER | "filter" | | +| FILTERS | "filters" | | +| GEOHASH\_GRID | "geohash_grid" | | +| GEOTILE\_GRID | "geotile_grid" | | +| HISTOGRAM | "histogram" | | +| IP\_RANGE | "ip_range" | | +| RANGE | "range" | | +| SIGNIFICANT\_TERMS | "significant_terms" | | +| TERMS | "terms" | | + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md new file mode 100644 index 00000000000000..3e966caa307995 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [DataPublicPluginStart](./kibana-plugin-plugins-data-public.datapublicpluginstart.md) > [actions](./kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md) + +## DataPublicPluginStart.actions property + +Signature: + +```typescript +actions: { + createFiltersFromEvent: typeof createFiltersFromEvent; + }; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md index defc633b5d1ce0..a623e91388fd68 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.datapublicpluginstart.md @@ -14,6 +14,7 @@ export interface DataPublicPluginStart | Property | Type | Description | | --- | --- | --- | +| [actions](./kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md) | {
createFiltersFromEvent: typeof createFiltersFromEvent;
} | | | [autocomplete](./kibana-plugin-plugins-data-public.datapublicpluginstart.autocomplete.md) | AutocompleteStart | | | [fieldFormats](./kibana-plugin-plugins-data-public.datapublicpluginstart.fieldformats.md) | FieldFormatsStart | | | [indexPatterns](./kibana-plugin-plugins-data-public.datapublicpluginstart.indexpatterns.md) | IndexPatternsContract | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.daterangekey.from.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.daterangekey.from.md new file mode 100644 index 00000000000000..245269af366bc0 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.daterangekey.from.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [DateRangeKey](./kibana-plugin-plugins-data-public.daterangekey.md) > [from](./kibana-plugin-plugins-data-public.daterangekey.from.md) + +## DateRangeKey.from property + +Signature: + +```typescript +from: number; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.daterangekey.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.daterangekey.md new file mode 100644 index 00000000000000..540d429dced48e --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.daterangekey.md @@ -0,0 +1,19 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [DateRangeKey](./kibana-plugin-plugins-data-public.daterangekey.md) + +## DateRangeKey interface + +Signature: + +```typescript +export interface DateRangeKey +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [from](./kibana-plugin-plugins-data-public.daterangekey.from.md) | number | | +| [to](./kibana-plugin-plugins-data-public.daterangekey.to.md) | number | | + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.daterangekey.to.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.daterangekey.to.md new file mode 100644 index 00000000000000..024a6c2105427d --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.daterangekey.to.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [DateRangeKey](./kibana-plugin-plugins-data-public.daterangekey.md) > [to](./kibana-plugin-plugins-data-public.daterangekey.to.md) + +## DateRangeKey.to property + +Signature: + +```typescript +to: number; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformats.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformats.md index 7fd4d03e1b0741..244633c3c4c9ef 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformats.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformats.md @@ -10,7 +10,7 @@ fieldFormats: { FieldFormat: typeof FieldFormat; FieldFormatsRegistry: typeof FieldFormatsRegistry; - serialize: (agg: import("../../../legacy/core_plugins/data/public/search").AggConfig) => import("../../expressions/common").SerializedFieldFormat; + serialize: (agg: import("./search").AggConfig) => import("../../expressions/common").SerializedFieldFormat; DEFAULT_CONVERTER_COLOR: { range: string; regex: string; diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iaggconfig.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iaggconfig.md new file mode 100644 index 00000000000000..9d07f610ba32ab --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iaggconfig.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IAggConfig](./kibana-plugin-plugins-data-public.iaggconfig.md) + +## IAggConfig type + + AggConfig + + This class represents an aggregation, which is displayed in the left-hand nav of the Visualize app. + +Signature: + +```typescript +export declare type IAggConfig = AggConfig; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iagggroupnames.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iagggroupnames.md new file mode 100644 index 00000000000000..07310a4219359a --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iagggroupnames.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IAggGroupNames](./kibana-plugin-plugins-data-public.iagggroupnames.md) + +## IAggGroupNames type + +Signature: + +```typescript +export declare type IAggGroupNames = $Values; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iaggtype.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iaggtype.md new file mode 100644 index 00000000000000..15505fed16bd46 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iaggtype.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IAggType](./kibana-plugin-plugins-data-public.iaggtype.md) + +## IAggType type + +Signature: + +```typescript +export declare type IAggType = AggType; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ifieldparamtype.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ifieldparamtype.md new file mode 100644 index 00000000000000..1226106895bdb7 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ifieldparamtype.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IFieldParamType](./kibana-plugin-plugins-data-public.ifieldparamtype.md) + +## IFieldParamType type + +Signature: + +```typescript +export declare type IFieldParamType = FieldParamType; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.imetricaggtype.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.imetricaggtype.md new file mode 100644 index 00000000000000..4f36d3ef7a16e3 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.imetricaggtype.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IMetricAggType](./kibana-plugin-plugins-data-public.imetricaggtype.md) + +## IMetricAggType type + +Signature: + +```typescript +export declare type IMetricAggType = MetricAggType; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iprangekey.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iprangekey.md new file mode 100644 index 00000000000000..96903a5df98441 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iprangekey.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IpRangeKey](./kibana-plugin-plugins-data-public.iprangekey.md) + +## IpRangeKey type + +Signature: + +```typescript +export declare type IpRangeKey = { + type: 'mask'; + mask: string; +} | { + type: 'range'; + from: string; + to: string; +}; +``` 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 ce1375d277b75f..f8516ec476e883 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 @@ -8,11 +8,15 @@ | Class | Description | | --- | --- | +| [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 . | | [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) | | | [Plugin](./kibana-plugin-plugins-data-public.plugin.md) | | | [SearchError](./kibana-plugin-plugins-data-public.searcherror.md) | | | [SearchSource](./kibana-plugin-plugins-data-public.searchsource.md) | | @@ -22,8 +26,10 @@ | Enumeration | Description | | --- | --- | +| [BUCKET\_TYPES](./kibana-plugin-plugins-data-public.bucket_types.md) | | | [ES\_FIELD\_TYPES](./kibana-plugin-plugins-data-public.es_field_types.md) | \* | | [KBN\_FIELD\_TYPES](./kibana-plugin-plugins-data-public.kbn_field_types.md) | \* | +| [METRIC\_TYPES](./kibana-plugin-plugins-data-public.metric_types.md) | | | [QuerySuggestionTypes](./kibana-plugin-plugins-data-public.querysuggestiontypes.md) | | | [SortDirection](./kibana-plugin-plugins-data-public.sortdirection.md) | | @@ -36,15 +42,16 @@ | [getQueryLog(uiSettings, storage, appName, language)](./kibana-plugin-plugins-data-public.getquerylog.md) | | | [getSearchErrorType({ message })](./kibana-plugin-plugins-data-public.getsearcherrortype.md) | | | [getTime(indexPattern, timeRange, forceNow)](./kibana-plugin-plugins-data-public.gettime.md) | | -| [parseInterval(interval)](./kibana-plugin-plugins-data-public.parseinterval.md) | | | [plugin(initializerContext)](./kibana-plugin-plugins-data-public.plugin.md) | | ## Interfaces | Interface | Description | | --- | --- | +| [AggParamOption](./kibana-plugin-plugins-data-public.aggparamoption.md) | | | [DataPublicPluginSetup](./kibana-plugin-plugins-data-public.datapublicpluginsetup.md) | | | [DataPublicPluginStart](./kibana-plugin-plugins-data-public.datapublicpluginstart.md) | | +| [DateRangeKey](./kibana-plugin-plugins-data-public.daterangekey.md) | | | [EsQueryConfig](./kibana-plugin-plugins-data-public.esqueryconfig.md) | | | [FetchOptions](./kibana-plugin-plugins-data-public.fetchoptions.md) | | | [FieldFormatConfig](./kibana-plugin-plugins-data-public.fieldformatconfig.md) | | @@ -66,6 +73,8 @@ | [ISearchStrategy](./kibana-plugin-plugins-data-public.isearchstrategy.md) | Search strategy interface contains a search method that takes in a request and returns a promise that resolves to a response. | | [ISyncSearchRequest](./kibana-plugin-plugins-data-public.isyncsearchrequest.md) | | | [KueryNode](./kibana-plugin-plugins-data-public.kuerynode.md) | | +| [OptionedParamEditorProps](./kibana-plugin-plugins-data-public.optionedparameditorprops.md) | | +| [OptionedValueProp](./kibana-plugin-plugins-data-public.optionedvalueprop.md) | | | [Query](./kibana-plugin-plugins-data-public.query.md) | | | [QueryState](./kibana-plugin-plugins-data-public.querystate.md) | All query state service state | | [QuerySuggestionBasic](./kibana-plugin-plugins-data-public.querysuggestionbasic.md) | \* | @@ -77,12 +86,15 @@ | [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) | | ## Variables | Variable | Description | | --- | --- | +| [AggGroupNames](./kibana-plugin-plugins-data-public.agggroupnames.md) | | | [baseFormattersPublic](./kibana-plugin-plugins-data-public.baseformatterspublic.md) | | | [castEsToKbnFieldTypeName](./kibana-plugin-plugins-data-public.castestokbnfieldtypename.md) | Get the KbnFieldType name for an esType string | | [connectToQueryState](./kibana-plugin-plugins-data-public.connecttoquerystate.md) | Helper to setup two-way syncing of global data and a state container | @@ -96,6 +108,7 @@ | [getKbnTypeNames](./kibana-plugin-plugins-data-public.getkbntypenames.md) | Get the esTypes known by all kbnFieldTypes {Array} | | [indexPatterns](./kibana-plugin-plugins-data-public.indexpatterns.md) | | | [QueryStringInput](./kibana-plugin-plugins-data-public.querystringinput.md) | | +| [search](./kibana-plugin-plugins-data-public.search.md) | | | [SearchBar](./kibana-plugin-plugins-data-public.searchbar.md) | | | [SYNC\_SEARCH\_STRATEGY](./kibana-plugin-plugins-data-public.sync_search_strategy.md) | | | [syncQueryStateWithUrl](./kibana-plugin-plugins-data-public.syncquerystatewithurl.md) | Helper to setup syncing of global data with the URL | @@ -104,21 +117,29 @@ | Type Alias | Description | | --- | --- | +| [AggParam](./kibana-plugin-plugins-data-public.aggparam.md) | | | [CustomFilter](./kibana-plugin-plugins-data-public.customfilter.md) | | | [EsQuerySortValue](./kibana-plugin-plugins-data-public.esquerysortvalue.md) | | | [ExistsFilter](./kibana-plugin-plugins-data-public.existsfilter.md) | | | [FieldFormatId](./kibana-plugin-plugins-data-public.fieldformatid.md) | id type is needed for creating custom converters. | | [FieldFormatsContentType](./kibana-plugin-plugins-data-public.fieldformatscontenttype.md) | \* | | [FieldFormatsGetConfigFn](./kibana-plugin-plugins-data-public.fieldformatsgetconfigfn.md) | | +| [IAggConfig](./kibana-plugin-plugins-data-public.iaggconfig.md) | AggConfig This class represents an aggregation, which is displayed in the left-hand nav of the Visualize app. | +| [IAggGroupNames](./kibana-plugin-plugins-data-public.iagggroupnames.md) | | +| [IAggType](./kibana-plugin-plugins-data-public.iaggtype.md) | | | [IFieldFormat](./kibana-plugin-plugins-data-public.ifieldformat.md) | | | [IFieldFormatsRegistry](./kibana-plugin-plugins-data-public.ifieldformatsregistry.md) | | +| [IFieldParamType](./kibana-plugin-plugins-data-public.ifieldparamtype.md) | | +| [IMetricAggType](./kibana-plugin-plugins-data-public.imetricaggtype.md) | | | [IndexPatternAggRestrictions](./kibana-plugin-plugins-data-public.indexpatternaggrestrictions.md) | | | [IndexPatternsContract](./kibana-plugin-plugins-data-public.indexpatternscontract.md) | | | [InputTimeRange](./kibana-plugin-plugins-data-public.inputtimerange.md) | | +| [IpRangeKey](./kibana-plugin-plugins-data-public.iprangekey.md) | | | [ISearch](./kibana-plugin-plugins-data-public.isearch.md) | | | [ISearchGeneric](./kibana-plugin-plugins-data-public.isearchgeneric.md) | | | [ISearchSource](./kibana-plugin-plugins-data-public.isearchsource.md) | | | [MatchAllFilter](./kibana-plugin-plugins-data-public.matchallfilter.md) | | +| [ParsedInterval](./kibana-plugin-plugins-data-public.parsedinterval.md) | | | [PhraseFilter](./kibana-plugin-plugins-data-public.phrasefilter.md) | | | [PhrasesFilter](./kibana-plugin-plugins-data-public.phrasesfilter.md) | | | [QuerySuggestion](./kibana-plugin-plugins-data-public.querysuggestion.md) | \* | @@ -130,6 +151,7 @@ | [SearchRequest](./kibana-plugin-plugins-data-public.searchrequest.md) | | | [SearchResponse](./kibana-plugin-plugins-data-public.searchresponse.md) | | | [StatefulSearchBarProps](./kibana-plugin-plugins-data-public.statefulsearchbarprops.md) | | +| [TabbedAggRow](./kibana-plugin-plugins-data-public.tabbedaggrow.md) | \* | | [TimefilterContract](./kibana-plugin-plugins-data-public.timefiltercontract.md) | | | [TimeHistoryContract](./kibana-plugin-plugins-data-public.timehistorycontract.md) | | | [TSearchStrategyProvider](./kibana-plugin-plugins-data-public.tsearchstrategyprovider.md) | 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. | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.metric_types.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.metric_types.md new file mode 100644 index 00000000000000..637717692a38c1 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.metric_types.md @@ -0,0 +1,38 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [METRIC\_TYPES](./kibana-plugin-plugins-data-public.metric_types.md) + +## METRIC\_TYPES enum + +Signature: + +```typescript +export declare enum METRIC_TYPES +``` + +## Enumeration Members + +| Member | Value | Description | +| --- | --- | --- | +| AVG | "avg" | | +| AVG\_BUCKET | "avg_bucket" | | +| CARDINALITY | "cardinality" | | +| COUNT | "count" | | +| CUMULATIVE\_SUM | "cumulative_sum" | | +| DERIVATIVE | "derivative" | | +| GEO\_BOUNDS | "geo_bounds" | | +| GEO\_CENTROID | "geo_centroid" | | +| MAX | "max" | | +| MAX\_BUCKET | "max_bucket" | | +| MEDIAN | "median" | | +| MIN | "min" | | +| MIN\_BUCKET | "min_bucket" | | +| MOVING\_FN | "moving_avg" | | +| PERCENTILE\_RANKS | "percentile_ranks" | | +| PERCENTILES | "percentiles" | | +| SERIAL\_DIFF | "serial_diff" | | +| STD\_DEV | "std_dev" | | +| SUM | "sum" | | +| SUM\_BUCKET | "sum_bucket" | | +| TOP\_HITS | "top_hits" | | + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedparameditorprops.aggparam.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedparameditorprops.aggparam.md new file mode 100644 index 00000000000000..68e4371acc2f36 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedparameditorprops.aggparam.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [OptionedParamEditorProps](./kibana-plugin-plugins-data-public.optionedparameditorprops.md) > [aggParam](./kibana-plugin-plugins-data-public.optionedparameditorprops.aggparam.md) + +## OptionedParamEditorProps.aggParam property + +Signature: + +```typescript +aggParam: { + options: T[]; + }; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedparameditorprops.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedparameditorprops.md new file mode 100644 index 00000000000000..00a440a0a775a6 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedparameditorprops.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [OptionedParamEditorProps](./kibana-plugin-plugins-data-public.optionedparameditorprops.md) + +## OptionedParamEditorProps interface + +Signature: + +```typescript +export interface OptionedParamEditorProps +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [aggParam](./kibana-plugin-plugins-data-public.optionedparameditorprops.aggparam.md) | {
options: T[];
} | | + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedparamtype._constructor_.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedparamtype._constructor_.md new file mode 100644 index 00000000000000..47272c7683e658 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedparamtype._constructor_.md @@ -0,0 +1,20 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [OptionedParamType](./kibana-plugin-plugins-data-public.optionedparamtype.md) > [(constructor)](./kibana-plugin-plugins-data-public.optionedparamtype._constructor_.md) + +## OptionedParamType.(constructor) + +Constructs a new instance of the `OptionedParamType` class + +Signature: + +```typescript +constructor(config: Record); +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| config | Record<string, any> | | + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedparamtype.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedparamtype.md new file mode 100644 index 00000000000000..911f9bdd171137 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedparamtype.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [OptionedParamType](./kibana-plugin-plugins-data-public.optionedparamtype.md) + +## OptionedParamType class + +Signature: + +```typescript +export declare class OptionedParamType extends BaseParamType +``` + +## Constructors + +| Constructor | Modifiers | Description | +| --- | --- | --- | +| [(constructor)(config)](./kibana-plugin-plugins-data-public.optionedparamtype._constructor_.md) | | Constructs a new instance of the OptionedParamType class | + +## Properties + +| Property | Modifiers | Type | Description | +| --- | --- | --- | --- | +| [options](./kibana-plugin-plugins-data-public.optionedparamtype.options.md) | | OptionedValueProp[] | | + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedparamtype.options.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedparamtype.options.md new file mode 100644 index 00000000000000..3d99beaca47c46 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedparamtype.options.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [OptionedParamType](./kibana-plugin-plugins-data-public.optionedparamtype.md) > [options](./kibana-plugin-plugins-data-public.optionedparamtype.options.md) + +## OptionedParamType.options property + +Signature: + +```typescript +options: OptionedValueProp[]; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedvalueprop.disabled.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedvalueprop.disabled.md new file mode 100644 index 00000000000000..49516d7e426151 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedvalueprop.disabled.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [OptionedValueProp](./kibana-plugin-plugins-data-public.optionedvalueprop.md) > [disabled](./kibana-plugin-plugins-data-public.optionedvalueprop.disabled.md) + +## OptionedValueProp.disabled property + +Signature: + +```typescript +disabled?: boolean; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedvalueprop.iscompatible.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedvalueprop.iscompatible.md new file mode 100644 index 00000000000000..90fc6ac80b1fef --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedvalueprop.iscompatible.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [OptionedValueProp](./kibana-plugin-plugins-data-public.optionedvalueprop.md) > [isCompatible](./kibana-plugin-plugins-data-public.optionedvalueprop.iscompatible.md) + +## OptionedValueProp.isCompatible property + +Signature: + +```typescript +isCompatible: (agg: IAggConfig) => boolean; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedvalueprop.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedvalueprop.md new file mode 100644 index 00000000000000..11c907db5ead23 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedvalueprop.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [OptionedValueProp](./kibana-plugin-plugins-data-public.optionedvalueprop.md) + +## OptionedValueProp interface + +Signature: + +```typescript +export interface OptionedValueProp +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [disabled](./kibana-plugin-plugins-data-public.optionedvalueprop.disabled.md) | boolean | | +| [isCompatible](./kibana-plugin-plugins-data-public.optionedvalueprop.iscompatible.md) | (agg: IAggConfig) => boolean | | +| [text](./kibana-plugin-plugins-data-public.optionedvalueprop.text.md) | string | | +| [value](./kibana-plugin-plugins-data-public.optionedvalueprop.value.md) | string | | + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedvalueprop.text.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedvalueprop.text.md new file mode 100644 index 00000000000000..ce83780da63a93 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedvalueprop.text.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [OptionedValueProp](./kibana-plugin-plugins-data-public.optionedvalueprop.md) > [text](./kibana-plugin-plugins-data-public.optionedvalueprop.text.md) + +## OptionedValueProp.text property + +Signature: + +```typescript +text: string; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedvalueprop.value.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedvalueprop.value.md new file mode 100644 index 00000000000000..3403a080d75072 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.optionedvalueprop.value.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [OptionedValueProp](./kibana-plugin-plugins-data-public.optionedvalueprop.md) > [value](./kibana-plugin-plugins-data-public.optionedvalueprop.value.md) + +## OptionedValueProp.value property + +Signature: + +```typescript +value: string; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.parsedinterval.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.parsedinterval.md new file mode 100644 index 00000000000000..6a940fa9a78b78 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.parsedinterval.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [ParsedInterval](./kibana-plugin-plugins-data-public.parsedinterval.md) + +## ParsedInterval type + +Signature: + +```typescript +export declare type ParsedInterval = ReturnType; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.parseinterval.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.parseinterval.md deleted file mode 100644 index 1f5371fbf088a7..00000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.parseinterval.md +++ /dev/null @@ -1,22 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [parseInterval](./kibana-plugin-plugins-data-public.parseinterval.md) - -## parseInterval() function - -Signature: - -```typescript -export declare function parseInterval(interval: string): moment.Duration | null; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| interval | string | | - -Returns: - -`moment.Duration | null` - diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.plugin.setup.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.plugin.setup.md index 98a954456d482c..51bc46bbdccc83 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.plugin.setup.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.plugin.setup.md @@ -7,7 +7,7 @@ Signature: ```typescript -setup(core: CoreSetup, { uiActions }: DataSetupDependencies): DataPublicPluginSetup; +setup(core: CoreSetup, { expressions, uiActions }: DataSetupDependencies): DataPublicPluginSetup; ``` ## Parameters @@ -15,7 +15,7 @@ setup(core: CoreSetup, { uiActions }: DataSetupDependencies): DataPublicPluginSe | Parameter | Type | Description | | --- | --- | --- | | core | CoreSetup | | -| { uiActions } | DataSetupDependencies | | +| { expressions, uiActions } | DataSetupDependencies | | Returns: diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystringinput.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystringinput.md index d0d4cc491e1428..58690300b3bd62 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystringinput.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystringinput.md @@ -7,5 +7,5 @@ Signature: ```typescript -QueryStringInput: React.FC> +QueryStringInput: React.FC> ``` 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 new file mode 100644 index 00000000000000..7e65ef85c8becc --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.search.md @@ -0,0 +1,47 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [search](./kibana-plugin-plugins-data-public.search.md) + +## search variable + +Signature: + +```typescript +search: { + aggs: { + AggConfigs: typeof AggConfigs; + aggGroupNamesMap: () => Record<"buckets" | "metrics", string>; + aggTypeFilters: import("./search/aggs/filter/agg_type_filters").AggTypeFilters; + CidrMask: typeof CidrMask; + convertDateRangeToString: typeof convertDateRangeToString; + convertIPRangeToString: (range: import("./search").IpRangeKey, format: (val: any) => string) => string; + dateHistogramInterval: typeof dateHistogramInterval; + intervalOptions: ({ + display: string; + val: string; + enabled(agg: import("./search/aggs/buckets/_bucket_agg_type").IBucketAggConfig): boolean | "" | undefined; + } | { + display: string; + val: string; + })[]; + InvalidEsCalendarIntervalError: typeof InvalidEsCalendarIntervalError; + InvalidEsIntervalFormatError: typeof InvalidEsIntervalFormatError; + isDateHistogramBucketAggConfig: typeof isDateHistogramBucketAggConfig; + isStringType: (agg: import("./search").AggConfig) => boolean; + isType: (type: string) => (agg: import("./search").AggConfig) => boolean; + isValidEsInterval: typeof isValidEsInterval; + isValidInterval: typeof isValidInterval; + parentPipelineType: string; + parseEsInterval: typeof parseEsInterval; + parseInterval: typeof parseInterval; + propFilter: typeof propFilter; + siblingPipelineType: string; + termsAggFilter: string[]; + toAbsoluteDates: typeof toAbsoluteDates; + }; + getRequestInspectorStats: typeof getRequestInspectorStats; + getResponseInspectorStats: typeof getResponseInspectorStats; + tabifyAggResponse: typeof tabifyAggResponse; + tabifyGetColumns: typeof tabifyGetColumns; +} +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchbar.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchbar.md index 89c5ca800a4d4a..5cdf938a9e47f7 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchbar.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchbar.md @@ -7,7 +7,7 @@ Signature: ```typescript -SearchBar: React.ComponentClass, "query" | "isLoading" | "indexPatterns" | "filters" | "refreshInterval" | "screenTitle" | "dataTestSubj" | "customSubmitButton" | "showQueryBar" | "showQueryInput" | "showFilterBar" | "showDatePicker" | "showAutoRefreshOnly" | "isRefreshPaused" | "dateRangeFrom" | "dateRangeTo" | "showSaveQuery" | "savedQuery" | "onQueryChange" | "onQuerySubmit" | "onSaved" | "onSavedQueryUpdated" | "onClearSavedQuery" | "onRefresh" | "timeHistory" | "onFiltersUpdated" | "onRefreshChange">, any> & { - WrappedComponent: React.ComponentType & ReactIntl.InjectedIntlProps>; +SearchBar: React.ComponentClass, "query" | "isLoading" | "indexPatterns" | "filters" | "onQueryChange" | "customSubmitButton" | "screenTitle" | "dataTestSubj" | "showQueryBar" | "showQueryInput" | "showFilterBar" | "showDatePicker" | "showAutoRefreshOnly" | "isRefreshPaused" | "refreshInterval" | "dateRangeFrom" | "dateRangeTo" | "showSaveQuery" | "savedQuery" | "onQuerySubmit" | "onSaved" | "onSavedQueryUpdated" | "onClearSavedQuery" | "onRefresh" | "timeHistory" | "onFiltersUpdated" | "onRefreshChange">, any> & { + WrappedComponent: React.ComponentType & ReactIntl.InjectedIntlProps>; } ``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.getfields.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.getfields.md index 4f4e575241e103..dce03e7e1a95c6 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.getfields.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchsource.getfields.md @@ -11,7 +11,7 @@ getFields(): { type?: string | undefined; query?: import("../..").Query | undefined; filter?: Filter | Filter[] | (() => Filter | Filter[] | undefined) | undefined; - sort?: Record | Record[] | undefined; + sort?: Record | Record[] | undefined; highlight?: any; highlightAll?: boolean | undefined; aggs?: any; @@ -32,7 +32,7 @@ getFields(): { type?: string | undefined; query?: import("../..").Query | undefined; filter?: Filter | Filter[] | (() => Filter | Filter[] | undefined) | undefined; - sort?: Record | Record[] | undefined; + sort?: Record | Record[] | undefined; highlight?: any; highlightAll?: boolean | undefined; aggs?: any; diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.aggconfig.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.aggconfig.md new file mode 100644 index 00000000000000..b010667af79e46 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.aggconfig.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [TabbedAggColumn](./kibana-plugin-plugins-data-public.tabbedaggcolumn.md) > [aggConfig](./kibana-plugin-plugins-data-public.tabbedaggcolumn.aggconfig.md) + +## TabbedAggColumn.aggConfig property + +Signature: + +```typescript +aggConfig: IAggConfig; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.id.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.id.md new file mode 100644 index 00000000000000..86f8b01312047b --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.id.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [TabbedAggColumn](./kibana-plugin-plugins-data-public.tabbedaggcolumn.md) > [id](./kibana-plugin-plugins-data-public.tabbedaggcolumn.id.md) + +## TabbedAggColumn.id property + +Signature: + +```typescript +id: string; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.md new file mode 100644 index 00000000000000..578a2b159f9eb3 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [TabbedAggColumn](./kibana-plugin-plugins-data-public.tabbedaggcolumn.md) + +## TabbedAggColumn interface + +\* + +Signature: + +```typescript +export interface TabbedAggColumn +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [aggConfig](./kibana-plugin-plugins-data-public.tabbedaggcolumn.aggconfig.md) | IAggConfig | | +| [id](./kibana-plugin-plugins-data-public.tabbedaggcolumn.id.md) | string | | +| [name](./kibana-plugin-plugins-data-public.tabbedaggcolumn.name.md) | string | | + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.name.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.name.md new file mode 100644 index 00000000000000..ce20c1c50b9842 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggcolumn.name.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [TabbedAggColumn](./kibana-plugin-plugins-data-public.tabbedaggcolumn.md) > [name](./kibana-plugin-plugins-data-public.tabbedaggcolumn.name.md) + +## TabbedAggColumn.name property + +Signature: + +```typescript +name: string; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggrow.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggrow.md new file mode 100644 index 00000000000000..28519d95c43749 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedaggrow.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [TabbedAggRow](./kibana-plugin-plugins-data-public.tabbedaggrow.md) + +## TabbedAggRow type + +\* + +Signature: + +```typescript +export declare type TabbedAggRow = Record; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedtable.columns.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedtable.columns.md new file mode 100644 index 00000000000000..8256291d368c36 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedtable.columns.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [TabbedTable](./kibana-plugin-plugins-data-public.tabbedtable.md) > [columns](./kibana-plugin-plugins-data-public.tabbedtable.columns.md) + +## TabbedTable.columns property + +Signature: + +```typescript +columns: TabbedAggColumn[]; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedtable.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedtable.md new file mode 100644 index 00000000000000..51b1bfa9b4362b --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedtable.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [TabbedTable](./kibana-plugin-plugins-data-public.tabbedtable.md) + +## TabbedTable interface + +\* + +Signature: + +```typescript +export interface TabbedTable +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [columns](./kibana-plugin-plugins-data-public.tabbedtable.columns.md) | TabbedAggColumn[] | | +| [rows](./kibana-plugin-plugins-data-public.tabbedtable.rows.md) | TabbedAggRow[] | | + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedtable.rows.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedtable.rows.md new file mode 100644 index 00000000000000..19a973b18d75c2 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.tabbedtable.rows.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [TabbedTable](./kibana-plugin-plugins-data-public.tabbedtable.md) > [rows](./kibana-plugin-plugins-data-public.tabbedtable.rows.md) + +## TabbedTable.rows property + +Signature: + +```typescript +rows: TabbedAggRow[]; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.fieldformats.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.fieldformats.md index 1cc1d829d01cd6..2b986aee508e22 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.fieldformats.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.fieldformats.md @@ -10,7 +10,7 @@ fieldFormats: { FieldFormatsRegistry: typeof FieldFormatsRegistry; FieldFormat: typeof FieldFormat; - serializeFieldFormat: (agg: import("../../../legacy/core_plugins/data/public/search").AggConfig) => import("../../expressions/common").SerializedFieldFormat; + serializeFieldFormat: (agg: import("../public/search").AggConfig) => import("../../expressions/common").SerializedFieldFormat; BoolFormat: typeof BoolFormat; BytesFormat: typeof BytesFormat; ColorFormat: typeof ColorFormat; diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md index 507e60971526b7..12d53f1a35ea0f 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md @@ -60,6 +60,7 @@ | [esQuery](./kibana-plugin-plugins-data-server.esquery.md) | | | [fieldFormats](./kibana-plugin-plugins-data-server.fieldformats.md) | | | [indexPatterns](./kibana-plugin-plugins-data-server.indexpatterns.md) | | +| [search](./kibana-plugin-plugins-data-server.search.md) | | ## Type Aliases @@ -69,5 +70,6 @@ | [ICancel](./kibana-plugin-plugins-data-server.icancel.md) | | | [IFieldFormatsRegistry](./kibana-plugin-plugins-data-server.ifieldformatsregistry.md) | | | [ISearch](./kibana-plugin-plugins-data-server.isearch.md) | | +| [ParsedInterval](./kibana-plugin-plugins-data-server.parsedinterval.md) | | | [TSearchStrategyProvider](./kibana-plugin-plugins-data-server.tsearchstrategyprovider.md) | 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. | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.parsedinterval.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.parsedinterval.md new file mode 100644 index 00000000000000..c31a4ec13b8379 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.parsedinterval.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ParsedInterval](./kibana-plugin-plugins-data-server.parsedinterval.md) + +## ParsedInterval type + +Signature: + +```typescript +export declare type ParsedInterval = ReturnType; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.search.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.search.md new file mode 100644 index 00000000000000..6020498fdcb6d0 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.search.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [search](./kibana-plugin-plugins-data-server.search.md) + +## search variable + +Signature: + +```typescript +search: { + aggs: { + dateHistogramInterval: typeof dateHistogramInterval; + InvalidEsCalendarIntervalError: typeof InvalidEsCalendarIntervalError; + InvalidEsIntervalFormatError: typeof InvalidEsIntervalFormatError; + isValidEsInterval: typeof isValidEsInterval; + isValidInterval: typeof isValidInterval; + parseEsInterval: typeof parseEsInterval; + parseInterval: typeof parseInterval; + toAbsoluteDates: typeof toAbsoluteDates; + }; +} +``` diff --git a/docs/discover/kuery.asciidoc b/docs/discover/kuery.asciidoc index c835c15028074e..48a7c65bdbf153 100644 --- a/docs/discover/kuery.asciidoc +++ b/docs/discover/kuery.asciidoc @@ -2,13 +2,13 @@ === Kibana Query Language In Kibana 6.3, we introduced a number of exciting experimental query language enhancements. These -features are now available by default in 7.0. Out of the box, Kibana's query language now includes scripted field support and a -simplified, easier to use syntax. If you have a Basic license or above, autocomplete functionality will also be enabled. +features are now available by default in 7.0. Out of the box, Kibana's query language now includes scripted field support and a +simplified, easier to use syntax. If you have a Basic license or above, autocomplete functionality will also be enabled. ==== Language Syntax -If you're familiar with Kibana's old lucene query syntax, you should feel right at home with the new syntax. The basics -stay the same, we've simply refined things to make the query language easier to use. Read about the changes below. +If you're familiar with Kibana's old Lucene query syntax, you should feel right at home with the new syntax. The basics +stay the same, we've simply refined things to make the query language easier to use. `response:200` will match documents where the response field matches the value 200. @@ -19,8 +19,8 @@ they appear. This means documents with "quick brown fox" will match, but so will to search for a phrase. The query parser will no longer split on whitespace. Multiple search terms must be separated by explicit -boolean operators. Lucene will combine search terms with an `or` by default, so `response:200 extension:php` would -become `response:200 or extension:php` in KQL. This will match documents where response matches 200, extension matches php, or both. +boolean operators. Lucene will combine search terms with an `or` by default, so `response:200 extension:php` would +become `response:200 or extension:php` in KQL. This will match documents where response matches 200, extension matches php, or both. Note that boolean operators are not case sensitive. We can make terms required by using `and`. @@ -48,9 +48,9 @@ Entire groups can also be inverted. `response:200 and not (extension:php or extension:css)` -Ranges are similar to lucene with a small syntactical difference. +Ranges are similar to lucene with a small syntactical difference. -Instead of `bytes:>1000`, we omit the colon: `bytes > 1000`. +Instead of `bytes:>1000`, we omit the colon: `bytes > 1000`. `>, >=, <, <=` are all valid range operators. @@ -76,15 +76,15 @@ in the response field, but a query for just `200` will search for 200 across all KQL supports querying on {ref}/nested.html[nested fields] through a special syntax. You can query nested fields in subtly different ways, depending on the results you want, so crafting nested queries requires extra thought. - + One main consideration is how to match parts of the nested query to the individual nested documents. There are two main approaches to take: * *Parts of the query may only match a single nested document.* This is what most users want when querying on a nested field. -* *Parts of the query can match different nested documents.* This is how a regular object field works. +* *Parts of the query can match different nested documents.* This is how a regular object field works. Although generally less useful, there might be occasions where you want to query a nested field in this way. -Let's take a look at the first approach. In the following document, `items` is a nested field. Each document in the nested +Let's take a look at the first approach. In the following document, `items` is a nested field. Each document in the nested field contains a name, stock, and category. [source,json] @@ -122,7 +122,7 @@ To find stores that have more than 10 bananas in stock, you would write a query `items:{ name:banana and stock > 10 }` -`items` is the "nested path". Everything inside the curly braces (the "nested group") must match a single nested document. +`items` is the "nested path". Everything inside the curly braces (the "nested group") must match a single nested document. The following example returns no matches because no single nested document has bananas with a stock of 9. @@ -138,7 +138,7 @@ The subqueries in this example are in separate nested groups and can match diffe ==== Combine approaches -You can combine these two approaches to create complex queries. What if you wanted to find a store with more than 10 +You can combine these two approaches to create complex queries. What if you wanted to find a store with more than 10 bananas that *also* stocks vegetables? You could do this: `items:{ name:banana and stock > 10 } and items:{ category:vegetable }` diff --git a/docs/discover/search.asciidoc b/docs/discover/search.asciidoc index 9c4e406455c27b..21ae4560fba946 100644 --- a/docs/discover/search.asciidoc +++ b/docs/discover/search.asciidoc @@ -56,7 +56,7 @@ query language you can also submit queries using the {ref}/query-dsl.html[Elasti [[save-open-search]] === Saving searches -A saved search persists your current view of Discover for later retrieval and reuse. You can reload a saved search into Discover, add it to a dashboard, and use it as the basis for a <>. +A saved search persists your current view of Discover for later retrieval and reuse. You can reload a saved search into Discover, add it to a dashboard, and use it as the basis for a <>. A saved search includes the query text, filters, and optionally, the time filter. A saved search also includes the selected columns in the document table, the sort order, and the current index pattern. @@ -164,12 +164,9 @@ You can import, export, and delete saved queries from <>. +index pattern are searched. +To change the indices you are searching, click the index pattern and select a +different <>. [[autorefresh]] === Refresh the search results @@ -180,7 +177,7 @@ retrieve the latest results. . Click image:images/time-filter-calendar.png[]. -. In the *Refresh every* field, enter the refresh rate, then select the interval +. In the *Refresh every* field, enter the refresh rate, then select the interval from the dropdown. . Click *Start*. @@ -189,5 +186,5 @@ image::images/autorefresh-intervals.png[] To disable auto refresh, click *Stop*. -If auto refresh is not enabled, click *Refresh* to manually refresh the search +If auto refresh is not enabled, click *Refresh* to manually refresh the search results. diff --git a/docs/epm/index.asciidoc b/docs/epm/index.asciidoc new file mode 100644 index 00000000000000..d2ebe003afd6be --- /dev/null +++ b/docs/epm/index.asciidoc @@ -0,0 +1,144 @@ +[role="xpack"] +[[epm]] +== Elastic Package Manager + +These are the docs for the Elastic Package Manager (EPM). + + +=== Configuration + +The Elastic Package Manager by default access `epr.elastic.co` to retrieve the package. The url can be configured with: + +``` +xpack.epm.registryUrl: 'http://localhost:8080' +``` + +=== API + +The Package Manager offers an API. Here an example on how they can be used. + +List installed packages: + +``` +curl localhost:5601/api/ingest_manager/epm/packages +``` + +Install a package: + +``` +curl -X POST localhost:5601/api/ingest_manager/epm/packages/iptables-1.0.4 +``` + +Delete a package: + +``` +curl -X DELETE localhost:5601/api/ingest_manager/epm/packages/iptables-1.0.4 +``` + +=== Definitions + +This section is to define terms used across ingest management. + +==== Elastic Agent +A single, unified agent that users can deploy to hosts or containers. It controls which data is collected from the host or containers and where the data is sent. It will run Beats, Endpoint or other monitoring programs as needed. It can operate standalone or pull a configuration policy from Fleet. + +==== Namespace +A user-specified string that will be used to part of the index name in Elasticsearch. It helps users identify logs coming from a specific environment (like prod or test), an application, or other identifiers. + +==== Package + +A package contains all the assets for the Elastic Stack. A more detailed definition of a package can be found under https://github.com/elastic/package-registry. + + +== Indexing Strategy + +Ingest Management enforces an indexing strategy to allow the system to automatically detect indices and run queries on it. In short the indexing strategy looks as following: + +``` +{type}-{dataset}-{namespace} +``` + +The `{type}` can be `logs` or `metrics`. The `{namespace}` is the part where the user can use free form. The only two requirement are that it has only characters allowed in an Elasticsearch index name and does NOT contain a `-`. The `dataset` is defined by the data that is indexed. The same requirements as for the namespace apply. It is expected that the fields for type, namespace and dataset are part of each event and are constant keywords. + +Note: More `{type}`s might be added in the future like `apm` and `endpoint`. + +This indexing strategy has a few advantages: + +* Each index contains only the fields which are relevant for the dataset. This leads to more dense indices and better field completion. +* ILM policies can be applied per namespace per dataset. +* Rollups can be specified per namespace per dataset. +* Having the namespace user configurable makes setting security permissions possible. +* Having a global metrics and logs template, allows to create new indices on demand which still follow the convention. This is common in the case of k8s as an example. +* Constant keywords allow to narrow down the indices we need to access for querying very efficiently. This is especially relevant in environments which a large number of indices or with indices on slower nodes. + +=== Ingest Pipeline + +The ingest pipelines for a specific dataset will have the following naming scheme: + +``` +{type}-{dataset}-{package.version} +``` + +As an example, the ingest pipeline for the Nginx access logs is called `logs-nginx.access-3.4.1`. The same ingest pipeline is used for all namespaces. It is possible that a dataset has multiple ingest pipelines in which case a suffix is added to the name. + +The version is included in each pipeline to allow upgrades. The pipeline itself is listed in the index template and is automatically applied at ingest time. + +=== Templates & ILM Policies + +To make the above strategy possible, alias templates are required. For each type there is a basic alias template with a default ILM policy. These default templates apply to all indices which follow the indexing strategy and do not have a more specific dataset alias template. + +The `metrics` and `logs` alias template contain all the basic fields from ECS. + +Each type template contains an ILM policy. Modifying this default ILM policy will affect all data covered by the default templates. + +The templates for a dataset are called as following: + +``` +{type}-{dataset} +``` + +The pattern used inside the index template is `{type}-{dataset}-*` to match all namespaces. + +=== Defaults + +If the Elastic Agent is used to ingest data and only the type is specified, `default` for the namespace is used and `generic` for the dataset. + +=== Data filtering + +Filtering for data in queries for example in visualizations or dashboards should always be done on the constant keyword fields. Visualizations needing data for the nginx.access dataset should query on `type:logs AND dataset:nginx.access`. As these are constant keywords the prefiltering is very efficient. + +=== Security permissions + +Security permissions can be set on different levels. To set special permissions for the access on the prod namespace, use the following index pattern: + +``` +/(logs|metrics)-[^-]+-prod-$/ +``` + +To set specific permissions on the logs index, the following can be used: + +``` +/^(logs|metrics)-.*/ +``` + +Todo: The above queries need to be tested. + + + +== Package Manager + +=== Package Upgrades + +When upgrading a package between a bugfix or a minor version, no breaking changes should happen. Upgrading a package has the following effect: + +* Removal of existing dashboards +* Installation of new dashboards +* Write new ingest pipelines with the version +* Write new Elasticsearch alias templates +* Trigger a rollover for all the affected indices + +The new ingest pipeline is expected to still work with the data coming from older configurations. In most cases this means some of the fields can be missing. For this to work, each event must contain the version of config / package it is coming from to make such a decision. + +In case of a breaking change in the data structure, the new ingest pipeline is also expected to deal with this change. In case there are breaking changes which cannot be dealt with in an ingest pipeline, a new package has to be created. + +Each package lists its minimal required agent version. In case there are agents enrolled with an older version, the user is notified to upgrade these agents as otherwise the new configs cannot be rolled out. diff --git a/docs/management/numeral.asciidoc b/docs/management/numeral.asciidoc index 65dfdab3abd3c5..5d4d48ca785e1e 100644 --- a/docs/management/numeral.asciidoc +++ b/docs/management/numeral.asciidoc @@ -19,7 +19,7 @@ The numeral pattern syntax expresses: Number of decimal places:: The `.` character turns on the option to show decimal places using a locale-specific decimal separator, most often `.` or `,`. To add trailing zeroes such as `5.00`, use a pattern like `0.00`. -To have optional zeroes, use the `[]` characters. Examples below. +To have optional zeroes, use the `[]` characters. Thousands separator:: The thousands separator `,` turns on the option to group thousands using a locale-specific separator. The separator is most often `,` or `.`, and sometimes ` `. diff --git a/docs/management/rollups/create_and_manage_rollups.asciidoc b/docs/management/rollups/create_and_manage_rollups.asciidoc index 565c179b741f11..6a56970687fd65 100644 --- a/docs/management/rollups/create_and_manage_rollups.asciidoc +++ b/docs/management/rollups/create_and_manage_rollups.asciidoc @@ -70,11 +70,7 @@ This allows for more granular queries, such as 2h and 12h. [float] ==== Create the rollup job -As you walk through the *Create rollup job* UI, enter the data shown in -the table below. The terms, histogram, and metrics fields reflect -the key information to retain in the rolled up data: where visitors are from (geo.src), -what operating system they are using (machine.os.keyword), -and how much data is being sent (bytes). +As you walk through the *Create rollup job* UI, enter the data: |=== |*Field* |*Value* @@ -118,6 +114,10 @@ and how much data is being sent (bytes). |bytes (average) |=== +The terms, histogram, and metrics fields reflect +the key information to retain in the rolled up data: where visitors are from (geo.src), +what operating system they are using (machine.os.keyword), +and how much data is being sent (bytes). You can now use the rolled up data for analysis at a fraction of the storage cost of the original index. The original data can live side by side with the new diff --git a/docs/maps/geojson-upload.asciidoc b/docs/maps/geojson-upload.asciidoc index 8c3cb371b6addf..ad20264f56138b 100644 --- a/docs/maps/geojson-upload.asciidoc +++ b/docs/maps/geojson-upload.asciidoc @@ -14,7 +14,7 @@ GeoJSON is the most commonly used and flexible option. [float] === Upload a GeoJSON file -Follow the instructions below to upload a GeoJSON data file, or try the +Follow these instructions to upload a GeoJSON data file, or try the <>. . Open *Elastic Maps*, and then click *Add layer*. diff --git a/docs/maps/indexing-geojson-data-tutorial.asciidoc b/docs/maps/indexing-geojson-data-tutorial.asciidoc index 22b736032cb796..a94e5757d5dfad 100644 --- a/docs/maps/indexing-geojson-data-tutorial.asciidoc +++ b/docs/maps/indexing-geojson-data-tutorial.asciidoc @@ -46,7 +46,7 @@ image::maps/images/fu_gs_new_england_map.png[] === Upload and index GeoJSON files For each GeoJSON file you downloaded, complete the following steps: -. Below the map legend, click *Add layer*. +. Click *Add layer*. . From the list of layer types, click *Uploaded GeoJSON*. . Using the File Picker, upload the GeoJSON file. + @@ -86,7 +86,7 @@ hot spots are. An advantage of having indexed {ref}/geo-point.html[geo_point] data for the lightning strikes is that you can perform aggregations on the data. -. Below the map legend, click *Add layer*. +. Click *Add layer*. . From the list of layer types, click *Grid aggregation*. + Because you indexed `lightning_detected.geojson` using the index name and diff --git a/docs/maps/vector-style.asciidoc b/docs/maps/vector-style.asciidoc index 509b1fae4066ad..80e4c4ed5f844b 100644 --- a/docs/maps/vector-style.asciidoc +++ b/docs/maps/vector-style.asciidoc @@ -12,7 +12,7 @@ For each property, you can specify whether to use a constant or data driven valu Use static styling to specificy a constant value for a style property. -The image below shows an example of static styling using the <> data set. +This image shows an example of static styling using the <> data set. The *kibana_sample_data_logs* layer uses static styling for all properties. [role="screenshot"] @@ -26,7 +26,7 @@ image::maps/images/vector_style_static.png[] Use data driven styling to symbolize features by property values. To enable data driven styling for a style property, change the selected value from *Fixed* or *Solid* to *By value*. -The image below shows an example of data driven styling using the <> data set. +This image shows an example of data driven styling using the <> data set. The *kibana_sample_data_logs* layer uses data driven styling for fill color and symbol size style properties. * The `hour_of_day` property determines the fill color for each feature based on where the value fits on a linear scale. @@ -87,7 +87,7 @@ Qualitative data driven styling is available for the following styling propertie Qualitative data driven styling uses a {ref}/search-aggregations-bucket-terms-aggregation.html[terms aggregation] to retrieve the top nine categories for the property. Feature values within the top categories are assigned a unique color. Feature values outside of the top categories are grouped into the *Other* category. A feature is assigned the *Other* category when the property value is undefined. -The image below shows an example of quantitative data driven styling using the <> data set. +This image shows an example of quantitative data driven styling using the <> data set. The `machine.os.keyword` property determines the color of each symbol based on category. [role="screenshot"] @@ -101,7 +101,7 @@ image::maps/images/quantitative_data_driven_styling.png[] Class styling symbolizes features by class and requires multiple layers. Use <> to define the class for each layer, and <> to symbolize each class. -The image below shows an example of class styling using the <> data set. +This image shows an example of class styling using the <> data set. * The *Mac OS requests* layer applies the filter `machine.os : osx` so the layer only contains Mac OS requests. The fill color is a static value of green. diff --git a/docs/migration/migrate_8_0.asciidoc b/docs/migration/migrate_8_0.asciidoc index a34f956ace263d..ce4c97391f1b57 100644 --- a/docs/migration/migrate_8_0.asciidoc +++ b/docs/migration/migrate_8_0.asciidoc @@ -19,16 +19,16 @@ See also <> and <>. [float] [[breaking_80_index_pattern_changes]] -=== Index pattern changes +=== Index pattern changes [float] ==== Removed support for time-based internal index patterns -*Details:* Time-based interval index patterns were deprecated in 5.x. In 6.x, -you could no longer create time-based interval index patterns, but they continued +*Details:* Time-based interval index patterns were deprecated in 5.x. In 6.x, +you could no longer create time-based interval index patterns, but they continued to function as expected. Support for these index patterns has been removed in 8.0. -*Impact:* You must migrate your time_based index patterns to a wildcard pattern, -for example, `logstash-*`. +*Impact:* You must migrate your time_based index patterns to a wildcard pattern, +for example, `logstash-*`. [float] @@ -76,7 +76,7 @@ specified explicitly. [float] ==== `/api/security/v1/saml` endpoint is no longer supported -*Details:* The deprecated `/api/security/v1/saml` endpoint is no longer supported. +*Details:* The deprecated `/api/security/v1/saml` endpoint is no longer supported. *Impact:* Rely on `/api/security/saml/callback` endpoint when using SAML instead. This change should be reflected in Kibana `server.xsrf.whitelist` config as well as in Elasticsearch and Identity Provider SAML settings. @@ -108,7 +108,7 @@ access level. [float] ==== Legacy job parameters are no longer supported -*Details:* POST URL snippets that were copied in Kibana 6.2 or below are no longer supported. These logs have +*Details:* POST URL snippets that were copied in Kibana 6.2 or earlier are no longer supported. These logs have been deprecated with warnings that have been logged throughout 7.x. Please use Kibana UI to re-generate the POST URL snippets if you depend on these for automated PDF reports. diff --git a/docs/settings/apm-settings.asciidoc b/docs/settings/apm-settings.asciidoc index a6eeffec51cb02..91bbef5690fd5d 100644 --- a/docs/settings/apm-settings.asciidoc +++ b/docs/settings/apm-settings.asciidoc @@ -32,7 +32,7 @@ image::settings/images/apm-settings.png[APM app settings in Kibana] // tag::general-apm-settings[] If you'd like to change any of the default values, -copy and paste the relevant settings below into your `kibana.yml` configuration file. +copy and paste the relevant settings into your `kibana.yml` configuration file. xpack.apm.enabled:: Set to `false` to disabled the APM plugin {kib}. Defaults to `true`. diff --git a/docs/settings/ssl-settings.asciidoc b/docs/settings/ssl-settings.asciidoc index 5341d3543e7c6f..3a0a474d9d597b 100644 --- a/docs/settings/ssl-settings.asciidoc +++ b/docs/settings/ssl-settings.asciidoc @@ -44,7 +44,7 @@ Java Cryptography Architecture documentation]. Defaults to the value of The following settings are used to specify a private key, certificate, and the trusted certificates that should be used when communicating over an SSL/TLS connection. -If none of the settings below are specified, the default values are used. +If none of the settings are specified, the default values are used. See {ref}/security-settings.html[Default TLS/SSL settings]. ifdef::server[] @@ -54,8 +54,8 @@ ifndef::server[] A private key and certificate are optional and would be used if the server requires client authentication for PKI authentication. endif::server[] -If none of the settings below are specified, the defaults values are used. -See {ref}/security-settings.html[Default TLS/SSL settings]. +If none of the settings bare specified, the defaults values are used. +See {ref}/security-settings.html[Default TLS/SSL settings]. [float] ===== PEM encoded files diff --git a/docs/uptime-guide/install.asciidoc b/docs/uptime-guide/install.asciidoc index 5d32a26529f868..e7c50bb7604ce9 100644 --- a/docs/uptime-guide/install.asciidoc +++ b/docs/uptime-guide/install.asciidoc @@ -20,7 +20,7 @@ then jump straight to <>. === Install the stack yourself If you'd rather install the stack yourself, -first see the https://www.elastic.co/support/matrix[Elastic Support Matrix] for information about supported operating systems and product compatibility. Then, follow the steps below. +first see the https://www.elastic.co/support/matrix[Elastic Support Matrix] for information about supported operating systems and product compatibility. * <> * <> diff --git a/docs/uptime-guide/security.asciidoc b/docs/uptime-guide/security.asciidoc index 6651b33ea0e0e8..0c6fa4c6c4f56f 100644 --- a/docs/uptime-guide/security.asciidoc +++ b/docs/uptime-guide/security.asciidoc @@ -1,9 +1,8 @@ [[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. Below is an example of creating -a user and support role to implement those privileges. +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 diff --git a/docs/user/graph/getting-started.asciidoc b/docs/user/graph/getting-started.asciidoc index 7b3bd10147966a..1749678ace9e30 100644 --- a/docs/user/graph/getting-started.asciidoc +++ b/docs/user/graph/getting-started.asciidoc @@ -2,7 +2,7 @@ [[graph-getting-started]] == Using Graph -You must index data into {es} before you can create a graph. +You must index data into {es} before you can create a graph. <> or get started with a <>. [float] @@ -11,24 +11,24 @@ You must index data into {es} before you can create a graph. . From the side navigation, open *Graph*. + -If this is your first graph, follow the prompts to create it. +If this is your first graph, follow the prompts to create it. For subsequent graphs, click *New*. . Select a data source to explore. . Add one or more multi-value fields that contain the terms you want to -graph. +graph. + The vertices in the graph are selected from these terms. . Enter a search query to discover relationships between terms in the selected -fields. +fields. + -For example, if you are using the {kib} sample web logs data set, and you want +For example, if you are using the {kib} sample web logs data set, and you want to generate a graph of the successful requests to particular pages from different locations, you could search for the 200 response code. The weight of the connection between two vertices indicates how strongly they -are related. +are related. + [role="screenshot"] image::user/graph/images/graph-url-connections.png["URL connections"] @@ -45,11 +45,11 @@ additional connections: image:user/graph/images/graph-expand-button.png[Expand Selection]. * To display additional connections between the displayed vertices, click the link icon -image:user/graph/images/graph-link-button.png[Add links to existing terms]. +image:user/graph/images/graph-link-button.png[Add links to existing terms]. * To explore a particular area of the graph, select the vertices you are interested in, and then click expand or link. * To step back through your changes to the graph, click undo -image:user/graph/images/graph-undo-button.png[Undo] and redo +image:user/graph/images/graph-undo-button.png[Undo] and redo image:user/graph/images/graph-redo-button.png[Redo]. . To see more relationships in your data, submit additional queries. @@ -63,61 +63,61 @@ image::user/graph/images/graph-add-query.png["Adding networks"] [[style-vertex-properties]] === Style vertex properties -Each vertex has a color, icon, and label. To change -the color or icon of all vertices -of a certain field, click the field badge below the search bar, and then +Each vertex has a color, icon, and label. To change +the color or icon of all vertices +of a certain field, click it's badge, and then select *Edit settings*. -To change the color and label of selected vertices, +To change the color and label of selected vertices, click the style icon image:user/graph/images/graph-style-button.png[Style] -in the control bar on the right. +in the control bar on the right. [float] [[edit-graph-settings]] === Edit graph settings -By default, *Graph* is configured to tune out noise in your data. +By default, *Graph* is configured to tune out noise in your data. If this isn't a good fit for your data, use *Settings > Advanced settings* -to adjust the way *Graph* queries your data. You can tune the graph to show -only the results relevant to you and to improve performance. -For more information, see <>. +to adjust the way *Graph* queries your data. You can tune the graph to show +only the results relevant to you and to improve performance. +For more information, see <>. -You can configure the number of vertices that a search or +You can configure the number of vertices that a search or expand operation adds to the graph. -By default, only the five most relevant terms for any given field are added -at a time. This keeps the graph from overflowing. To increase this number, click -a field below the search bar, select *Edit Settings*, and change *Terms per hop*. +By default, only the five most relevant terms for any given field are added +at a time. This keeps the graph from overflowing. To increase this number, click +a field, select *Edit Settings*, and change *Terms per hop*. [float] [[graph-block-terms]] === Block terms from the graph -Documents that match a blocked term are not allowed in the graph. -To block a term, select its vertex and click +Documents that match a blocked term are not allowed in the graph. +To block a term, select its vertex and click the block icon image:user/graph/images/graph-block-button.png[Block selection] -in the control panel. +in the control panel. For a list of blocked terms, go to *Settings > Blocked terms*. [float] [[graph-drill-down]] === Drill down into raw documents -With drilldowns, you can display additional information about a -selected vertex in a new browser window. For example, you might -configure a drilldown URL to perform a web search for the selected vertex term. +With drilldowns, you can display additional information about a +selected vertex in a new browser window. For example, you might +configure a drilldown URL to perform a web search for the selected vertex term. -Use the drilldown icon image:user/graph/images/graph-info-icon.png[Drilldown selection] +Use the drilldown icon image:user/graph/images/graph-info-icon.png[Drilldown selection] in the control panel to show the drilldown buttons for the selected vertices. -To configure drilldowns, go to *Settings > Drilldowns*. See also +To configure drilldowns, go to *Settings > Drilldowns*. See also <>. [float] [[graph-run-layout]] === Run and pause layout -Graph uses a "force layout", where vertices behave like magnets, -pushing off of one another. By default, when you add a new vertex to -the graph, all vertices begin moving. In some cases, the movement might -go on for some time. To freeze the current vertex position, +Graph uses a "force layout", where vertices behave like magnets, +pushing off of one another. By default, when you add a new vertex to +the graph, all vertices begin moving. In some cases, the movement might +go on for some time. To freeze the current vertex position, click the pause icon image:user/graph/images/graph-pause-button.png[Block selection] -in the control panel. +in the control panel. diff --git a/docs/user/monitoring/beats-details.asciidoc b/docs/user/monitoring/beats-details.asciidoc index 672ed6226e4273..0b2be4dd9e3d9a 100644 --- a/docs/user/monitoring/beats-details.asciidoc +++ b/docs/user/monitoring/beats-details.asciidoc @@ -13,7 +13,7 @@ image::user/monitoring/images/monitoring-beats.jpg["Monitoring Beats",link="imag To view an overview of the Beats data in the cluster, click *Overview*. The overview page has a section for activity in the last day, which is a real-time -sample of data. Below that, a summary bar and charts follow the typical paradigm +sample of data. The summary bar and charts follow the typical paradigm of data in the Monitoring UI, which is bound to the span of the time filter in the top right corner of the page. This overview page can therefore show up-to-date or historical information. diff --git a/docs/user/security/rbac_tutorial.asciidoc b/docs/user/security/rbac_tutorial.asciidoc index e4dbdc2483f702..d45aae86a9ccb4 100644 --- a/docs/user/security/rbac_tutorial.asciidoc +++ b/docs/user/security/rbac_tutorial.asciidoc @@ -10,10 +10,10 @@ Kibana spaces. ==== Scenario Our user is a web developer working on a bank's -online mortgage service. The web developer has these +online mortgage service. The web developer has these three requirements: -* Have access to the data for that service +* Have access to the data for that service * Build visualizations and dashboards * Monitor the performance of the system @@ -24,28 +24,28 @@ You'll provide the web developer with the access and privileges to get the job d To complete this tutorial, you'll need the following: -* **Administrative privileges**: You must have a role that grants privileges to create a space, role, and user. This is any role which grants the `manage_security` cluster privilege. By default, the `superuser` role provides this access. See the {ref}/built-in-roles.html[built-in] roles. -* **A space**: In this tutorial, use `Dev Mortgage` as the space +* **Administrative privileges**: You must have a role that grants privileges to create a space, role, and user. This is any role which grants the `manage_security` cluster privilege. By default, the `superuser` role provides this access. See the {ref}/built-in-roles.html[built-in] roles. +* **A space**: In this tutorial, use `Dev Mortgage` as the space name. See <> for details on creating a space. -* **Data**: You can use <> or -live data. In the steps below, Filebeat and Metricbeat data are used. +* **Data**: You can use <> or +live data. In the following steps, Filebeat and Metricbeat data are used. [float] ==== Steps -With the requirements in mind, here are the steps that you will work +With the requirements in mind, here are the steps that you will work through in this tutorial: * Create a role named `mortgage-developer` * Give the role permission to access the data in the relevant indices -* Give the role permission to create visualizations and dashboards +* Give the role permission to create visualizations and dashboards * Create the web developer's user account with the proper roles [float] ==== Create a role -Go to **Management > Roles** +Go to **Management > Roles** for an overview of your roles. This view provides actions for you to create, edit, and delete roles. @@ -53,21 +53,21 @@ for you to create, edit, and delete roles. image::security/images/role-management.png["Role management"] -You can create as many roles as you like. Click *Create role* and -provide a name. Use `dev-mortgage` because this role is for a developer +You can create as many roles as you like. Click *Create role* and +provide a name. Use `dev-mortgage` because this role is for a developer working on the bank's mortgage application. [float] ==== Give the role permission to access the data -Access to data in indices is an index-level privilege, so in -*Index privileges*, add lines for the indices that contain the -data for this role. Two privileges are required: `read` and -`view_index_metadata`. All privileges are detailed in the +Access to data in indices is an index-level privilege, so in +*Index privileges*, add lines for the indices that contain the +data for this role. Two privileges are required: `read` and +`view_index_metadata`. All privileges are detailed in the https://www.elastic.co/guide/en/elasticsearch/reference/current/security-privileges.html[security privileges] documentation. -In the screenshots, Filebeat and Metricbeat data is used, but you +In the screenshots, Filebeat and Metricbeat data is used, but you should use the index patterns for your indices. [role="screenshot"] @@ -76,12 +76,12 @@ image::security/images/role-index-privilege.png["Index privilege"] [float] ==== Give the role permission to create visualizations and dashboards -By default, roles do not give Kibana privileges. Click **Add space +By default, roles do not give Kibana privileges. Click **Add space privilege** and associate this role with the `Dev Mortgage` space. -To enable users with the `dev-mortgage` role to create visualizations -and dashboards, click *All* for *Visualize* and *Dashboard*. Also -assign *All* for *Discover* because it is common for developers +To enable users with the `dev-mortgage` role to create visualizations +and dashboards, click *All* for *Visualize* and *Dashboard*. Also +assign *All* for *Discover* because it is common for developers to create saved searches while designing visualizations. [role="screenshot"] @@ -90,15 +90,14 @@ image::security/images/role-space-visualization.png["Associate space"] [float] ==== Create the developer's user account with the proper roles -Go to **Management > Users** and click on **Create user** to create a -user. Give the user the `dev-mortgage` role +Go to **Management > Users** and click on **Create user** to create a +user. Give the user the `dev-mortgage` role and the `monitoring-user` role, which is required for users of **Stack Monitoring**. [role="screenshot"] image::security/images/role-new-user.png["Developer user"] -Finally, have the developer log in and access the Dev Mortgage space +Finally, have the developer log in and access the Dev Mortgage space and create a new visualization. NOTE: If the user is assigned to only one space, they will automatically enter that space on login. - diff --git a/docs/visualize/vega.asciidoc b/docs/visualize/vega.asciidoc index c9cf1e7aeb8205..b8c0d1dbe3ddaf 100644 --- a/docs/visualize/vega.asciidoc +++ b/docs/visualize/vega.asciidoc @@ -324,7 +324,7 @@ 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] below. +values. See link:#sizing-and-positioning[sizing and positioning]. [[vega-additional-configuration-options]] ==== Additional configuration options diff --git a/examples/embeddable_examples/public/hello_world/hello_world_embeddable_factory.ts b/examples/embeddable_examples/public/hello_world/hello_world_embeddable_factory.ts index de5a3d9380def3..2995c99ac9e58a 100644 --- a/examples/embeddable_examples/public/hello_world/hello_world_embeddable_factory.ts +++ b/examples/embeddable_examples/public/hello_world/hello_world_embeddable_factory.ts @@ -33,7 +33,7 @@ export class HelloWorldEmbeddableFactory extends EmbeddableFactory { * embeddables should check the UI Capabilities service to be sure of * the right permissions. */ - public isEditable() { + public async isEditable() { return true; } diff --git a/examples/embeddable_examples/public/list_container/list_container.tsx b/examples/embeddable_examples/public/list_container/list_container.tsx index 35a674a03573a6..bbbd0d6e323046 100644 --- a/examples/embeddable_examples/public/list_container/list_container.tsx +++ b/examples/embeddable_examples/public/list_container/list_container.tsx @@ -21,7 +21,7 @@ import ReactDOM from 'react-dom'; import { Container, ContainerInput, - GetEmbeddableFactory, + EmbeddableStart, } from '../../../../src/plugins/embeddable/public'; import { ListContainerComponent } from './list_container_component'; @@ -31,7 +31,10 @@ export class ListContainer extends Container<{}, ContainerInput> { public readonly type = LIST_CONTAINER; private node?: HTMLElement; - constructor(input: ContainerInput, getEmbeddableFactory: GetEmbeddableFactory) { + constructor( + input: ContainerInput, + getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory'] + ) { super(input, { embeddableLoaded: {} }, getEmbeddableFactory); } diff --git a/examples/embeddable_examples/public/list_container/list_container_factory.ts b/examples/embeddable_examples/public/list_container/list_container_factory.ts index de6b7d5f5e5039..247cf48b41bde2 100644 --- a/examples/embeddable_examples/public/list_container/list_container_factory.ts +++ b/examples/embeddable_examples/public/list_container/list_container_factory.ts @@ -20,25 +20,30 @@ import { i18n } from '@kbn/i18n'; import { EmbeddableFactory, - GetEmbeddableFactory, ContainerInput, + EmbeddableStart, } from '../../../../src/plugins/embeddable/public'; import { LIST_CONTAINER, ListContainer } from './list_container'; +interface StartServices { + getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory']; +} + export class ListContainerFactory extends EmbeddableFactory { public readonly type = LIST_CONTAINER; public readonly isContainerType = true; - constructor(private getEmbeddableFactory: GetEmbeddableFactory) { + constructor(private getStartServices: () => Promise) { super(); } - public isEditable() { + public async isEditable() { return true; } public async create(initialInput: ContainerInput) { - return new ListContainer(initialInput, this.getEmbeddableFactory); + const { getEmbeddableFactory } = await this.getStartServices(); + return new ListContainer(initialInput, getEmbeddableFactory); } public getDisplayName() { diff --git a/examples/embeddable_examples/public/multi_task_todo/multi_task_todo_embeddable_factory.ts b/examples/embeddable_examples/public/multi_task_todo/multi_task_todo_embeddable_factory.ts index a54201b157a6ca..9afdeabaee7656 100644 --- a/examples/embeddable_examples/public/multi_task_todo/multi_task_todo_embeddable_factory.ts +++ b/examples/embeddable_examples/public/multi_task_todo/multi_task_todo_embeddable_factory.ts @@ -32,7 +32,7 @@ export class MultiTaskTodoEmbeddableFactory extends EmbeddableFactory< > { public readonly type = MULTI_TASK_TODO_EMBEDDABLE; - public isEditable() { + public async isEditable() { return true; } diff --git a/examples/embeddable_examples/public/plugin.ts b/examples/embeddable_examples/public/plugin.ts index b7a4f5c078d546..3663af68ae2c79 100644 --- a/examples/embeddable_examples/public/plugin.ts +++ b/examples/embeddable_examples/public/plugin.ts @@ -17,20 +17,11 @@ * under the License. */ -import { - IEmbeddableSetup, - IEmbeddableStart, - EmbeddableFactory, -} from '../../../src/plugins/embeddable/public'; +import { EmbeddableSetup, EmbeddableStart } from '../../../src/plugins/embeddable/public'; import { Plugin, CoreSetup, CoreStart } from '../../../src/core/public'; import { HelloWorldEmbeddableFactory, HELLO_WORLD_EMBEDDABLE } from './hello_world'; import { TODO_EMBEDDABLE, TodoEmbeddableFactory, TodoInput, TodoOutput } from './todo'; -import { - MULTI_TASK_TODO_EMBEDDABLE, - MultiTaskTodoEmbeddableFactory, - MultiTaskTodoOutput, - MultiTaskTodoInput, -} from './multi_task_todo'; +import { MULTI_TASK_TODO_EMBEDDABLE, MultiTaskTodoEmbeddableFactory } from './multi_task_todo'; import { SEARCHABLE_LIST_CONTAINER, SearchableListContainerFactory, @@ -38,46 +29,56 @@ import { import { LIST_CONTAINER, ListContainerFactory } from './list_container'; interface EmbeddableExamplesSetupDependencies { - embeddable: IEmbeddableSetup; + embeddable: EmbeddableSetup; } interface EmbeddableExamplesStartDependencies { - embeddable: IEmbeddableStart; + embeddable: EmbeddableStart; } export class EmbeddableExamplesPlugin implements Plugin { - public setup(core: CoreSetup, deps: EmbeddableExamplesSetupDependencies) { + public setup( + core: CoreSetup, + deps: EmbeddableExamplesSetupDependencies + ) { deps.embeddable.registerEmbeddableFactory( HELLO_WORLD_EMBEDDABLE, new HelloWorldEmbeddableFactory() ); - deps.embeddable.registerEmbeddableFactory< - EmbeddableFactory - >(MULTI_TASK_TODO_EMBEDDABLE, new MultiTaskTodoEmbeddableFactory()); - } + deps.embeddable.registerEmbeddableFactory( + MULTI_TASK_TODO_EMBEDDABLE, + new MultiTaskTodoEmbeddableFactory() + ); - public start(core: CoreStart, deps: EmbeddableExamplesStartDependencies) { // These are registered in the start method because `getEmbeddableFactory ` // is only available in start. We could reconsider this I think and make it // available in both. deps.embeddable.registerEmbeddableFactory( SEARCHABLE_LIST_CONTAINER, - new SearchableListContainerFactory(deps.embeddable.getEmbeddableFactory) + new SearchableListContainerFactory(async () => ({ + getEmbeddableFactory: (await core.getStartServices())[1].embeddable.getEmbeddableFactory, + })) ); deps.embeddable.registerEmbeddableFactory( LIST_CONTAINER, - new ListContainerFactory(deps.embeddable.getEmbeddableFactory) + new ListContainerFactory(async () => ({ + getEmbeddableFactory: (await core.getStartServices())[1].embeddable.getEmbeddableFactory, + })) ); - deps.embeddable.registerEmbeddableFactory>( + deps.embeddable.registerEmbeddableFactory( TODO_EMBEDDABLE, - new TodoEmbeddableFactory(core.overlays.openModal) + new TodoEmbeddableFactory(async () => ({ + openModal: (await core.getStartServices())[0].overlays.openModal, + })) ); } + public start(core: CoreStart, deps: EmbeddableExamplesStartDependencies) {} + public stop() {} } diff --git a/examples/embeddable_examples/public/searchable_list_container/searchable_list_container.tsx b/examples/embeddable_examples/public/searchable_list_container/searchable_list_container.tsx index 3079abb867c387..06462937c768d7 100644 --- a/examples/embeddable_examples/public/searchable_list_container/searchable_list_container.tsx +++ b/examples/embeddable_examples/public/searchable_list_container/searchable_list_container.tsx @@ -21,7 +21,7 @@ import ReactDOM from 'react-dom'; import { Container, ContainerInput, - GetEmbeddableFactory, + EmbeddableStart, EmbeddableInput, } from '../../../../src/plugins/embeddable/public'; import { SearchableListContainerComponent } from './searchable_list_container_component'; @@ -40,7 +40,10 @@ export class SearchableListContainer extends Container Promise) { super(); } - public isEditable() { + public async isEditable() { return true; } public async create(initialInput: SearchableContainerInput) { - return new SearchableListContainer(initialInput, this.getEmbeddableFactory); + const { getEmbeddableFactory } = await this.getStartServices(); + return new SearchableListContainer(initialInput, getEmbeddableFactory); } public getDisplayName() { diff --git a/examples/embeddable_examples/public/todo/todo_embeddable_factory.tsx b/examples/embeddable_examples/public/todo/todo_embeddable_factory.tsx index dd2168bb39eeeb..d7be436905382f 100644 --- a/examples/embeddable_examples/public/todo/todo_embeddable_factory.tsx +++ b/examples/embeddable_examples/public/todo/todo_embeddable_factory.tsx @@ -43,6 +43,10 @@ function TaskInput({ onSave }: { onSave: (task: string) => void }) { ); } +interface StartServices { + openModal: OverlayStart['openModal']; +} + export class TodoEmbeddableFactory extends EmbeddableFactory< TodoInput, TodoOutput, @@ -50,11 +54,11 @@ export class TodoEmbeddableFactory extends EmbeddableFactory< > { public readonly type = TODO_EMBEDDABLE; - constructor(private openModal: OverlayStart['openModal']) { + constructor(private getStartServices: () => Promise) { super(); } - public isEditable() { + public async isEditable() { return true; } @@ -69,9 +73,10 @@ export class TodoEmbeddableFactory extends EmbeddableFactory< * in this case, the task string. */ public async getExplicitInput() { + const { openModal } = await this.getStartServices(); return new Promise<{ task: string }>(resolve => { const onSave = (task: string) => resolve({ task }); - const overlay = this.openModal( + const overlay = openModal( toMountPoint( { diff --git a/examples/embeddable_explorer/public/app.tsx b/examples/embeddable_explorer/public/app.tsx index da7e8cc188e31f..9c8568454855db 100644 --- a/examples/embeddable_explorer/public/app.tsx +++ b/examples/embeddable_explorer/public/app.tsx @@ -23,7 +23,7 @@ import { BrowserRouter as Router, Route, withRouter, RouteComponentProps } from import { EuiPage, EuiPageSideBar, EuiSideNav } from '@elastic/eui'; -import { IEmbeddableStart } from '../../../src/plugins/embeddable/public'; +import { EmbeddableStart } from '../../../src/plugins/embeddable/public'; import { UiActionsStart } from '../../../src/plugins/ui_actions/public'; import { Start as InspectorStartContract } from '../../../src/plugins/inspector/public'; import { @@ -74,7 +74,7 @@ const Nav = withRouter(({ history, navigateToApp, pages }: NavProps) => { interface Props { basename: string; navigateToApp: CoreStart['application']['navigateToApp']; - embeddableApi: IEmbeddableStart; + embeddableApi: EmbeddableStart; uiActionsApi: UiActionsStart; overlays: OverlayStart; notifications: CoreStart['notifications']; diff --git a/examples/embeddable_explorer/public/embeddable_panel_example.tsx b/examples/embeddable_explorer/public/embeddable_panel_example.tsx index e6687d8563f59d..b26111bed7ff23 100644 --- a/examples/embeddable_explorer/public/embeddable_panel_example.tsx +++ b/examples/embeddable_explorer/public/embeddable_panel_example.tsx @@ -31,9 +31,8 @@ import { import { EuiSpacer } from '@elastic/eui'; import { OverlayStart, CoreStart, SavedObjectsStart, IUiSettingsClient } from 'kibana/public'; import { - GetEmbeddableFactory, EmbeddablePanel, - IEmbeddableStart, + EmbeddableStart, IEmbeddable, } from '../../../src/plugins/embeddable/public'; import { @@ -47,8 +46,8 @@ import { Start as InspectorStartContract } from '../../../src/plugins/inspector/ import { getSavedObjectFinder } from '../../../src/plugins/saved_objects/public'; interface Props { - getAllEmbeddableFactories: IEmbeddableStart['getEmbeddableFactories']; - getEmbeddableFactory: GetEmbeddableFactory; + getAllEmbeddableFactories: EmbeddableStart['getEmbeddableFactories']; + getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory']; uiActionsApi: UiActionsStart; overlays: OverlayStart; notifications: CoreStart['notifications']; diff --git a/examples/embeddable_explorer/public/hello_world_embeddable_example.tsx b/examples/embeddable_explorer/public/hello_world_embeddable_example.tsx index 74a6766a1b5ee4..ea1c3d781ebfda 100644 --- a/examples/embeddable_explorer/public/hello_world_embeddable_example.tsx +++ b/examples/embeddable_explorer/public/hello_world_embeddable_example.tsx @@ -29,14 +29,14 @@ import { EuiText, } from '@elastic/eui'; import { - GetEmbeddableFactory, + EmbeddableStart, EmbeddableFactoryRenderer, EmbeddableRoot, } from '../../../src/plugins/embeddable/public'; import { HelloWorldEmbeddable, HELLO_WORLD_EMBEDDABLE } from '../../embeddable_examples/public'; interface Props { - getEmbeddableFactory: GetEmbeddableFactory; + getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory']; } export function HelloWorldEmbeddableExample({ getEmbeddableFactory }: Props) { diff --git a/examples/embeddable_explorer/public/list_container_example.tsx b/examples/embeddable_explorer/public/list_container_example.tsx index 2c7b12a27d963a..969fdb0ca46db8 100644 --- a/examples/embeddable_explorer/public/list_container_example.tsx +++ b/examples/embeddable_explorer/public/list_container_example.tsx @@ -29,10 +29,7 @@ import { EuiText, } from '@elastic/eui'; import { EuiSpacer } from '@elastic/eui'; -import { - GetEmbeddableFactory, - EmbeddableFactoryRenderer, -} from '../../../src/plugins/embeddable/public'; +import { EmbeddableFactoryRenderer, EmbeddableStart } from '../../../src/plugins/embeddable/public'; import { HELLO_WORLD_EMBEDDABLE, TODO_EMBEDDABLE, @@ -42,7 +39,7 @@ import { } from '../../embeddable_examples/public'; interface Props { - getEmbeddableFactory: GetEmbeddableFactory; + getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory']; } export function ListContainerExample({ getEmbeddableFactory }: Props) { diff --git a/examples/embeddable_explorer/public/plugin.tsx b/examples/embeddable_explorer/public/plugin.tsx index 1294e0c89c9e7d..7c75b108d99122 100644 --- a/examples/embeddable_explorer/public/plugin.tsx +++ b/examples/embeddable_explorer/public/plugin.tsx @@ -19,12 +19,12 @@ import { Plugin, CoreSetup, AppMountParameters } from 'kibana/public'; import { UiActionsService } from '../../../src/plugins/ui_actions/public'; -import { IEmbeddableStart } from '../../../src/plugins/embeddable/public'; +import { EmbeddableStart } from '../../../src/plugins/embeddable/public'; import { Start as InspectorStart } from '../../../src/plugins/inspector/public'; interface StartDeps { uiActions: UiActionsService; - embeddable: IEmbeddableStart; + embeddable: EmbeddableStart; inspector: InspectorStart; } diff --git a/examples/embeddable_explorer/public/todo_embeddable_example.tsx b/examples/embeddable_explorer/public/todo_embeddable_example.tsx index b1c93087faf83b..ce92301236c2b8 100644 --- a/examples/embeddable_explorer/public/todo_embeddable_example.tsx +++ b/examples/embeddable_explorer/public/todo_embeddable_example.tsx @@ -39,10 +39,10 @@ import { TODO_EMBEDDABLE, TodoEmbeddableFactory, } from '../../../examples/embeddable_examples/public/todo'; -import { GetEmbeddableFactory, EmbeddableRoot } from '../../../src/plugins/embeddable/public'; +import { EmbeddableStart, EmbeddableRoot } from '../../../src/plugins/embeddable/public'; interface Props { - getEmbeddableFactory: GetEmbeddableFactory; + getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory']; } interface State { diff --git a/package.json b/package.json index a97c21164d406d..b3dcfb2aa3b0a7 100644 --- a/package.json +++ b/package.json @@ -138,6 +138,7 @@ "@kbn/test-subj-selector": "0.2.1", "@kbn/ui-framework": "1.0.0", "@kbn/ui-shared-deps": "1.0.0", + "@types/tar": "^4.0.3", "JSONStream": "1.3.5", "abortcontroller-polyfill": "^1.4.0", "angular": "^1.7.9", @@ -225,7 +226,7 @@ "prop-types": "15.6.0", "proxy-from-env": "1.0.0", "pug": "^2.0.4", - "query-string": "6.10.1", + "query-string": "5.1.1", "raw-loader": "3.1.0", "react": "^16.12.0", "react-color": "^2.13.8", @@ -454,6 +455,7 @@ "listr": "^0.14.1", "load-grunt-config": "^3.0.1", "mocha": "^6.2.2", + "mock-http-server": "1.3.0", "multistream": "^2.1.1", "murmurhash3js": "3.0.1", "mutation-observer": "^1.0.3", diff --git a/packages/kbn-config-schema/src/errors/validation_error.ts b/packages/kbn-config-schema/src/errors/validation_error.ts index d688d022da85cd..2a4f887bc43498 100644 --- a/packages/kbn-config-schema/src/errors/validation_error.ts +++ b/packages/kbn-config-schema/src/errors/validation_error.ts @@ -44,5 +44,8 @@ export class ValidationError extends SchemaError { constructor(error: SchemaTypeError, namespace?: string) { super(ValidationError.extractMessage(error, namespace), error); + + // https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work + Object.setPrototypeOf(this, ValidationError.prototype); } } diff --git a/packages/kbn-dev-utils/src/kbn_client/kbn_client_ui_settings.ts b/packages/kbn-dev-utils/src/kbn_client/kbn_client_ui_settings.ts index ad01dea624c3c6..dbfa87e70032bf 100644 --- a/packages/kbn-dev-utils/src/kbn_client/kbn_client_ui_settings.ts +++ b/packages/kbn-dev-utils/src/kbn_client/kbn_client_ui_settings.ts @@ -67,7 +67,7 @@ export class KbnClientUiSettings { * Replace all uiSettings with the `doc` values, `doc` is merged * with some defaults */ - async replace(doc: UiSettingValues) { + async replace(doc: UiSettingValues, { retries = 5 }: { retries?: number } = {}) { this.log.debug('replacing kibana config doc: %j', doc); const changes: Record = { @@ -85,7 +85,7 @@ export class KbnClientUiSettings { method: 'POST', path: '/api/kibana/settings', body: { changes }, - retries: 5, + retries, }); } diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index fe0491870e4bda..338d4893005260 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -43920,7 +43920,7 @@ class KbnClientUiSettings { * Replace all uiSettings with the `doc` values, `doc` is merged * with some defaults */ - async replace(doc) { + async replace(doc, { retries = 5 } = {}) { this.log.debug('replacing kibana config doc: %j', doc); const changes = { ...this.defaults, @@ -43935,7 +43935,7 @@ class KbnClientUiSettings { method: 'POST', path: '/api/kibana/settings', body: { changes }, - retries: 5, + retries, }); } /** diff --git a/renovate.json5 b/renovate.json5 index ca2cd2e6bcd932..e4836537df703f 100644 --- a/renovate.json5 +++ b/renovate.json5 @@ -431,6 +431,14 @@ '@types/jquery', ], }, + { + groupSlug: 'js-search', + groupName: 'js-search related packages', + packageNames: [ + 'js-search', + '@types/js-search', + ], + }, { groupSlug: 'js-yaml', groupName: 'js-yaml related packages', @@ -877,6 +885,14 @@ '@types/supertest-as-promised', ], }, + { + groupSlug: 'tar', + groupName: 'tar related packages', + packageNames: [ + 'tar', + '@types/tar', + ], + }, { groupSlug: 'tar-fs', groupName: 'tar-fs related packages', diff --git a/rfcs/text/0010_service_status.md b/rfcs/text/0010_service_status.md new file mode 100644 index 00000000000000..ded594930a3677 --- /dev/null +++ b/rfcs/text/0010_service_status.md @@ -0,0 +1,373 @@ +- Start Date: 2020-03-07 +- RFC PR: https://github.com/elastic/kibana/pull/59621 +- Kibana Issue: https://github.com/elastic/kibana/issues/41983 + +# Summary + +A set API for describing the current status of a system (Core service or plugin) +in Kibana. + +# Basic example + +```ts +// Override default behavior and only elevate severity when elasticsearch is not available +core.status.set( + core.status.core$.pipe(core => core.elasticsearch); +) +``` + +# Motivation + +Kibana should do as much possible to help users keep their installation in a working state. This includes providing as much detail about components that are not working as well as ensuring that failures in one part of the application do not block using other portions of the application. + +In order to provide the user with as much detail as possible about any systems that are not working correctly, the status mechanism should provide excellent defaults in terms of expressing relationships between services and presenting detailed information to the user. + +# Detailed design + +## Failure Guidelines + +While this RFC primarily describes how status information is signaled from individual services and plugins to Core, it's first important to define how Core expects these services and plugins to behave in the face of failure more broadly. + +Core is designed to be resilient and adaptive to change. When at all possible, Kibana should automatically recover from failure, rather than requiring any kind of intervention by the user or administrator. + +Given this goal, Core expects the following from plugins: +- During initialization, `setup`, and `start` plugins should only throw an exception if a truly unrecoverable issue is encountered. Examples: HTTP port is unavailable, server does not have the appropriate file permissions. +- Temporary error conditions should always be retried automatically. A user should not have to restart Kibana in order to resolve a problem when avoidable. This means all initialization code should include error handling and automated retries. Examples: creating an Elasticsearch index, connecting to an external service. + - It's important to note that some issues do require manual intervention in _other services_ (eg. Elasticsearch). Kibana should still recover without restarting once that external issue is resolved. +- Unhandled promise rejections are not permitted. In the future, Node.js will crash on unhandled promise rejections. It is impossible for Core to be able to properly handle and retry these situations, so all services and plugins should handle all rejected promises and retry when necessary. +- Plugins should only crash the Kibana server when absolutely necessary. Some features are considered "mission-critical" to customers and may need to halt Kibana if they are not functioning correctly. Example: audit logging. + +## API Design + +### Types + +```ts +/** + * The current status of a service at a point in time. + * + * @typeParam Meta - JSON-serializable object. Plugins should export this type to allow other plugins to read the `meta` + * field in a type-safe way. + */ +type ServiceStatus = unknown> = { + /** + * The current availability level of the service. + */ + level: ServiceStatusLevel.available; + /** + * A high-level summary of the service status. + */ + summary?: string; + /** + * A more detailed description of the service status. + */ + detail?: string; + /** + * A URL to open in a new tab about how to resolve or troubleshoot the problem. + */ + documentationUrl?: string; + /** + * Any JSON-serializable data to be included in the HTTP API response. Useful for providing more fine-grained, + * machine-readable information about the service status. May include status information for underlying features. + */ + meta?: Meta; +} | { + level: ServiceStatusLevel; + summary: string; // required when level !== available + detail?: string; + documentationUrl?: string; + meta?: Meta; +} + +/** + * The current "level" of availability of a service. + */ +enum ServiceStatusLevel { + /** + * Everything is working! + */ + available, + /** + * Some features may not be working. + */ + degraded, + /** + * The service is unavailable, but other functions that do not depend on this service should work. + */ + unavailable, + /** + * Block all user functions and display the status page, reserved for Core services only. + * Note: In the real implementation, this will be split out to a different type. Kept as a single type here to make + * the RFC easier to follow. + */ + critical +} + +/** + * Status of core services. Only contains entries for backend services that could have a non-available `status`. + * For example, `context` cannot possibly be broken, so it is not included. + */ +interface CoreStatus { + elasticsearch: ServiceStatus; + http: ServiceStatus; + savedObjects: ServiceStatus; + uiSettings: ServiceStatus; + metrics: ServiceStatus; +} +``` + +### Plugin API + +```ts +/** + * The API exposed to plugins on CoreSetup.status + */ +interface StatusSetup { + /** + * Allows a plugin to specify a custom status dependent on its own criteria. + * Completely overrides the default inherited status. + */ + set(status$: Observable): void; + + /** + * Current status for all Core services. + */ + core$: Observable; + + /** + * Current status for all dependencies of the current plugin. + * Each key of the `Record` is a plugin id. + */ + plugins$: Observable>; + + /** + * The status of this plugin as derived from its dependencies. + * + * @remarks + * By default, plugins inherit this derived status from their dependencies. + * Calling {@link StatusSetup.set} overrides this default status. + */ + derivedStatus$: Observable; +} +``` + +### HTTP API + +The HTTP endpoint should return basic information about the Kibana node as well as the overall system status and the status of each individual system. + +This API does not need to include UI-specific details like the existing API such as `uiColor` and `icon`. + +```ts +/** + * Response type for the endpoint: GET /api/status + */ +interface StatusResponse { + /** server.name */ + name: string; + /** server.uuid */ + uuid: string; + /** Currently exposed by existing status API */ + version: { + number: string; + build_hash: string; + build_number: number; + build_snapshot: boolean; + }; + /** Similar format to existing API, but slightly different shape */ + status: { + /** See "Overall status calculation" section below */ + overall: ServiceStatus; + core: CoreStatus; + plugins: Record; + } +} +``` + +## Behaviors + +### Levels + +Each member of the `ServiceStatusLevel` enum has specific behaviors associated with it: +- **`available`**: + - All endpoints and apps associated with the service are accessible +- **`degraded`**: + - All endpoints and apps are available by default + - Some APIs may return `503 Unavailable` responses. This is not automatic, must be implemented directly by the service. + - Some plugin contract APIs may throw errors. This is not automatic, must be implemented directly by the service. +- **`unavailable`**: + - All endpoints (with some exceptions in Core) in Kibana return a `503 Unavailable` responses by default. This is automatic. + - When trying to access any app associated with the unavailable service, the user is presented with an error UI with detail about the outage. + - Some plugin contract APIs may throw errors. This is not automatic, must be implemented directly by the service. +- **`critical`**: + - All endpoints (with some exceptions in Core) in Kibana return a `503 Unavailable` response by default. This is automatic. + - All applications redirect to the system-wide status page with detail about which services are down and any relevant detail. This is automatic. + - Some plugin contract APIs may throw errors. This is not automatic, must be implemented directly by the service. + - This level is reserved for Core services only. + +### Overall status calculation + +The status level of the overall system is calculated to be the highest severity status of all core services and plugins. + +The `summary` property is calculated as follows: +- If the overall status level is `available`, the `summary` is `"Kibana is operating normally"` +- If a single core service or plugin is not `available`, the `summary` is `Kibana is ${level} due to ${serviceName}. See ${statusPageUrl} for more information.` +- If multiple core services or plugins are not `available`, the `summary` is `Kibana is ${level} due to multiple components. See ${statusPageUrl} for more information.` + +### Status inheritance + +By default, plugins inherit their status from all Core services and their dependencies on other plugins. + +This can be summarized by the following matrix: + +| core | required | optional | inherited | +|----------------|----------------|----------------|-------------| +| critical | _any_ | _any_ | critical | +| unavailable | <= unavailable | <= unavailable | unavailable | +| degraded | <= degraded | <= degraded | degraded | +| <= unavailable | unavailable | <= unavailable | unavailable | +| <= degraded | degraded | <= degraded | degraded | +| <= degraded | <= degraded | unavailable | degraded | +| <= degraded | <= degraded | degraded | degraded | +| available | available | available | available | + +If a plugin calls the `StatusSetup#set` API, the inherited status is completely overridden. They status the plugin specifies is the source of truth. If a plugin wishes to "merge" its custom status with the inherited status calculated by Core, it may do so by using the `StatusSetup#inherited$` property in its calculated status. + +If a plugin never calls the `StatusSetup#set` API, the plugin's status defaults to the inherited status. + +_Disabled_ plugins, that is plugins that are explicitly disabled in Kibana's configuration, do not have any status. They are not present in any status APIs and are **not** considered `unavailable`. Disabled plugins are excluded from the status inheritance calculation, even if a plugin has a optional dependency on a disabled plugin. In summary, if a plugin has an optional dependency on a disabled plugin, the plugin will not be considered `degraded` just because that optional dependency is disabled. + +### HTTP responses + +As specified in the [_Levels section_](#levels), a service's HTTP endpoints will respond with `503 Unavailable` responses in some status levels. + +In both the `critical` and `unavailable` levels, all of a service's endpoints will return 503s. However, in the `degraded` level, it is up to service authors to decide which endpoints should return a 503. This may be implemented directly in the route handler logic or by using any of the [utilities provided](#status-utilities). + +When a 503 is returned either via the default behavior or behavior implemented using the [provided utilities](#status-utilities), the HTTP response will include the following: +- `Retry-After` header, set to `60` seconds +- A body with mime type `application/json` containing the status of the service the HTTP route belongs to: + ```json5 + { + "error": "Unavailable", + // `ServiceStatus#summary` + "message": "Newsfeed API cannot be reached", + "attributes": { + "status": { + // Human readable form of `ServiceStatus#level` + "level": "critical", + // `ServiceStatus#summary` + "summary": "Newsfeed API cannot be reached", + // `ServiceStatus#detail` or null + "detail": null, + // `ServiceStatus#documentationUrl` or null + "documentationUrl": null, + // JSON-serialized from `ServiceStatus#meta` or null + "meta": {} + } + }, + "statusCode": 503 + } + ``` + +## Status Utilities + +Though many plugins should be able to rely on the default status inheritance and associated behaviors, there are common patterns and overrides that some plugins will need. The status service should provide some utilities for these common patterns out-of-the-box. + +```ts +/** + * Extension of the main Status API + */ +interface StatusSetup { + /** + * Helpers for expressing status in HTTP routes. + */ + http: { + /** + * High-order route handler function for wrapping routes with 503 logic based + * on a predicate. + * + * @remarks + * When a 503 is returned, it also includes detailed information from the service's + * current `ServiceStatus` including `meta` information. + * + * @example + * ```ts + * router.get( + * { path: '/my-api' } + * unavailableWhen( + * ServiceStatusLevel.degraded, + * async (context, req, res) => { + * return res.ok({ body: 'done' }); + * } + * ) + * ) + * ``` + * + * @param predicate When a level is specified, if the plugin's current status + * level is >= to the severity of the specified level, route + * returns a 503. When a function is specified, if that + * function returns `true`, a 503 is returned. + * @param handler The route handler to execute when a 503 is not returned. + * @param options.retryAfter Number of seconds to set the `Retry-After` + * header to when the endpoint is unavailable. + * Defaults to `60`. + */ + unavailableWhen( + predicate: ServiceStatusLevel | + (self: ServiceStatus, core: CoreStatus, plugins: Record) => boolean, + handler: RouteHandler, + options?: { retryAfter?: number } + ): RouteHandler; + } +} +``` + +## Additional Examples + +### Combine inherited status with check against external dependency +```ts +const getExternalDepHealth = async () => { + const resp = await window.fetch('https://myexternaldep.com/_healthz'); + return resp.json(); +} + +// Create an observable that checks the status of an external service every every 10s +const myExternalDependency$: Observable = interval(10000).pipe( + mergeMap(() => of(getExternalDepHealth())), + map(health => health.ok ? ServiceStatusLevel.available : ServiceStatusLevel.unavailable), + catchError(() => of(ServiceStatusLevel.unavailable)) +); + +// Merge the inherited status with the external check +core.status.set( + combineLatest( + core.status.inherited$, + myExternalDependency$ + ).pipe( + map(([inherited, external]) => ({ + level: Math.max(inherited.level, external) + })) + ) +); +``` + +# Drawbacks + +1. **The default behaviors and inheritance of statuses may appear to be "magic" to developers who do not read the documentation about how this works.** Compared to the legacy status mechanism, these defaults are much more opinionated and the resulting status is less explicit in plugin code compared to the legacy `mirrorPluginStatus` mechanism. +2. **The default behaviors and inheritance may not fit real-world status very well.** If many plugins must customize their status in order to opt-out of the defaults, this would be a step backwards from the legacy mechanism. + +# Alternatives + +We could somewhat reduce the complexity of the status inheritance by leveraging the dependencies between plugins to enable and disable plugins based on whether or not their upstream dependencies are available. This may simplify plugin code but would greatly complicate how Kibana fundamentally operates, requiring that plugins may get stopped and started multiple times within a single Kibana server process. We would be trading simplicity in one area for complexity in another. + +# Adoption strategy + +By default, most plugins would not need to do much at all. Today, very few plugins leverage the legacy status system. The majority of ones that do, simply call the `mirrorPluginStatus` utility to follow the status of the legacy elasticsearch plugin. + +Plugins that wish to expose more detail about their availability will easily be able to do so, including providing detailed information such as links to documentation to resolve the problem. + +# How we teach this + +This largely follows the same patterns we have used for other Core APIs: Observables, composable utilties, etc. + +This should be taught using the same channels we've leveraged for other Kibana Platform APIs: API documentation, additions to the [Migration Guide](../../src/core/MIGRATION.md) and [Migration Examples](../../src/core/MIGRATION_EXMAPLES.md). + +# Unresolved questions diff --git a/src/core/MIGRATION.md b/src/core/MIGRATION.md index e04d45f77db5d3..1ca9b63a51d187 100644 --- a/src/core/MIGRATION.md +++ b/src/core/MIGRATION.md @@ -45,7 +45,7 @@ - [UI Exports](#ui-exports) - [How to](#how-to) - [Configure plugin](#configure-plugin) - - [Handle plugin configuration deprecations](#handle-plugin-config-deprecations) + - [Handle plugin configuration deprecations](#handle-plugin-configuration-deprecations) - [Use scoped services](#use-scoped-services) - [Declare a custom scoped service](#declare-a-custom-scoped-service) - [Mock new platform services in tests](#mock-new-platform-services-in-tests) @@ -55,7 +55,7 @@ - [Provide Legacy Platform API to the New platform plugin](#provide-legacy-platform-api-to-the-new-platform-plugin) - [On the server side](#on-the-server-side) - [On the client side](#on-the-client-side) - - [Updates an application navlink at runtime](#updates-an-app-navlink-at-runtime) + - [Updates an application navlink at runtime](#updates-an-application-navlink-at-runtime) - [Logging config migration](#logging-config-migration) Make no mistake, it is going to take a lot of work to move certain plugins to the new platform. Our target is to migrate the entire repo over to the new platform throughout 7.x and to remove the legacy plugin system no later than 8.0, and this is only possible if teams start on the effort now. @@ -1157,33 +1157,32 @@ In client code, we have a series of plugins which house shared application servi The contracts for these plugins are exposed for you to consume in your own plugin; we have created dedicated exports for the `setup` and `start` contracts in a file called `legacy`. By passing these contracts to your plugin's `setup` and `start` methods, you can mimic the functionality that will eventually be provided in the new platform. ```ts -import { setup, start } from '../core_plugins/data/public/legacy'; -import { setup, start } from '../core_plugins/embeddables/public/legacy'; import { setup, start } from '../core_plugins/visualizations/public/legacy'; ``` | Legacy Platform | New Platform | Notes | | ------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ | -| `import 'ui/management'` | `management.sections` | | | `import 'ui/apply_filters'` | N/A. Replaced by triggering an APPLY_FILTER_TRIGGER trigger. | Directive is deprecated. | | `import 'ui/filter_bar'` | `import { FilterBar } from '../data/public'` | Directive is deprecated. | | `import 'ui/query_bar'` | `import { QueryStringInput } from '../data/public'` | Directives are deprecated. | | `import 'ui/search_bar'` | `import { SearchBar } from '../data/public'` | Directive is deprecated. | | `import 'ui/kbn_top_nav'` | `import { TopNavMenu } from '../navigation/public'` | Directive was moved to `src/plugins/kibana_legacy`. | | `ui/saved_objects/components/saved_object_finder` | `import { SavedObjectFinder } from '../saved_objects/public'` | | -| `core_plugins/interpreter` | `data.expressions` | still in progress | -| `ui/courier` | `data.search` | still in progress | -| `ui/embeddable` | `embeddables` | still in progress | -| `ui/filter_manager` | `data.filter` | -- | -| `ui/index_patterns` | `data.indexPatterns` | still in progress | -| `ui/registry/field_formats` | `data.fieldFormats` | | -| `ui/registry/feature_catalogue` | `home.featureCatalogue.register` | Must add `home` as a dependency in your kibana.json. | -| `ui/registry/vis_types` | `visualizations` | -- | -| `ui/vis` | `visualizations` | -- | -| `ui/share` | `share` | `showShareContextMenu` is now called `toggleShareContextMenu`, `ShareContextMenuExtensionsRegistryProvider` is now called `register` | -| `ui/vis/vis_factory` | `visualizations` | -- | -| `ui/vis/vis_filters` | `visualizations.filters` | -- | -| `ui/utils/parse_es_interval` | `import { parseEsInterval } from '../data/public'` | `parseEsInterval`, `ParsedInterval`, `InvalidEsCalendarIntervalError`, `InvalidEsIntervalFormatError` items were moved to the `Data Plugin` as a static code | +| `core_plugins/interpreter` | `plugins.data.expressions` | +| `ui/courier` | `plugins.data.search` | +| `ui/agg_types` | `plugins.data.search.aggs` | Most code is available for static import. Stateful code is part of the `search` service. +| `ui/embeddable` | `plugins.embeddables` | +| `ui/filter_manager` | `plugins.data.filter` | -- | +| `ui/index_patterns` | `plugins.data.indexPatterns` | +| `import 'ui/management'` | `plugins.management.sections` | | +| `ui/registry/field_formats` | `plugins.data.fieldFormats` | | +| `ui/registry/feature_catalogue` | `plugins.home.featureCatalogue.register` | Must add `home` as a dependency in your kibana.json. | +| `ui/registry/vis_types` | `plugins.visualizations` | -- | +| `ui/vis` | `plugins.visualizations` | -- | +| `ui/share` | `plugins.share` | `showShareContextMenu` is now called `toggleShareContextMenu`, `ShareContextMenuExtensionsRegistryProvider` is now called `register` | +| `ui/vis/vis_factory` | `plugins.visualizations` | -- | +| `ui/vis/vis_filters` | `plugins.visualizations.filters` | -- | +| `ui/utils/parse_es_interval` | `import { search: { aggs: { parseEsInterval } } } from '../data/public'` | `parseEsInterval`, `ParsedInterval`, `InvalidEsCalendarIntervalError`, `InvalidEsIntervalFormatError` items were moved to the `Data Plugin` as a static code | #### Server-side @@ -1199,13 +1198,13 @@ In server code, `core` can be accessed from either `server.newPlatform` or `kbnS | `request.getBasePath()` | [`core.http.basePath.get`](/docs/development/core/server/kibana-plugin-server.httpservicesetup.basepath.md) | | | `server.plugins.elasticsearch.getCluster('data')` | [`context.core.elasticsearch.dataClient`](/docs/development/core/server/kibana-plugin-server.iscopedclusterclient.md) | | | `server.plugins.elasticsearch.getCluster('admin')` | [`context.core.elasticsearch.adminClient`](/docs/development/core/server/kibana-plugin-server.iscopedclusterclient.md) | | -| `server.plugins.elasticsearch.createCluster(...)` | [`core.elasticsearch.createClient`](/docs/development/core/server/kibana-plugin-server.elasticsearchservicesetup.createclient.md) | | +| `server.plugins.elasticsearch.createCluster(...)` | [`core.elasticsearch.legacy.createClient`](/docs/development/core/server/kibana-plugin-server.elasticsearchservicestart.legacy.md) | | | `server.savedObjects.setScopedSavedObjectsClientFactory` | [`core.savedObjects.setClientFactoryProvider`](/docs/development/core/server/kibana-plugin-server.savedobjectsservicesetup.setclientfactoryprovider.md) | | | `server.savedObjects.addScopedSavedObjectsClientWrapperFactory` | [`core.savedObjects.addClientWrapper`](/docs/development/core/server/kibana-plugin-server.savedobjectsservicesetup.addclientwrapper.md) | | | `server.savedObjects.getSavedObjectsRepository` | [`core.savedObjects.createInternalRepository`](/docs/development/core/server/kibana-plugin-server.savedobjectsservicestart.createinternalrepository.md) [`core.savedObjects.createScopedRepository`](/docs/development/core/server/kibana-plugin-server.savedobjectsservicestart.createscopedrepository.md) | | | `server.savedObjects.getScopedSavedObjectsClient` | [`core.savedObjects.getScopedClient`](/docs/development/core/server/kibana-plugin-server.savedobjectsservicestart.getscopedclient.md) | | | `request.getSavedObjectsClient` | [`context.core.savedObjects.client`](/docs/development/core/server/kibana-plugin-server.requesthandlercontext.core.md) | | -| `request.getUiSettingsService` | [`context.uiSettings.client`](/docs/development/core/server/kibana-plugin-server.iuisettingsclient.md) | | +| `request.getUiSettingsService` | [`context.core.uiSettings.client`](/docs/development/core/server/kibana-plugin-server.iuisettingsclient.md) | | | `kibana.Plugin.deprecations` | [Handle plugin configuration deprecations](#handle-plugin-config-deprecations) and [`PluginConfigDescriptor.deprecations`](docs/development/core/server/kibana-plugin-server.pluginconfigdescriptor.md) | Deprecations from New Platform are not applied to legacy configuration | | `kibana.Plugin.savedObjectSchemas` | [`core.savedObjects.registerType`](docs/development/core/server/kibana-plugin-server.savedobjectsservicesetup.registertype.md) | [Examples](./MIGRATION_EXAMPLES.md#saved-objects-types) | | `kibana.Plugin.mappings` | [`core.savedObjects.registerType`](docs/development/core/server/kibana-plugin-server.savedobjectsservicesetup.registertype.md) | [Examples](./MIGRATION_EXAMPLES.md#saved-objects-types) | @@ -1262,7 +1261,7 @@ This table shows where these uiExports have moved to in the New Platform. In mos | `validations` | | Part of SavedObjects, see [#33587](https://github.com/elastic/kibana/issues/33587) | | `visEditorTypes` | | | | `visTypeEnhancers` | | | -| `visTypes` | | | +| `visTypes` | `plugins.visualizations.types` | | | `visualize` | | | Examples: diff --git a/src/core/public/index.ts b/src/core/public/index.ts index 483d4dbfdf7c54..0ff044878afa9a 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -171,7 +171,7 @@ export { ErrorToastOptions, } from './notifications'; -export { MountPoint, UnmountCallback } from './types'; +export { MountPoint, UnmountCallback, PublicUiSettingsParams } from './types'; /** * Core services exposed to the `Plugin` setup lifecycle diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index f71a50e2927d88..fa5dc745e69313 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -16,10 +16,11 @@ import { Location } from 'history'; import { LocationDescriptorObject } from 'history'; import { MaybePromise } from '@kbn/utility-types'; import { Observable } from 'rxjs'; +import { PublicUiSettingsParams as PublicUiSettingsParams_2 } from 'src/core/server/types'; import React from 'react'; import * as Rx from 'rxjs'; import { ShallowPromise } from '@kbn/utility-types'; -import { UiSettingsParams as UiSettingsParams_2 } from 'src/core/server/types'; +import { Type } from '@kbn/config-schema'; import { UnregisterCallback } from 'history'; import { UserProvidedValues as UserProvidedValues_2 } from 'src/core/server/types'; @@ -735,8 +736,10 @@ export interface IContextContainer> { registerContext>(pluginOpaqueId: PluginOpaqueId, contextName: TContextName, provider: IContextProvider): this; } +// Warning: (ae-forgotten-export) The symbol "PartialExceptFor" needs to be exported by the entry point index.d.ts +// // @public -export type IContextProvider, TContextName extends keyof HandlerContextType> = (context: Partial>, ...rest: HandlerParameters) => Promise[TContextName]> | HandlerContextType[TContextName]; +export type IContextProvider, TContextName extends keyof HandlerContextType> = (context: PartialExceptFor, 'core'>, ...rest: HandlerParameters) => Promise[TContextName]> | HandlerContextType[TContextName]; // @public (undocumented) export interface IHttpFetchError extends Error { @@ -782,7 +785,7 @@ export type IToasts = Pick(key: string, defaultOverride?: T) => Observable; get: (key: string, defaultOverride?: T) => T; - getAll: () => Readonly>; + getAll: () => Readonly>; getSaved$: () => Observable<{ key: string; newValue: T; @@ -931,6 +934,9 @@ export interface PluginInitializerContext // @public (undocumented) export type PluginOpaqueId = symbol; +// @public +export type PublicUiSettingsParams = Omit; + // Warning: (ae-forgotten-export) The symbol "RecursiveReadonlyArray" needs to be exported by the entry point index.d.ts // // @public (undocumented) @@ -938,6 +944,8 @@ export type RecursiveReadonly = T extends (...args: any[]) => any ? T : T ext [K in keyof T]: RecursiveReadonly; }> : T; +// Warning: (ae-missing-release-tag) "SavedObject" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export interface SavedObject { attributes: T; @@ -1289,7 +1297,7 @@ export type ToastsSetup = IToasts; export type ToastsStart = IToasts; // @public -export interface UiSettingsParams { +export interface UiSettingsParams { category?: string[]; // Warning: (ae-forgotten-export) The symbol "DeprecationSettings" needs to be exported by the entry point index.d.ts deprecation?: DeprecationSettings; @@ -1299,16 +1307,18 @@ export interface UiSettingsParams { options?: string[]; readonly?: boolean; requiresPageReload?: boolean; + // (undocumented) + schema: Type; type?: UiSettingsType; // (undocumented) validation?: ImageValidation | StringValidation; - value?: SavedObjectAttribute; + value?: T; } // @public (undocumented) export interface UiSettingsState { // (undocumented) - [key: string]: UiSettingsParams_2 & UserProvidedValues_2; + [key: string]: PublicUiSettingsParams_2 & UserProvidedValues_2; } // @public diff --git a/src/core/public/saved_objects/index.ts b/src/core/public/saved_objects/index.ts index 5015a9c3db78e2..13b4a128936664 100644 --- a/src/core/public/saved_objects/index.ts +++ b/src/core/public/saved_objects/index.ts @@ -32,11 +32,6 @@ export { export { SimpleSavedObject } from './simple_saved_object'; export { SavedObjectsStart, SavedObjectsService } from './saved_objects_service'; export { - SavedObject, - SavedObjectAttribute, - SavedObjectAttributes, - SavedObjectAttributeSingle, - SavedObjectReference, SavedObjectsBaseOptions, SavedObjectsFindOptions, SavedObjectsMigrationVersion, @@ -48,3 +43,11 @@ export { SavedObjectsImportError, SavedObjectsImportRetry, } from '../../server/types'; + +export { + SavedObject, + SavedObjectAttribute, + SavedObjectAttributes, + SavedObjectAttributeSingle, + SavedObjectReference, +} from '../../types'; diff --git a/src/core/public/types.ts b/src/core/public/types.ts index 267a9e9f7e0145..26f1e46836378e 100644 --- a/src/core/public/types.ts +++ b/src/core/public/types.ts @@ -19,6 +19,7 @@ export { UiSettingsParams, + PublicUiSettingsParams, UserProvidedValues, UiSettingsType, ImageValidation, diff --git a/src/core/public/ui_settings/__snapshots__/ui_settings_api.test.ts.snap b/src/core/public/ui_settings/__snapshots__/ui_settings_api.test.ts.snap index cd55c77526d529..b737c04a5f269e 100644 --- a/src/core/public/ui_settings/__snapshots__/ui_settings_api.test.ts.snap +++ b/src/core/public/ui_settings/__snapshots__/ui_settings_api.test.ts.snap @@ -84,21 +84,21 @@ Array [ exports[`#batchSet rejects all promises for batched requests that fail: promise rejections 1`] = ` Array [ Object { - "error": [Error: Request failed with status code: 400], + "error": [Error: invalid], "isRejected": true, }, Object { - "error": [Error: Request failed with status code: 400], + "error": [Error: invalid], "isRejected": true, }, Object { - "error": [Error: Request failed with status code: 400], + "error": [Error: invalid], "isRejected": true, }, ] `; -exports[`#batchSet rejects on 301 1`] = `"Request failed with status code: 301"`; +exports[`#batchSet rejects on 301 1`] = `"Moved Permanently"`; exports[`#batchSet rejects on 404 response 1`] = `"Request failed with status code: 404"`; diff --git a/src/core/public/ui_settings/types.ts b/src/core/public/ui_settings/types.ts index 19fd91924f247d..d92c033ae8c8c4 100644 --- a/src/core/public/ui_settings/types.ts +++ b/src/core/public/ui_settings/types.ts @@ -18,11 +18,11 @@ */ import { Observable } from 'rxjs'; -import { UiSettingsParams, UserProvidedValues } from 'src/core/server/types'; +import { PublicUiSettingsParams, UserProvidedValues } from 'src/core/server/types'; /** @public */ export interface UiSettingsState { - [key: string]: UiSettingsParams & UserProvidedValues; + [key: string]: PublicUiSettingsParams & UserProvidedValues; } /** @@ -53,7 +53,7 @@ export interface IUiSettingsClient { * Gets the metadata about all uiSettings, including the type, default value, and user value * for each key. */ - getAll: () => Readonly>; + getAll: () => Readonly>; /** * Sets the value for a uiSetting. If the setting is not registered by any plugin diff --git a/src/core/public/ui_settings/ui_settings_api.test.ts b/src/core/public/ui_settings/ui_settings_api.test.ts index 1170c42cea704c..9a462e05413472 100644 --- a/src/core/public/ui_settings/ui_settings_api.test.ts +++ b/src/core/public/ui_settings/ui_settings_api.test.ts @@ -148,7 +148,7 @@ describe('#batchSet', () => { '*', { status: 400, - body: 'invalid', + body: { message: 'invalid' }, }, { overwriteRoutes: false, diff --git a/src/core/public/ui_settings/ui_settings_api.ts b/src/core/public/ui_settings/ui_settings_api.ts index 33b43107acf1bc..c5efced0a41e3f 100644 --- a/src/core/public/ui_settings/ui_settings_api.ts +++ b/src/core/public/ui_settings/ui_settings_api.ts @@ -152,10 +152,14 @@ export class UiSettingsApi { }, }); } catch (err) { - if (err.response && err.response.status >= 300) { - throw new Error(`Request failed with status code: ${err.response.status}`); + if (err.response) { + if (err.response.status === 400) { + throw new Error(err.body.message); + } + if (err.response.status > 400) { + throw new Error(`Request failed with status code: ${err.response.status}`); + } } - throw err; } finally { this.loadingCount$.next(this.loadingCount$.getValue() - 1); diff --git a/src/core/public/ui_settings/ui_settings_client.ts b/src/core/public/ui_settings/ui_settings_client.ts index f0071ed08435c8..f5596b1bc34fc2 100644 --- a/src/core/public/ui_settings/ui_settings_client.ts +++ b/src/core/public/ui_settings/ui_settings_client.ts @@ -21,14 +21,14 @@ import { cloneDeep, defaultsDeep } from 'lodash'; import { Observable, Subject, concat, defer, of } from 'rxjs'; import { filter, map } from 'rxjs/operators'; -import { UiSettingsParams, UserProvidedValues } from 'src/core/server/types'; +import { UserProvidedValues, PublicUiSettingsParams } from 'src/core/server/types'; import { IUiSettingsClient, UiSettingsState } from './types'; import { UiSettingsApi } from './ui_settings_api'; interface UiSettingsClientParams { api: UiSettingsApi; - defaults: Record; + defaults: Record; initialSettings?: UiSettingsState; done$: Observable; } @@ -39,8 +39,8 @@ export class UiSettingsClient implements IUiSettingsClient { private readonly updateErrors$ = new Subject(); private readonly api: UiSettingsApi; - private readonly defaults: Record; - private cache: Record; + private readonly defaults: Record; + private cache: Record; constructor(params: UiSettingsClientParams) { this.api = params.api; diff --git a/src/core/server/core_app/core_app.ts b/src/core/server/core_app/core_app.ts new file mode 100644 index 00000000000000..2f8c85f47a76e4 --- /dev/null +++ b/src/core/server/core_app/core_app.ts @@ -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 { InternalCoreSetup } from '../internal_types'; +import { CoreContext } from '../core_context'; +import { Logger } from '../logging'; + +/** @internal */ +export class CoreApp { + private readonly logger: Logger; + constructor(core: CoreContext) { + this.logger = core.logger.get('core-app'); + } + setup(coreSetup: InternalCoreSetup) { + this.logger.debug('Setting up core app.'); + this.registerDefaultRoutes(coreSetup); + } + + private registerDefaultRoutes(coreSetup: InternalCoreSetup) { + const httpSetup = coreSetup.http; + const router = httpSetup.createRouter('/'); + router.get({ path: '/', validate: false }, async (context, req, res) => { + const defaultRoute = await context.core.uiSettings.client.get('defaultRoute'); + const basePath = httpSetup.basePath.get(req); + const url = `${basePath}${defaultRoute}`; + + return res.redirected({ + headers: { + location: url, + }, + }); + }); + router.get({ path: '/core', validate: false }, async (context, req, res) => + res.ok({ body: { version: '0.0.1' } }) + ); + } +} diff --git a/src/legacy/core_plugins/dashboard_embeddable_container/public/np_ready/public/legacy.ts b/src/core/server/core_app/index.ts similarity index 95% rename from src/legacy/core_plugins/dashboard_embeddable_container/public/np_ready/public/legacy.ts rename to src/core/server/core_app/index.ts index 9880b336e76e5c..342ed43f1ff8a2 100644 --- a/src/legacy/core_plugins/dashboard_embeddable_container/public/np_ready/public/legacy.ts +++ b/src/core/server/core_app/index.ts @@ -16,3 +16,5 @@ * specific language governing permissions and limitations * under the License. */ + +export { CoreApp } from './core_app'; diff --git a/src/core/server/core_app/integration_tests/default_route_provider_config.test.ts b/src/core/server/core_app/integration_tests/default_route_provider_config.test.ts new file mode 100644 index 00000000000000..221e6fa42471cd --- /dev/null +++ b/src/core/server/core_app/integration_tests/default_route_provider_config.test.ts @@ -0,0 +1,90 @@ +/* + * 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 * as kbnTestServer from '../../../../test_utils/kbn_server'; +import { Root } from '../../root'; + +const { startES } = kbnTestServer.createTestServers({ + adjustTimeout: (t: number) => jest.setTimeout(t), +}); +let esServer: kbnTestServer.TestElasticsearchUtils; + +describe('default route provider', () => { + let root: Root; + + beforeAll(async () => { + esServer = await startES(); + root = kbnTestServer.createRootWithCorePlugins({ + server: { + basePath: '/hello', + }, + }); + + await root.setup(); + await root.start(); + }); + + afterAll(async () => { + await esServer.stop(); + await root.shutdown(); + }); + + it('redirects to the configured default route respecting basePath', async function() { + const { status, header } = await kbnTestServer.request.get(root, '/'); + + expect(status).toEqual(302); + expect(header).toMatchObject({ + location: '/hello/app/kibana', + }); + }); + + it('ignores invalid values', async function() { + const invalidRoutes = [ + 'http://not-your-kibana.com', + '///example.com', + '//example.com', + ' //example.com', + ]; + + for (const url of invalidRoutes) { + await kbnTestServer.request + .post(root, '/api/kibana/settings/defaultRoute') + .send({ value: url }) + .expect(400); + } + + const { status, header } = await kbnTestServer.request.get(root, '/'); + expect(status).toEqual(302); + expect(header).toMatchObject({ + location: '/hello/app/kibana', + }); + }); + + it('consumes valid values', async function() { + await kbnTestServer.request + .post(root, '/api/kibana/settings/defaultRoute') + .send({ value: '/valid' }) + .expect(200); + + const { status, header } = await kbnTestServer.request.get(root, '/'); + expect(status).toEqual(302); + expect(header).toMatchObject({ + location: '/hello/valid', + }); + }); +}); diff --git a/src/core/server/elasticsearch/elasticsearch_service.mock.ts b/src/core/server/elasticsearch/elasticsearch_service.mock.ts index b8ad3754965449..389d98a0818c8e 100644 --- a/src/core/server/elasticsearch/elasticsearch_service.mock.ts +++ b/src/core/server/elasticsearch/elasticsearch_service.mock.ts @@ -22,7 +22,11 @@ import { IClusterClient, ICustomClusterClient } from './cluster_client'; import { IScopedClusterClient } from './scoped_cluster_client'; import { ElasticsearchConfig } from './elasticsearch_config'; import { ElasticsearchService } from './elasticsearch_service'; -import { InternalElasticsearchServiceSetup, ElasticsearchServiceSetup } from './types'; +import { + InternalElasticsearchServiceSetup, + ElasticsearchServiceSetup, + ElasticsearchServiceStart, +} from './types'; import { NodesVersionCompatibility } from './version_check/ensure_es_version'; const createScopedClusterClientMock = (): jest.Mocked => ({ @@ -63,6 +67,26 @@ const createSetupContractMock = () => { return setupContract; }; +type MockedElasticSearchServiceStart = { + legacy: jest.Mocked; +} & { + legacy: { + client: jest.Mocked; + }; +}; + +const createStartContractMock = () => { + const startContract: MockedElasticSearchServiceStart = { + legacy: { + createClient: jest.fn(), + client: createClusterClientMock(), + }, + }; + startContract.legacy.createClient.mockReturnValue(createCustomClusterClientMock()); + startContract.legacy.client.asScoped.mockReturnValue(createScopedClusterClientMock()); + return startContract; +}; + type MockedInternalElasticSearchServiceSetup = jest.Mocked< InternalElasticsearchServiceSetup & { adminClient: jest.Mocked; @@ -95,6 +119,7 @@ const createMock = () => { stop: jest.fn(), }; mocked.setup.mockResolvedValue(createInternalSetupContractMock()); + mocked.start.mockResolvedValueOnce(createStartContractMock()); mocked.stop.mockResolvedValue(); return mocked; }; @@ -103,6 +128,7 @@ export const elasticsearchServiceMock = { create: createMock, createInternalSetup: createInternalSetupContractMock, createSetup: createSetupContractMock, + createStart: createStartContractMock, createClusterClient: createClusterClientMock, createCustomClusterClient: createCustomClusterClientMock, createScopedClusterClient: createScopedClusterClientMock, diff --git a/src/core/server/elasticsearch/elasticsearch_service.ts b/src/core/server/elasticsearch/elasticsearch_service.ts index 6616b42f136c04..b92a6edf778ed0 100644 --- a/src/core/server/elasticsearch/elasticsearch_service.ts +++ b/src/core/server/elasticsearch/elasticsearch_service.ts @@ -37,7 +37,7 @@ import { ClusterClient, ScopeableRequest } from './cluster_client'; import { ElasticsearchClientConfig } from './elasticsearch_client_config'; import { ElasticsearchConfig, ElasticsearchConfigType } from './elasticsearch_config'; import { InternalHttpServiceSetup, GetAuthHeaders } from '../http/'; -import { InternalElasticsearchServiceSetup } from './types'; +import { InternalElasticsearchServiceSetup, ElasticsearchServiceStart } from './types'; import { CallAPIOptions } from './api_types'; import { pollEsNodesVersion } from './version_check/ensure_es_version'; @@ -53,12 +53,16 @@ interface SetupDeps { } /** @internal */ -export class ElasticsearchService implements CoreService { +export class ElasticsearchService + implements CoreService { private readonly log: Logger; private readonly config$: Observable; private subscription: Subscription | undefined; private stop$ = new Subject(); private kibanaVersion: string; + createClient: InternalElasticsearchServiceSetup['createClient'] | undefined; + dataClient: InternalElasticsearchServiceSetup['dataClient'] | undefined; + adminClient: InternalElasticsearchServiceSetup['adminClient'] | undefined; constructor(private readonly coreContext: CoreContext) { this.kibanaVersion = coreContext.env.packageInfo.version; @@ -111,7 +115,7 @@ export class ElasticsearchService implements CoreService clients.adminClient)); const dataClient$ = clients$.pipe(map(clients => clients.dataClient)); - const adminClient = { + this.adminClient = { async callAsInternalUser( endpoint: string, clientParams: Record = {}, @@ -120,9 +124,9 @@ export class ElasticsearchService implements CoreService { return { - callAsInternalUser: adminClient.callAsInternalUser, + callAsInternalUser: this.adminClient!.callAsInternalUser, async callAsCurrentUser( endpoint: string, clientParams: Record = {}, @@ -136,6 +140,7 @@ export class ElasticsearchService implements CoreService = {}) => { + const finalConfig = merge({}, config, clientConfig); + return this.createClusterClient(type, finalConfig, deps.http.getAuthHeaders); + }; + return { legacy: { config$: clients$.pipe(map(clients => clients.config)) }, - - adminClient, - dataClient, esNodesCompatibility$, - - createClient: (type: string, clientConfig: Partial = {}) => { - const finalConfig = merge({}, config, clientConfig); - return this.createClusterClient(type, finalConfig, deps.http.getAuthHeaders); - }, + adminClient: this.adminClient, + dataClient, + createClient: this.createClient, }; } - public async start() {} + public async start() { + if (typeof this.adminClient === 'undefined' || typeof this.createClient === 'undefined') { + throw new Error('ElasticsearchService needs to be setup before calling start'); + } else { + return { + legacy: { + client: this.adminClient, + createClient: this.createClient, + }, + }; + } + } public async stop() { this.log.debug('Stopping elasticsearch service'); diff --git a/src/core/server/elasticsearch/types.ts b/src/core/server/elasticsearch/types.ts index 90cfdcc035d8e4..ef8edecfd26ec6 100644 --- a/src/core/server/elasticsearch/types.ts +++ b/src/core/server/elasticsearch/types.ts @@ -28,6 +28,9 @@ import { NodesVersionCompatibility } from './version_check/ensure_es_version'; */ export interface ElasticsearchServiceSetup { /** + * @deprecated + * Use {@link ElasticsearchServiceStart.legacy | ElasticsearchServiceStart.legacy.createClient} instead. + * * Create application specific Elasticsearch cluster API client with customized config. See {@link IClusterClient}. * * @param type Unique identifier of the client @@ -50,6 +53,9 @@ export interface ElasticsearchServiceSetup { ) => ICustomClusterClient; /** + * @deprecated + * Use {@link ElasticsearchServiceStart.legacy | ElasticsearchServiceStart.legacy.client} instead. + * * A client for the `admin` cluster. All Elasticsearch config value changes are processed under the hood. * See {@link IClusterClient}. * @@ -61,6 +67,9 @@ export interface ElasticsearchServiceSetup { readonly adminClient: IClusterClient; /** + * @deprecated + * Use {@link ElasticsearchServiceStart.legacy | ElasticsearchServiceStart.legacy.client} instead. + * * A client for the `data` cluster. All Elasticsearch config value changes are processed under the hood. * See {@link IClusterClient}. * @@ -72,6 +81,46 @@ export interface ElasticsearchServiceSetup { readonly dataClient: IClusterClient; } +/** + * @public + */ +export interface ElasticsearchServiceStart { + legacy: { + /** + * Create application specific Elasticsearch cluster API client with customized config. See {@link IClusterClient}. + * + * @param type Unique identifier of the client + * @param clientConfig A config consists of Elasticsearch JS client options and + * valid sub-set of Elasticsearch service config. + * We fill all the missing properties in the `clientConfig` using the default + * Elasticsearch config so that we don't depend on default values set and + * controlled by underlying Elasticsearch JS client. + * We don't run validation against the passed config and expect it to be valid. + * + * @example + * ```js + * const client = elasticsearch.createCluster('my-app-name', config); + * const data = await client.callAsInternalUser(); + * ``` + */ + readonly createClient: ( + type: string, + clientConfig?: Partial + ) => ICustomClusterClient; + + /** + * A pre-configured Elasticsearch client. All Elasticsearch config value changes are processed under the hood. + * See {@link IClusterClient}. + * + * @example + * ```js + * const client = core.elasticsearch.client; + * ``` + */ + readonly client: IClusterClient; + }; +} + /** @internal */ export interface InternalElasticsearchServiceSetup extends ElasticsearchServiceSetup { // Required for the BWC with the legacy Kibana only. diff --git a/src/core/server/index.ts b/src/core/server/index.ts index e2faf49ba7a9e0..89fee92a7ef027 100644 --- a/src/core/server/index.ts +++ b/src/core/server/index.ts @@ -43,6 +43,7 @@ import { ElasticsearchServiceSetup, IScopedClusterClient, configSchema as elasticsearchConfigSchema, + ElasticsearchServiceStart, } from './elasticsearch'; import { HttpServiceSetup } from './http'; @@ -93,6 +94,7 @@ export { ElasticsearchError, ElasticsearchErrorHelpers, ElasticsearchServiceSetup, + ElasticsearchServiceStart, APICaller, FakeRequest, ScopeableRequest, @@ -248,6 +250,7 @@ export { export { IUiSettingsClient, UiSettingsParams, + PublicUiSettingsParams, UiSettingsType, UiSettingsServiceSetup, UiSettingsServiceStart, @@ -366,6 +369,8 @@ export interface CoreSetup { export interface CoreStart { /** {@link CapabilitiesStart} */ capabilities: CapabilitiesStart; + /** {@link ElasticsearchServiceStart} */ + elasticsearch: ElasticsearchServiceStart; /** {@link SavedObjectsServiceStart} */ savedObjects: SavedObjectsServiceStart; /** {@link UiSettingsServiceStart} */ diff --git a/src/core/server/internal_types.ts b/src/core/server/internal_types.ts index 37d1061dc618dc..825deea99bc230 100644 --- a/src/core/server/internal_types.ts +++ b/src/core/server/internal_types.ts @@ -22,7 +22,7 @@ import { Type } from '@kbn/config-schema'; import { CapabilitiesSetup, CapabilitiesStart } from './capabilities'; import { ConfigDeprecationProvider } from './config'; import { ContextSetup } from './context'; -import { InternalElasticsearchServiceSetup } from './elasticsearch'; +import { InternalElasticsearchServiceSetup, ElasticsearchServiceStart } from './elasticsearch'; import { InternalHttpServiceSetup } from './http'; import { InternalSavedObjectsServiceSetup, @@ -49,6 +49,7 @@ export interface InternalCoreSetup { */ export interface InternalCoreStart { capabilities: CapabilitiesStart; + elasticsearch: ElasticsearchServiceStart; savedObjects: InternalSavedObjectsServiceStart; uiSettings: InternalUiSettingsServiceStart; } diff --git a/src/core/server/legacy/legacy_service.test.ts b/src/core/server/legacy/legacy_service.test.ts index 50468db8a504de..94e86c39289bcf 100644 --- a/src/core/server/legacy/legacy_service.test.ts +++ b/src/core/server/legacy/legacy_service.test.ts @@ -47,6 +47,7 @@ import { metricsServiceMock } from '../metrics/metrics_service.mock'; import { findLegacyPluginSpecs } from './plugins'; import { LegacyVars, LegacyServiceSetupDeps, LegacyServiceStartDeps } from './types'; import { LegacyService } from './legacy_service'; +import { coreMock } from '../mocks'; const MockKbnServer: jest.Mock = KbnServer as any; @@ -102,9 +103,8 @@ beforeEach(() => { startDeps = { core: { - capabilities: capabilitiesServiceMock.createStartContract(), + ...coreMock.createStart(), savedObjects: savedObjectsServiceMock.createInternalStartContract(), - uiSettings: uiSettingsServiceMock.createStartContract(), plugins: { contracts: new Map() }, }, plugins: {}, diff --git a/src/core/server/legacy/legacy_service.ts b/src/core/server/legacy/legacy_service.ts index f67148d720446a..b19a991fdf0d15 100644 --- a/src/core/server/legacy/legacy_service.ts +++ b/src/core/server/legacy/legacy_service.ts @@ -258,6 +258,7 @@ export class LegacyService implements CoreService { ) { const coreStart: CoreStart = { capabilities: startDeps.core.capabilities, + elasticsearch: startDeps.core.elasticsearch, savedObjects: { getScopedClient: startDeps.core.savedObjects.getScopedClient, createScopedRepository: startDeps.core.savedObjects.createScopedRepository, diff --git a/src/core/server/mocks.ts b/src/core/server/mocks.ts index a0bbe623289d8a..2aa35dff563f05 100644 --- a/src/core/server/mocks.ts +++ b/src/core/server/mocks.ts @@ -141,6 +141,7 @@ function createCoreSetupMock() { function createCoreStartMock() { const mock: MockedKeys = { capabilities: capabilitiesServiceMock.createStartContract(), + elasticsearch: elasticsearchServiceMock.createStart(), savedObjects: savedObjectsServiceMock.createStartContract(), uiSettings: uiSettingsServiceMock.createStartContract(), }; @@ -165,6 +166,7 @@ function createInternalCoreSetupMock() { function createInternalCoreStartMock() { const startDeps: InternalCoreStart = { capabilities: capabilitiesServiceMock.createStartContract(), + elasticsearch: elasticsearchServiceMock.createStart(), savedObjects: savedObjectsServiceMock.createInternalStartContract(), uiSettings: uiSettingsServiceMock.createStartContract(), }; diff --git a/src/core/server/plugins/plugin_context.ts b/src/core/server/plugins/plugin_context.ts index b430fd28fb896c..32662f07a86f02 100644 --- a/src/core/server/plugins/plugin_context.ts +++ b/src/core/server/plugins/plugin_context.ts @@ -206,6 +206,7 @@ export function createPluginStartContext( capabilities: { resolveCapabilities: deps.capabilities.resolveCapabilities, }, + elasticsearch: deps.elasticsearch, savedObjects: { getScopedClient: deps.savedObjects.getScopedClient, createInternalRepository: deps.savedObjects.createInternalRepository, diff --git a/src/core/server/saved_objects/serialization/types.ts b/src/core/server/saved_objects/serialization/types.ts index 524c2c8ffae7ae..dfaec127ba1593 100644 --- a/src/core/server/saved_objects/serialization/types.ts +++ b/src/core/server/saved_objects/serialization/types.ts @@ -50,7 +50,7 @@ export interface SavedObjectsRawDocSource { * scenario out of the box. */ interface SavedObjectDoc { - attributes: unknown; + attributes: any; id?: string; // NOTE: SavedObjectDoc is used for uncreated objects where `id` is optional type: string; namespace?: string; diff --git a/src/core/server/saved_objects/types.ts b/src/core/server/saved_objects/types.ts index 1d927211b43e50..962965a08f8b2a 100644 --- a/src/core/server/saved_objects/types.ts +++ b/src/core/server/saved_objects/types.ts @@ -35,66 +35,17 @@ export { import { LegacyConfig } from '../legacy'; import { SavedObjectUnsanitizedDoc } from './serialization'; import { SavedObjectsMigrationLogger } from './migrations/core/migration_logger'; +import { SavedObject } from '../../types'; + export { SavedObjectAttributes, SavedObjectAttribute, SavedObjectAttributeSingle, + SavedObject, + SavedObjectReference, + SavedObjectsMigrationVersion, } from '../../types'; -/** - * Information about the migrations that have been applied to this SavedObject. - * When Kibana starts up, KibanaMigrator detects outdated documents and - * migrates them based on this value. For each migration that has been applied, - * the plugin's name is used as a key and the latest migration version as the - * value. - * - * @example - * migrationVersion: { - * dashboard: '7.1.1', - * space: '6.6.6', - * } - * - * @public - */ -export interface SavedObjectsMigrationVersion { - [pluginName: string]: string; -} - -/** - * @public - */ -export interface SavedObject { - /** The ID of this Saved Object, guaranteed to be unique for all objects of the same `type` */ - id: string; - /** The type of Saved Object. Each plugin can define it's own custom Saved Object types. */ - type: string; - /** An opaque version number which changes on each successful write operation. Can be used for implementing optimistic concurrency control. */ - version?: string; - /** Timestamp of the last time this document had been updated. */ - updated_at?: string; - error?: { - message: string; - statusCode: number; - }; - /** {@inheritdoc SavedObjectAttributes} */ - attributes: T; - /** {@inheritdoc SavedObjectReference} */ - references: SavedObjectReference[]; - /** {@inheritdoc SavedObjectsMigrationVersion} */ - migrationVersion?: SavedObjectsMigrationVersion; -} - -/** - * A reference to another saved object. - * - * @public - */ -export interface SavedObjectReference { - name: string; - type: string; - id: string; -} - /** * * @public diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index 5ede98a1e6e6da..229ffc4d215757 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -647,6 +647,8 @@ export interface CoreStart { // (undocumented) capabilities: CapabilitiesStart; // (undocumented) + elasticsearch: ElasticsearchServiceStart; + // (undocumented) savedObjects: SavedObjectsServiceStart; // (undocumented) uiSettings: UiSettingsServiceStart; @@ -774,11 +776,23 @@ export class ElasticsearchErrorHelpers { // @public (undocumented) export interface ElasticsearchServiceSetup { + // @deprecated (undocumented) readonly adminClient: IClusterClient; + // @deprecated (undocumented) readonly createClient: (type: string, clientConfig?: Partial) => ICustomClusterClient; + // @deprecated (undocumented) readonly dataClient: IClusterClient; } +// @public (undocumented) +export interface ElasticsearchServiceStart { + // (undocumented) + legacy: { + readonly createClient: (type: string, clientConfig?: Partial) => ICustomClusterClient; + readonly client: IClusterClient; + }; +} + // @public (undocumented) export interface EnvironmentMode { // (undocumented) @@ -882,8 +896,10 @@ export interface IContextContainer> { registerContext>(pluginOpaqueId: PluginOpaqueId, contextName: TContextName, provider: IContextProvider): this; } +// Warning: (ae-forgotten-export) The symbol "PartialExceptFor" needs to be exported by the entry point index.d.ts +// // @public -export type IContextProvider, TContextName extends keyof HandlerContextType> = (context: Partial>, ...rest: HandlerParameters) => Promise[TContextName]> | HandlerContextType[TContextName]; +export type IContextProvider, TContextName extends keyof HandlerContextType> = (context: PartialExceptFor, 'core'>, ...rest: HandlerParameters) => Promise[TContextName]> | HandlerContextType[TContextName]; // @public export interface ICspConfig { @@ -982,7 +998,7 @@ export interface IScopedRenderingClient { export interface IUiSettingsClient { get: (key: string) => Promise; getAll: () => Promise>; - getRegistered: () => Readonly>; + getRegistered: () => Readonly>; getUserProvided: () => Promise>>; isOverridden: (key: string) => boolean; remove: (key: string) => Promise; @@ -1427,6 +1443,9 @@ export interface PluginsServiceStart { contracts: Map; } +// @public +export type PublicUiSettingsParams = Omit; + // Warning: (ae-forgotten-export) The symbol "RecursiveReadonlyArray" needs to be exported by the entry point index.d.ts // // @public (undocumented) @@ -1576,6 +1595,8 @@ export interface RouteValidatorOptions { // @public export type SafeRouteMethod = 'get' | 'options'; +// Warning: (ae-missing-release-tag) "SavedObject" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// // @public (undocumented) export interface SavedObject { attributes: T; @@ -2268,7 +2289,7 @@ export interface StringValidationRegexString { } // @public -export interface UiSettingsParams { +export interface UiSettingsParams { category?: string[]; deprecation?: DeprecationSettings; description?: string; @@ -2277,10 +2298,12 @@ export interface UiSettingsParams { options?: string[]; readonly?: boolean; requiresPageReload?: boolean; + // (undocumented) + schema: Type; type?: UiSettingsType; // (undocumented) validation?: ImageValidation | StringValidation; - value?: SavedObjectAttribute; + value?: T; } // @public (undocumented) diff --git a/src/core/server/server.ts b/src/core/server/server.ts index 792227a05e248e..09a1328f346d89 100644 --- a/src/core/server/server.ts +++ b/src/core/server/server.ts @@ -26,8 +26,9 @@ import { RawConfigurationProvider, coreDeprecationProvider, } from './config'; +import { CoreApp } from './core_app'; import { ElasticsearchService } from './elasticsearch'; -import { HttpService, InternalHttpServiceSetup } from './http'; +import { HttpService } from './http'; import { RenderingService, RenderingServiceSetup } from './rendering'; import { LegacyService, ensureValidConfiguration } from './legacy'; import { Logger, LoggerFactory } from './logging'; @@ -69,6 +70,7 @@ export class Server { private readonly uiSettings: UiSettingsService; private readonly uuid: UuidService; private readonly metrics: MetricsService; + private readonly coreApp: CoreApp; private coreStart?: InternalCoreStart; @@ -92,6 +94,7 @@ export class Server { this.capabilities = new CapabilitiesService(core); this.uuid = new UuidService(core); this.metrics = new MetricsService(core); + this.coreApp = new CoreApp(core); } public async setup() { @@ -122,8 +125,6 @@ export class Server { context: contextServiceSetup, }); - this.registerDefaultRoute(httpSetup); - const capabilitiesSetup = this.capabilities.setup({ http: httpSetup }); const elasticsearchServiceSetup = await this.elasticsearch.setup({ @@ -168,6 +169,7 @@ export class Server { }); this.registerCoreContext(coreSetup, renderingSetup); + this.coreApp.setup(coreSetup); return coreSetup; } @@ -177,19 +179,17 @@ export class Server { const savedObjectsStart = await this.savedObjects.start({}); const capabilitiesStart = this.capabilities.start(); const uiSettingsStart = await this.uiSettings.start(); - - const pluginsStart = await this.plugins.start({ - capabilities: capabilitiesStart, - savedObjects: savedObjectsStart, - uiSettings: uiSettingsStart, - }); + const elasticsearchStart = await this.elasticsearch.start(); this.coreStart = { capabilities: capabilitiesStart, + elasticsearch: elasticsearchStart, savedObjects: savedObjectsStart, uiSettings: uiSettingsStart, }; + const pluginsStart = await this.plugins.start(this.coreStart!); + await this.legacy.start({ core: { ...this.coreStart, @@ -218,13 +218,6 @@ export class Server { await this.metrics.stop(); } - private registerDefaultRoute(httpSetup: InternalHttpServiceSetup) { - const router = httpSetup.createRouter('/core'); - router.get({ path: '/', validate: false }, async (context, req, res) => - res.ok({ body: { version: '0.0.1' } }) - ); - } - private registerCoreContext(coreSetup: InternalCoreSetup, rendering: RenderingServiceSetup) { coreSetup.http.registerRouteHandlerContext( coreId, diff --git a/src/core/server/ui_settings/index.ts b/src/core/server/ui_settings/index.ts index ddb66df3ffcbe1..b11f398d59fa83 100644 --- a/src/core/server/ui_settings/index.ts +++ b/src/core/server/ui_settings/index.ts @@ -27,6 +27,7 @@ export { UiSettingsServiceStart, IUiSettingsClient, UiSettingsParams, + PublicUiSettingsParams, InternalUiSettingsServiceSetup, InternalUiSettingsServiceStart, UiSettingsType, diff --git a/src/core/server/ui_settings/integration_tests/routes.test.ts b/src/core/server/ui_settings/integration_tests/routes.test.ts new file mode 100644 index 00000000000000..c1261bc7c13506 --- /dev/null +++ b/src/core/server/ui_settings/integration_tests/routes.test.ts @@ -0,0 +1,66 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import * as kbnTestServer from '../../../../test_utils/kbn_server'; + +describe('ui settings service', () => { + describe('routes', () => { + let root: ReturnType; + beforeAll(async () => { + root = kbnTestServer.createRoot(); + + const { uiSettings } = await root.setup(); + uiSettings.register({ + custom: { + value: '42', + schema: schema.string(), + }, + }); + + await root.start(); + }, 30000); + afterAll(async () => await root.shutdown()); + + describe('set', () => { + it('validates value', async () => { + const response = await kbnTestServer.request + .post(root, '/api/kibana/settings/custom') + .send({ value: 100 }) + .expect(400); + + expect(response.body.message).toBe( + '[validation [custom]]: expected value of type [string] but got [number]' + ); + }); + }); + describe('set many', () => { + it('validates value', async () => { + const response = await kbnTestServer.request + .post(root, '/api/kibana/settings') + .send({ changes: { custom: 100, foo: 'bar' } }) + .expect(400); + + expect(response.body.message).toBe( + '[validation [custom]]: expected value of type [string] but got [number]' + ); + }); + }); + }); +}); diff --git a/src/core/server/ui_settings/routes/set.ts b/src/core/server/ui_settings/routes/set.ts index 51ad256b51335f..e5158e274245cd 100644 --- a/src/core/server/ui_settings/routes/set.ts +++ b/src/core/server/ui_settings/routes/set.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { schema } from '@kbn/config-schema'; +import { schema, ValidationError } from '@kbn/config-schema'; import { IRouter } from '../../http'; import { SavedObjectsErrorHelpers } from '../../saved_objects'; @@ -56,7 +56,7 @@ export function registerSetRoute(router: IRouter) { }); } - if (error instanceof CannotOverrideError) { + if (error instanceof CannotOverrideError || error instanceof ValidationError) { return response.badRequest({ body: error }); } diff --git a/src/core/server/ui_settings/routes/set_many.ts b/src/core/server/ui_settings/routes/set_many.ts index 3794eba004beea..5623c3fe11b807 100644 --- a/src/core/server/ui_settings/routes/set_many.ts +++ b/src/core/server/ui_settings/routes/set_many.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { schema } from '@kbn/config-schema'; +import { schema, ValidationError } from '@kbn/config-schema'; import { IRouter } from '../../http'; import { SavedObjectsErrorHelpers } from '../../saved_objects'; @@ -50,7 +50,7 @@ export function registerSetManyRoute(router: IRouter) { }); } - if (error instanceof CannotOverrideError) { + if (error instanceof CannotOverrideError || error instanceof ValidationError) { return response.badRequest({ body: error }); } diff --git a/src/core/server/ui_settings/types.ts b/src/core/server/ui_settings/types.ts index f3eb1f5a6859cc..076e1de4458d76 100644 --- a/src/core/server/ui_settings/types.ts +++ b/src/core/server/ui_settings/types.ts @@ -17,9 +17,10 @@ * under the License. */ import { SavedObjectsClientContract } from '../saved_objects/types'; -import { UiSettingsParams, UserProvidedValues } from '../../types'; +import { UiSettingsParams, UserProvidedValues, PublicUiSettingsParams } from '../../types'; export { UiSettingsParams, + PublicUiSettingsParams, StringValidationRegexString, StringValidationRegex, StringValidation, @@ -41,7 +42,7 @@ export interface IUiSettingsClient { /** * Returns registered uiSettings values {@link UiSettingsParams} */ - getRegistered: () => Readonly>; + getRegistered: () => Readonly>; /** * Retrieves uiSettings values set by the user with fallbacks to default values if not specified. */ diff --git a/src/core/server/ui_settings/ui_settings_client.test.ts b/src/core/server/ui_settings/ui_settings_client.test.ts index b8aa57291dccf6..4ce33eed267a34 100644 --- a/src/core/server/ui_settings/ui_settings_client.test.ts +++ b/src/core/server/ui_settings/ui_settings_client.test.ts @@ -18,6 +18,7 @@ */ import Chance from 'chance'; +import { schema } from '@kbn/config-schema'; import { loggingServiceMock } from '../logging/logging_service.mock'; import { createOrUpgradeSavedConfigMock } from './create_or_upgrade_saved_config/create_or_upgrade_saved_config.test.mock'; @@ -145,6 +146,22 @@ describe('ui settings', () => { expect(error.message).toBe('Unable to update "foo" because it is overridden'); } }); + + it('validates value if a schema presents', async () => { + const defaults = { foo: { schema: schema.string() } }; + const { uiSettings, savedObjectsClient } = setup({ defaults }); + + await expect( + uiSettings.setMany({ + bar: 2, + foo: 1, + }) + ).rejects.toMatchInlineSnapshot( + `[Error: [validation [foo]]: expected value of type [string] but got [number]]` + ); + + expect(savedObjectsClient.update).toHaveBeenCalledTimes(0); + }); }); describe('#set()', () => { @@ -163,6 +180,17 @@ describe('ui settings', () => { }); }); + it('validates value if a schema presents', async () => { + const defaults = { foo: { schema: schema.string() } }; + const { uiSettings, savedObjectsClient } = setup({ defaults }); + + await expect(uiSettings.set('foo', 1)).rejects.toMatchInlineSnapshot( + `[Error: [validation [foo]]: expected value of type [string] but got [number]]` + ); + + expect(savedObjectsClient.update).toHaveBeenCalledTimes(0); + }); + it('throws CannotOverrideError if the key is overridden', async () => { const { uiSettings } = setup({ overrides: { @@ -193,6 +221,20 @@ describe('ui settings', () => { expect(savedObjectsClient.update).toHaveBeenCalledWith(TYPE, ID, { one: null }); }); + it('does not fail validation', async () => { + const defaults = { + foo: { + schema: schema.string(), + value: '1', + }, + }; + const { uiSettings, savedObjectsClient } = setup({ defaults }); + + await uiSettings.remove('foo'); + + expect(savedObjectsClient.update).toHaveBeenCalledTimes(1); + }); + it('throws CannotOverrideError if the key is overridden', async () => { const { uiSettings } = setup({ overrides: { @@ -235,6 +277,20 @@ describe('ui settings', () => { }); }); + it('does not fail validation', async () => { + const defaults = { + foo: { + schema: schema.string(), + value: '1', + }, + }; + const { uiSettings, savedObjectsClient } = setup({ defaults }); + + await uiSettings.removeMany(['foo', 'bar']); + + expect(savedObjectsClient.update).toHaveBeenCalledTimes(1); + }); + it('throws CannotOverrideError if any key is overridden', async () => { const { uiSettings } = setup({ overrides: { @@ -256,7 +312,13 @@ describe('ui settings', () => { const value = chance.word(); const defaults = { key: { value } }; const { uiSettings } = setup({ defaults }); - expect(uiSettings.getRegistered()).toBe(defaults); + expect(uiSettings.getRegistered()).toEqual(defaults); + }); + it('does not leak validation schema outside', () => { + const value = chance.word(); + const defaults = { key: { value, schema: schema.string() } }; + const { uiSettings } = setup({ defaults }); + expect(uiSettings.getRegistered()).toStrictEqual({ key: { value } }); }); }); @@ -274,7 +336,7 @@ describe('ui settings', () => { const { uiSettings } = setup({ esDocSource }); const result = await uiSettings.getUserProvided(); - expect(result).toEqual({ + expect(result).toStrictEqual({ user: { userValue: 'customized', }, @@ -286,7 +348,7 @@ describe('ui settings', () => { const { uiSettings } = setup({ esDocSource }); const result = await uiSettings.getUserProvided(); - expect(result).toEqual({ + expect(result).toStrictEqual({ user: { userValue: 'customized', }, @@ -296,6 +358,32 @@ describe('ui settings', () => { }); }); + it('ignores user-configured value if it fails validation', async () => { + const esDocSource = { user: 'foo', id: 'bar' }; + const defaults = { + id: { + value: 42, + schema: schema.number(), + }, + }; + const { uiSettings } = setup({ esDocSource, defaults }); + const result = await uiSettings.getUserProvided(); + + expect(result).toStrictEqual({ + user: { + userValue: 'foo', + }, + }); + + expect(loggingServiceMock.collect(logger).warn).toMatchInlineSnapshot(` + Array [ + Array [ + "Ignore invalid UiSettings value. Error: [validation [id]]: expected value of type [number] but got [string].", + ], + ] + `); + }); + it('automatically creates the savedConfig if it is missing and returns empty object', async () => { const { uiSettings, savedObjectsClient, createOrUpgradeSavedConfig } = setup(); savedObjectsClient.get = jest @@ -303,7 +391,7 @@ describe('ui settings', () => { .mockRejectedValueOnce(SavedObjectsClient.errors.createGenericNotFoundError()) .mockResolvedValueOnce({ attributes: {} }); - expect(await uiSettings.getUserProvided()).toEqual({}); + expect(await uiSettings.getUserProvided()).toStrictEqual({}); expect(savedObjectsClient.get).toHaveBeenCalledTimes(2); @@ -320,7 +408,7 @@ describe('ui settings', () => { SavedObjectsClient.errors.createGenericNotFoundError() ); - expect(await uiSettings.getUserProvided()).toEqual({ foo: { userValue: 'bar ' } }); + expect(await uiSettings.getUserProvided()).toStrictEqual({ foo: { userValue: 'bar ' } }); }); it('returns an empty object on Forbidden responses', async () => { @@ -329,7 +417,7 @@ describe('ui settings', () => { const error = SavedObjectsClient.errors.decorateForbiddenError(new Error()); savedObjectsClient.get.mockRejectedValue(error); - expect(await uiSettings.getUserProvided()).toEqual({}); + expect(await uiSettings.getUserProvided()).toStrictEqual({}); expect(createOrUpgradeSavedConfig).toHaveBeenCalledTimes(0); }); @@ -339,7 +427,7 @@ describe('ui settings', () => { const error = SavedObjectsClient.errors.decorateEsUnavailableError(new Error()); savedObjectsClient.get.mockRejectedValue(error); - expect(await uiSettings.getUserProvided()).toEqual({}); + expect(await uiSettings.getUserProvided()).toStrictEqual({}); expect(createOrUpgradeSavedConfig).toHaveBeenCalledTimes(0); }); @@ -382,7 +470,7 @@ describe('ui settings', () => { }; const { uiSettings } = setup({ esDocSource, overrides }); - expect(await uiSettings.getUserProvided()).toEqual({ + expect(await uiSettings.getUserProvided()).toStrictEqual({ user: { userValue: 'customized', }, @@ -404,15 +492,40 @@ describe('ui settings', () => { expect(savedObjectsClient.get).toHaveBeenCalledWith(TYPE, ID); }); - it(`returns defaults when es doc is empty`, async () => { + it('returns defaults when es doc is empty', async () => { const esDocSource = {}; const defaults = { foo: { value: 'bar' } }; const { uiSettings } = setup({ esDocSource, defaults }); - expect(await uiSettings.getAll()).toEqual({ + expect(await uiSettings.getAll()).toStrictEqual({ foo: 'bar', }); }); + it('ignores user-configured value if it fails validation', async () => { + const esDocSource = { user: 'foo', id: 'bar' }; + const defaults = { + id: { + value: 42, + schema: schema.number(), + }, + }; + const { uiSettings } = setup({ esDocSource, defaults }); + const result = await uiSettings.getAll(); + + expect(result).toStrictEqual({ + id: 42, + user: 'foo', + }); + + expect(loggingServiceMock.collect(logger).warn).toMatchInlineSnapshot(` + Array [ + Array [ + "Ignore invalid UiSettings value. Error: [validation [id]]: expected value of type [number] but got [string].", + ], + ] + `); + }); + it(`merges user values, including ones without defaults, into key value pairs`, async () => { const esDocSource = { foo: 'user-override', @@ -427,7 +540,7 @@ describe('ui settings', () => { const { uiSettings } = setup({ esDocSource, defaults }); - expect(await uiSettings.getAll()).toEqual({ + expect(await uiSettings.getAll()).toStrictEqual({ foo: 'user-override', bar: 'user-provided', }); @@ -451,7 +564,7 @@ describe('ui settings', () => { const { uiSettings } = setup({ esDocSource, defaults, overrides }); - expect(await uiSettings.getAll()).toEqual({ + expect(await uiSettings.getAll()).toStrictEqual({ foo: 'bax', bar: 'user-provided', }); @@ -518,6 +631,28 @@ describe('ui settings', () => { expect(await uiSettings.get('dateFormat')).toBe('foo'); }); + + it('returns the default value if user-configured value fails validation', async () => { + const esDocSource = { id: 'bar' }; + const defaults = { + id: { + value: 42, + schema: schema.number(), + }, + }; + + const { uiSettings } = setup({ esDocSource, defaults }); + + expect(await uiSettings.get('id')).toBe(42); + + expect(loggingServiceMock.collect(logger).warn).toMatchInlineSnapshot(` + Array [ + Array [ + "Ignore invalid UiSettings value. Error: [validation [id]]: expected value of type [number] but got [string].", + ], + ] + `); + }); }); describe('#isOverridden()', () => { diff --git a/src/core/server/ui_settings/ui_settings_client.ts b/src/core/server/ui_settings/ui_settings_client.ts index a7e55d2b2da65e..76c8284175f119 100644 --- a/src/core/server/ui_settings/ui_settings_client.ts +++ b/src/core/server/ui_settings/ui_settings_client.ts @@ -16,13 +16,13 @@ * specific language governing permissions and limitations * under the License. */ -import { defaultsDeep } from 'lodash'; +import { defaultsDeep, omit } from 'lodash'; import { SavedObjectsErrorHelpers } from '../saved_objects'; import { SavedObjectsClientContract } from '../saved_objects/types'; import { Logger } from '../logging'; import { createOrUpgradeSavedConfig } from './create_or_upgrade_saved_config'; -import { IUiSettingsClient, UiSettingsParams } from './types'; +import { IUiSettingsClient, UiSettingsParams, PublicUiSettingsParams } from './types'; import { CannotOverrideError } from './ui_settings_errors'; export interface UiSettingsServiceOptions { @@ -40,14 +40,14 @@ interface ReadOptions { autoCreateOrUpgradeIfMissing?: boolean; } -interface UserProvidedValue { +interface UserProvidedValue { userValue?: T; isOverridden?: boolean; } type UiSettingsRawValue = UiSettingsParams & UserProvidedValue; -type UserProvided = Record>; +type UserProvided = Record>; type UiSettingsRaw = Record; export class UiSettingsClient implements IUiSettingsClient { @@ -72,7 +72,11 @@ export class UiSettingsClient implements IUiSettingsClient { } getRegistered() { - return this.defaults; + const copiedDefaults: Record = {}; + for (const [key, value] of Object.entries(this.defaults)) { + copiedDefaults[key] = omit(value, 'schema'); + } + return copiedDefaults; } async get(key: string): Promise { @@ -90,29 +94,21 @@ export class UiSettingsClient implements IUiSettingsClient { }, {} as Record); } - async getUserProvided(): Promise> { - const userProvided: UserProvided = {}; - - // write the userValue for each key stored in the saved object that is not overridden - for (const [key, userValue] of Object.entries(await this.read())) { - if (userValue !== null && !this.isOverridden(key)) { - userProvided[key] = { - userValue, - }; - } - } + async getUserProvided(): Promise> { + const userProvided: UserProvided = this.onReadHook(await this.read()); // write all overridden keys, dropping the userValue is override is null and // adding keys for overrides that are not in saved object - for (const [key, userValue] of Object.entries(this.overrides)) { + for (const [key, value] of Object.entries(this.overrides)) { userProvided[key] = - userValue === null ? { isOverridden: true } : { isOverridden: true, userValue }; + value === null ? { isOverridden: true } : { isOverridden: true, userValue: value }; } return userProvided; } async setMany(changes: Record) { + this.onWriteHook(changes); await this.write({ changes }); } @@ -147,6 +143,43 @@ export class UiSettingsClient implements IUiSettingsClient { return defaultsDeep(userProvided, this.defaults); } + private validateKey(key: string, value: unknown) { + const definition = this.defaults[key]; + if (value === null || definition === undefined) return; + if (definition.schema) { + definition.schema.validate(value, {}, `validation [${key}]`); + } + } + + private onWriteHook(changes: Record) { + for (const key of Object.keys(changes)) { + this.assertUpdateAllowed(key); + } + + for (const [key, value] of Object.entries(changes)) { + this.validateKey(key, value); + } + } + + private onReadHook(values: Record) { + // write the userValue for each key stored in the saved object that is not overridden + // validate value read from saved objects as it can be changed via SO API + const filteredValues: UserProvided = {}; + for (const [key, userValue] of Object.entries(values)) { + if (userValue === null || this.isOverridden(key)) continue; + try { + this.validateKey(key, userValue); + filteredValues[key] = { + userValue: userValue as T, + }; + } catch (error) { + this.log.warn(`Ignore invalid UiSettings value. ${error}.`); + } + } + + return filteredValues; + } + private async write({ changes, autoCreateOrUpgradeIfMissing = true, @@ -154,10 +187,6 @@ export class UiSettingsClient implements IUiSettingsClient { changes: Record; autoCreateOrUpgradeIfMissing?: boolean; }) { - for (const key of Object.keys(changes)) { - this.assertUpdateAllowed(key); - } - try { await this.savedObjectsClient.update(this.type, this.id, changes); } catch (error) { diff --git a/src/core/server/ui_settings/ui_settings_service.test.ts b/src/core/server/ui_settings/ui_settings_service.test.ts index 11766713b3be0a..08400f56ad2811 100644 --- a/src/core/server/ui_settings/ui_settings_service.test.ts +++ b/src/core/server/ui_settings/ui_settings_service.test.ts @@ -17,6 +17,8 @@ * under the License. */ import { BehaviorSubject } from 'rxjs'; +import { schema } from '@kbn/config-schema'; + import { MockUiSettingsClientConstructor } from './ui_settings_service.test.mock'; import { UiSettingsService, SetupDeps } from './ui_settings_service'; import { httpServiceMock } from '../http/http_service.mock'; @@ -35,6 +37,7 @@ const defaults = { value: 'bar', category: [], description: '', + schema: schema.string(), }, }; @@ -104,6 +107,45 @@ describe('uiSettings', () => { }); describe('#start', () => { + describe('validation', () => { + it('validates registered definitions', async () => { + const { register } = await service.setup(setupDeps); + register({ + custom: { + value: 42, + schema: schema.string(), + }, + }); + + await expect(service.start()).rejects.toMatchInlineSnapshot( + `[Error: [ui settings defaults [custom]]: expected value of type [string] but got [number]]` + ); + }); + + it('validates overrides', async () => { + const coreContext = mockCoreContext.create(); + coreContext.configService.atPath.mockReturnValueOnce( + new BehaviorSubject({ + overrides: { + custom: 42, + }, + }) + ); + const customizedService = new UiSettingsService(coreContext); + const { register } = await customizedService.setup(setupDeps); + register({ + custom: { + value: '42', + schema: schema.string(), + }, + }); + + await expect(customizedService.start()).rejects.toMatchInlineSnapshot( + `[Error: [ui settings overrides [custom]]: expected value of type [string] but got [number]]` + ); + }); + }); + describe('#asScopedToClient', () => { it('passes saved object type "config" to UiSettingsClient', async () => { await service.setup(setupDeps); diff --git a/src/core/server/ui_settings/ui_settings_service.ts b/src/core/server/ui_settings/ui_settings_service.ts index de2cc9d510e0c6..83e66cf6dd06da 100644 --- a/src/core/server/ui_settings/ui_settings_service.ts +++ b/src/core/server/ui_settings/ui_settings_service.ts @@ -70,6 +70,9 @@ export class UiSettingsService } public async start(): Promise { + this.validatesDefinitions(); + this.validatesOverrides(); + return { asScopedToClient: this.getScopedClientFactory(), }; @@ -101,4 +104,21 @@ export class UiSettingsService this.uiSettingsDefaults.set(key, value); }); } + + private validatesDefinitions() { + for (const [key, definition] of this.uiSettingsDefaults) { + if (definition.schema) { + definition.schema.validate(definition.value, {}, `ui settings defaults [${key}]`); + } + } + } + + private validatesOverrides() { + for (const [key, value] of Object.entries(this.overrides)) { + const definition = this.uiSettingsDefaults.get(key); + if (definition?.schema) { + definition.schema.validate(value, {}, `ui settings overrides [${key}]`); + } + } + } } diff --git a/src/core/types/saved_objects.ts b/src/core/types/saved_objects.ts index 73eb2db11d62fb..d3faab6c557cd6 100644 --- a/src/core/types/saved_objects.ts +++ b/src/core/types/saved_objects.ts @@ -46,3 +46,54 @@ export type SavedObjectAttribute = SavedObjectAttributeSingle | SavedObjectAttri export interface SavedObjectAttributes { [key: string]: SavedObjectAttribute; } + +/** + * A reference to another saved object. + * + * @public + */ +export interface SavedObjectReference { + name: string; + type: string; + id: string; +} + +/** + * Information about the migrations that have been applied to this SavedObject. + * When Kibana starts up, KibanaMigrator detects outdated documents and + * migrates them based on this value. For each migration that has been applied, + * the plugin's name is used as a key and the latest migration version as the + * value. + * + * @example + * migrationVersion: { + * dashboard: '7.1.1', + * space: '6.6.6', + * } + * + * @public + */ +export interface SavedObjectsMigrationVersion { + [pluginName: string]: string; +} + +export interface SavedObject { + /** The ID of this Saved Object, guaranteed to be unique for all objects of the same `type` */ + id: string; + /** The type of Saved Object. Each plugin can define it's own custom Saved Object types. */ + type: string; + /** An opaque version number which changes on each successful write operation. Can be used for implementing optimistic concurrency control. */ + version?: string; + /** Timestamp of the last time this document had been updated. */ + updated_at?: string; + error?: { + message: string; + statusCode: number; + }; + /** {@inheritdoc SavedObjectAttributes} */ + attributes: T; + /** {@inheritdoc SavedObjectReference} */ + references: SavedObjectReference[]; + /** {@inheritdoc SavedObjectsMigrationVersion} */ + migrationVersion?: SavedObjectsMigrationVersion; +} diff --git a/src/core/types/ui_settings.ts b/src/core/types/ui_settings.ts index eccd3f9616af07..ed1076b5719603 100644 --- a/src/core/types/ui_settings.ts +++ b/src/core/types/ui_settings.ts @@ -16,8 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - -import { SavedObjectAttribute } from './saved_objects'; +import { Type } from '@kbn/config-schema'; /** * UI element type to represent the settings. @@ -49,11 +48,11 @@ export interface DeprecationSettings { * UiSettings parameters defined by the plugins. * @public * */ -export interface UiSettingsParams { +export interface UiSettingsParams { /** title in the UI */ name?: string; /** default value to fall back to if a user doesn't provide any */ - value?: SavedObjectAttribute; + value?: T; /** description provided to a user in UI */ description?: string; /** used to group the configured setting in the UI */ @@ -73,10 +72,22 @@ export interface UiSettingsParams { /* * Allows defining a custom validation applicable to value change on the client. * @deprecated + * Use schema instead. */ validation?: ImageValidation | StringValidation; + /* + * Value validation schema + * Used to validate value on write and read. + */ + schema: Type; } +/** + * A sub-set of {@link UiSettingsParams} exposed to the client-side. + * @public + * */ +export type PublicUiSettingsParams = Omit; + /** * Allows regex objects or a regex string * @public diff --git a/src/core/utils/context.ts b/src/core/utils/context.ts index 775c8906754100..de311f91d56fa4 100644 --- a/src/core/utils/context.ts +++ b/src/core/utils/context.ts @@ -22,6 +22,11 @@ import { ShallowPromise } from '@kbn/utility-types'; import { pick } from '.'; import { CoreId, PluginOpaqueId } from '../server'; +/** + * Make all properties in T optional, except for the properties whose keys are in the union K + */ +type PartialExceptFor = Partial & Pick; + /** * A function that returns a context value for a specific key of given context type. * @@ -39,7 +44,8 @@ export type IContextProvider< THandler extends HandlerFunction, TContextName extends keyof HandlerContextType > = ( - context: Partial>, + // context.core will always be available, but plugin contexts are typed as optional + context: PartialExceptFor, 'core'>, ...rest: HandlerParameters ) => | Promise[TContextName]> @@ -261,7 +267,7 @@ export class ContextContainer> // registered that provider. const exposedContext = pick(resolvedContext, [ ...this.getContextNamesForSource(providerSource), - ]) as Partial>; + ]) as PartialExceptFor, 'core'>; return { ...resolvedContext, diff --git a/src/core/utils/url.test.ts b/src/core/utils/url.test.ts index 3c35ba44455bc4..419c0cda2b8cb5 100644 --- a/src/core/utils/url.test.ts +++ b/src/core/utils/url.test.ts @@ -17,7 +17,7 @@ * under the License. */ -import { modifyUrl } from './url'; +import { modifyUrl, isRelativeUrl } from './url'; describe('modifyUrl()', () => { test('throws an error with invalid input', () => { @@ -69,3 +69,17 @@ describe('modifyUrl()', () => { ).toEqual('mail:localhost'); }); }); + +describe('isRelativeUrl()', () => { + test('returns "true" for a relative URL', () => { + expect(isRelativeUrl('good')).toBe(true); + expect(isRelativeUrl('/good')).toBe(true); + expect(isRelativeUrl('/good/even/better')).toBe(true); + }); + test('returns "false" for a non-relative URL', () => { + expect(isRelativeUrl('http://evil.com')).toBe(false); + expect(isRelativeUrl('//evil.com')).toBe(false); + expect(isRelativeUrl('///evil.com')).toBe(false); + expect(isRelativeUrl(' //evil.com')).toBe(false); + }); +}); diff --git a/src/core/utils/url.ts b/src/core/utils/url.ts index 31de7e18140380..c2bf80ce3f86f2 100644 --- a/src/core/utils/url.ts +++ b/src/core/utils/url.ts @@ -99,3 +99,19 @@ export function modifyUrl( slashes: modifiedParts.slashes, } as UrlObject); } + +export function isRelativeUrl(candidatePath: string) { + // validate that `candidatePath` is not attempting a redirect to somewhere + // outside of this Kibana install + const all = parseUrl(candidatePath, false /* parseQueryString */, true /* slashesDenoteHost */); + const { protocol, hostname, port } = all; + // We should explicitly compare `protocol`, `port` and `hostname` to null to make sure these are not + // detected in the URL at all. For example `hostname` can be empty string for Node URL parser, but + // browser (because of various bwc reasons) processes URL differently (e.g. `///abc.com` - for browser + // hostname is `abc.com`, but for Node hostname is an empty string i.e. everything between schema (`//`) + // and the first slash that belongs to path. + if (protocol !== null || hostname !== null || port !== null) { + return false; + } + return true; +} diff --git a/src/legacy/core_plugins/dashboard_embeddable_container/package.json b/src/legacy/core_plugins/dashboard_embeddable_container/package.json deleted file mode 100644 index 7555895e8d71ba..00000000000000 --- a/src/legacy/core_plugins/dashboard_embeddable_container/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "dashboard_embeddable_container", - "version": "kibana" -} diff --git a/src/legacy/core_plugins/data/index.ts b/src/legacy/core_plugins/data/index.ts index 428f0c305a375e..10c8cf464b82de 100644 --- a/src/legacy/core_plugins/data/index.ts +++ b/src/legacy/core_plugins/data/index.ts @@ -19,8 +19,6 @@ import { resolve } from 'path'; import { Legacy } from '../../../../kibana'; -import { mappings } from './mappings'; -import { SavedQuery } from '../../../plugins/data/public'; // eslint-disable-next-line import/no-default-export export default function DataPlugin(kibana: any) { @@ -35,25 +33,7 @@ export default function DataPlugin(kibana: any) { }, init: (server: Legacy.Server) => ({}), uiExports: { - interpreter: ['plugins/data/search/expressions/boot'], injectDefaultVars: () => ({}), - mappings, - savedObjectsManagement: { - query: { - icon: 'search', - defaultSearchField: 'title', - isImportableAndExportable: true, - getTitle(obj: SavedQuery) { - return obj.attributes.title; - }, - getInAppUrl(obj: SavedQuery) { - return { - path: `/app/kibana#/discover?_a=(savedQuery:'${encodeURIComponent(obj.id)}')`, - uiCapabilitiesPath: 'discover.show', - }; - }, - }, - }, }, }; diff --git a/src/legacy/core_plugins/data/public/index.ts b/src/legacy/core_plugins/data/public/index.ts index 61d8621a368433..27a3dd825485da 100644 --- a/src/legacy/core_plugins/data/public/index.ts +++ b/src/legacy/core_plugins/data/public/index.ts @@ -17,62 +17,10 @@ * under the License. */ -// /// Define plugin function import { DataPlugin as Plugin } from './plugin'; export function plugin() { return new Plugin(); } -// /// Export types & static code - -/** @public types */ export { DataSetup, DataStart } from './plugin'; -export { - // agg_types - AggParam, // only the type is used externally, only in vis editor - AggParamOption, // only the type is used externally - DateRangeKey, // only used in field formatter deserialization, which will live in data - IAggConfig, - IAggConfigs, - IAggType, - IFieldParamType, - IMetricAggType, - IpRangeKey, // only used in field formatter deserialization, which will live in data - OptionedParamEditorProps, // only type is used externally - OptionedValueProp, // only type is used externally -} from './search/types'; - -/** @public static code */ -export * from '../common'; -export { - // agg_types TODO need to group these under a namespace or prefix - AggConfigs, - AggParamType, - AggTypeFilters, // TODO convert to interface - aggTypeFilters, - AggTypeFieldFilters, // TODO convert to interface - AggGroupNames, - aggGroupNamesMap, - BUCKET_TYPES, - CidrMask, - convertDateRangeToString, - convertIPRangeToString, - intervalOptions, // only used in Discover - isDateHistogramBucketAggConfig, - isStringType, - isType, - isValidInterval, - METRIC_TYPES, - OptionedParamType, - parentPipelineType, - propFilter, - siblingPipelineType, - termsAggFilter, - toAbsoluteDates, - // search_source - getRequestInspectorStats, - getResponseInspectorStats, - tabifyAggResponse, - tabifyGetColumns, -} from './search'; diff --git a/src/legacy/core_plugins/data/public/legacy.ts b/src/legacy/core_plugins/data/public/legacy.ts index d37c17c2240727..370b412127db88 100644 --- a/src/legacy/core_plugins/data/public/legacy.ts +++ b/src/legacy/core_plugins/data/public/legacy.ts @@ -39,6 +39,6 @@ import { plugin } from '.'; const dataPlugin = plugin(); -export const setup = dataPlugin.setup(npSetup.core, npSetup.plugins); +export const setup = dataPlugin.setup(npSetup.core); -export const start = dataPlugin.start(npStart.core, npStart.plugins); +export const start = dataPlugin.start(npStart.core); diff --git a/src/legacy/core_plugins/data/public/plugin.ts b/src/legacy/core_plugins/data/public/plugin.ts index f40cda8760bc7a..76a3d92d202832 100644 --- a/src/legacy/core_plugins/data/public/plugin.ts +++ b/src/legacy/core_plugins/data/public/plugin.ts @@ -18,73 +18,20 @@ */ import { CoreSetup, CoreStart, Plugin } from 'kibana/public'; -import { DataPublicPluginStart, DataPublicPluginSetup } from '../../../../plugins/data/public'; -import { ExpressionsSetup } from '../../../../plugins/expressions/public'; - -import { - setIndexPatterns, - setQueryService, - setUiSettings, - setInjectedMetadata, - setFieldFormats, - setSearchService, - setOverlays, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../plugins/data/public/services'; -import { setSearchServiceShim } from './services'; -import { - selectRangeAction, - SelectRangeActionContext, - ACTION_SELECT_RANGE, -} from './actions/select_range_action'; -import { - valueClickAction, - ACTION_VALUE_CLICK, - ValueClickActionContext, -} from './actions/value_click_action'; -import { - SELECT_RANGE_TRIGGER, - VALUE_CLICK_TRIGGER, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../plugins/embeddable/public/lib/triggers'; -import { UiActionsSetup, UiActionsStart } from '../../../../plugins/ui_actions/public'; - -import { SearchSetup, SearchStart, SearchService } from './search/search_service'; - -export interface DataPluginSetupDependencies { - data: DataPublicPluginSetup; - expressions: ExpressionsSetup; - uiActions: UiActionsSetup; -} - -export interface DataPluginStartDependencies { - data: DataPublicPluginStart; - uiActions: UiActionsStart; -} /** * Interface for this plugin's returned `setup` contract. * * @public */ -export interface DataSetup { - search: SearchSetup; -} +export interface DataSetup {} // eslint-disable-line @typescript-eslint/no-empty-interface /** * Interface for this plugin's returned `start` contract. * * @public */ -export interface DataStart { - search: SearchStart; -} -declare module '../../../../plugins/ui_actions/public' { - export interface ActionContextMapping { - [ACTION_SELECT_RANGE]: SelectRangeActionContext; - [ACTION_VALUE_CLICK]: ValueClickActionContext; - } -} +export interface DataStart {} // eslint-disable-line @typescript-eslint/no-empty-interface /** * Data Plugin - public @@ -98,43 +45,13 @@ declare module '../../../../plugins/ui_actions/public' { * or static code. */ -export class DataPlugin - implements - Plugin { - private readonly search = new SearchService(); - - public setup(core: CoreSetup, { data, uiActions }: DataPluginSetupDependencies) { - setInjectedMetadata(core.injectedMetadata); - - uiActions.attachAction( - SELECT_RANGE_TRIGGER, - selectRangeAction(data.query.filterManager, data.query.timefilter.timefilter) - ); - - uiActions.attachAction( - VALUE_CLICK_TRIGGER, - valueClickAction(data.query.filterManager, data.query.timefilter.timefilter) - ); - - return { - search: this.search.setup(core), - }; +export class DataPlugin implements Plugin { + public setup(core: CoreSetup) { + return {}; } - public start(core: CoreStart, { data, uiActions }: DataPluginStartDependencies): DataStart { - const search = this.search.start(core); - setSearchServiceShim(search); - - setUiSettings(core.uiSettings); - setQueryService(data.query); - setIndexPatterns(data.indexPatterns); - setFieldFormats(data.fieldFormats); - setSearchService(data.search); - setOverlays(core.overlays); - - return { - search, - }; + public start(core: CoreStart): DataStart { + return {}; } public stop() {} diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/filters.ts b/src/legacy/core_plugins/data/public/search/aggs/buckets/filters.ts deleted file mode 100644 index 2852f3e4bdf464..00000000000000 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/filters.ts +++ /dev/null @@ -1,116 +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 _ from 'lodash'; -import { i18n } from '@kbn/i18n'; - -import chrome from 'ui/chrome'; - -import { createFilterFilters } from './create_filter/filters'; -import { toAngularJSON } from '../utils'; -import { BucketAggType } from './_bucket_agg_type'; -import { BUCKET_TYPES } from './bucket_agg_types'; -import { Storage } from '../../../../../../../plugins/kibana_utils/public'; - -import { getQueryLog, esQuery, Query } from '../../../../../../../plugins/data/public'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getUiSettings } from '../../../../../../../plugins/data/public/services'; - -const config = chrome.getUiSettingsClient(); - -const filtersTitle = i18n.translate('data.search.aggs.buckets.filtersTitle', { - defaultMessage: 'Filters', - description: - 'The name of an aggregation, that allows to specify multiple individual filters to group data by.', -}); - -interface FilterValue { - input: Query; - label: string; - id: string; -} - -export const filtersBucketAgg = new BucketAggType({ - name: BUCKET_TYPES.FILTERS, - title: filtersTitle, - createFilter: createFilterFilters, - customLabels: false, - params: [ - { - name: 'filters', - // TODO need to get rid of reference to `config` below - default: [{ input: { query: '', language: config.get('search:queryLanguage') }, label: '' }], - write(aggConfig, output) { - const uiSettings = getUiSettings(); - const inFilters: FilterValue[] = aggConfig.params.filters; - if (!_.size(inFilters)) return; - - inFilters.forEach(filter => { - const persistedLog = getQueryLog( - uiSettings, - new Storage(window.localStorage), - 'vis_default_editor', - filter.input.language - ); - persistedLog.add(filter.input.query); - }); - - const outFilters = _.transform( - inFilters, - function(filters, filter) { - const input = _.cloneDeep(filter.input); - - if (!input) { - console.log('malformed filter agg params, missing "input" query'); // eslint-disable-line no-console - return; - } - - const esQueryConfigs = esQuery.getEsQueryConfig(uiSettings); - const query = esQuery.buildEsQuery( - aggConfig.getIndexPattern(), - [input], - [], - esQueryConfigs - ); - - if (!query) { - console.log('malformed filter agg params, missing "query" on input'); // eslint-disable-line no-console - return; - } - - const matchAllLabel = filter.input.query === '' ? '*' : ''; - const label = - filter.label || - matchAllLabel || - (typeof filter.input.query === 'string' - ? filter.input.query - : toAngularJSON(filter.input.query)); - filters[label] = { query }; - }, - {} - ); - - if (!_.size(outFilters)) return; - - const params = output.params || (output.params = {}); - params.filters = outFilters; - }, - }, - ], -}); diff --git a/src/legacy/core_plugins/data/public/search/aggs/index.ts b/src/legacy/core_plugins/data/public/search/aggs/index.ts deleted file mode 100644 index 75d632a0f931f2..00000000000000 --- a/src/legacy/core_plugins/data/public/search/aggs/index.ts +++ /dev/null @@ -1,61 +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. - */ - -export { - AggTypesRegistry, - AggTypesRegistrySetup, - AggTypesRegistryStart, -} from './agg_types_registry'; -export { AggType } from './agg_type'; -export { aggTypes } from './agg_types'; -export { AggConfig } from './agg_config'; -export { AggConfigs } from './agg_configs'; -export { FieldParamType } from './param_types'; -export { getCalculateAutoTimeExpression } from './buckets/lib/date_utils'; -export { MetricAggType } from './metrics/metric_agg_type'; -export { AggTypeFilters } from './filter'; -export { aggTypeFieldFilters, AggTypeFieldFilters } from './param_types/filter'; -export { - parentPipelineAggHelper, - parentPipelineType, -} from './metrics/lib/parent_pipeline_agg_helper'; -export { - siblingPipelineAggHelper, - siblingPipelineType, -} from './metrics/lib/sibling_pipeline_agg_helper'; - -// static code -export { AggParamType } from './param_types/agg'; -export { AggGroupNames, aggGroupNamesMap } from './agg_groups'; -export { intervalOptions } from './buckets/_interval_options'; // only used in Discover -export { isDateHistogramBucketAggConfig } from './buckets/date_histogram'; -export { termsAggFilter } from './buckets/terms'; -export { isType, isStringType } from './buckets/migrate_include_exclude_format'; -export { CidrMask } from './buckets/lib/cidr_mask'; -export { convertDateRangeToString } from './buckets/date_range'; -export { toAbsoluteDates } from './buckets/lib/date_utils'; -export { convertIPRangeToString } from './buckets/ip_range'; -export { aggTypeFilters, propFilter } from './filter'; -export { OptionedParamType } from './param_types/optioned'; -export { isValidInterval } from './utils'; -export { BUCKET_TYPES } from './buckets/bucket_agg_types'; -export { METRIC_TYPES } from './metrics/metric_agg_types'; - -// types -export { CreateAggConfigParams, IAggConfig, IAggConfigs } from './types'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/types.ts b/src/legacy/core_plugins/data/public/search/aggs/types.ts deleted file mode 100644 index 069a933fd994a6..00000000000000 --- a/src/legacy/core_plugins/data/public/search/aggs/types.ts +++ /dev/null @@ -1,28 +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. - */ - -export { IAggConfig } from './agg_config'; -export { CreateAggConfigParams, IAggConfigs } from './agg_configs'; -export { IAggType } from './agg_type'; -export { AggParam, AggParamOption } from './agg_params'; -export { IFieldParamType } from './param_types'; -export { IMetricAggType } from './metrics/metric_agg_type'; -export { DateRangeKey } from './buckets/date_range'; -export { IpRangeKey } from './buckets/ip_range'; -export { OptionedValueProp, OptionedParamEditorProps } from './param_types/optioned'; diff --git a/src/legacy/core_plugins/data/public/search/index.ts b/src/legacy/core_plugins/data/public/search/index.ts deleted file mode 100644 index 96d2825559da26..00000000000000 --- a/src/legacy/core_plugins/data/public/search/index.ts +++ /dev/null @@ -1,23 +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. - */ - -export * from './aggs'; -export { getRequestInspectorStats, getResponseInspectorStats } from './utils'; -export { serializeAggConfig } from './expressions/utils'; -export { tabifyAggResponse, tabifyGetColumns } from './tabify'; diff --git a/src/legacy/core_plugins/data/public/search/search_service.ts b/src/legacy/core_plugins/data/public/search/search_service.ts deleted file mode 100644 index 2d01ac446d9513..00000000000000 --- a/src/legacy/core_plugins/data/public/search/search_service.ts +++ /dev/null @@ -1,120 +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 { CoreSetup, CoreStart } from '../../../../../core/public'; -import { IndexPattern } from '../../../../../plugins/data/public'; -import { - aggTypes, - AggType, - AggTypesRegistry, - AggTypesRegistrySetup, - AggTypesRegistryStart, - AggConfig, - AggConfigs, - CreateAggConfigParams, - FieldParamType, - getCalculateAutoTimeExpression, - MetricAggType, - aggTypeFieldFilters, - parentPipelineAggHelper, - siblingPipelineAggHelper, -} from './aggs'; - -interface AggsSetup { - calculateAutoTimeExpression: ReturnType; - types: AggTypesRegistrySetup; -} - -interface AggsStartLegacy { - AggConfig: typeof AggConfig; - AggType: typeof AggType; - aggTypeFieldFilters: typeof aggTypeFieldFilters; - FieldParamType: typeof FieldParamType; - MetricAggType: typeof MetricAggType; - parentPipelineAggHelper: typeof parentPipelineAggHelper; - siblingPipelineAggHelper: typeof siblingPipelineAggHelper; -} - -interface AggsStart { - calculateAutoTimeExpression: ReturnType; - createAggConfigs: ( - indexPattern: IndexPattern, - configStates?: CreateAggConfigParams[], - schemas?: Record - ) => InstanceType; - types: AggTypesRegistryStart; - __LEGACY: AggsStartLegacy; -} - -export interface SearchSetup { - aggs: AggsSetup; -} - -export interface SearchStart { - aggs: AggsStart; -} - -/** - * The contract provided here is a new platform shim for ui/agg_types. - * - * Once it has been refactored to work with new platform services, - * it will move into the existing search service in src/plugins/data/public/search - */ -export class SearchService { - private readonly aggTypesRegistry = new AggTypesRegistry(); - - public setup(core: CoreSetup): SearchSetup { - const aggTypesSetup = this.aggTypesRegistry.setup(); - aggTypes.buckets.forEach(b => aggTypesSetup.registerBucket(b)); - aggTypes.metrics.forEach(m => aggTypesSetup.registerMetric(m)); - - return { - aggs: { - calculateAutoTimeExpression: getCalculateAutoTimeExpression(core.uiSettings), - types: aggTypesSetup, - }, - }; - } - - public start(core: CoreStart): SearchStart { - const aggTypesStart = this.aggTypesRegistry.start(); - return { - aggs: { - calculateAutoTimeExpression: getCalculateAutoTimeExpression(core.uiSettings), - createAggConfigs: (indexPattern, configStates = [], schemas) => { - return new AggConfigs(indexPattern, configStates, { - typesRegistry: aggTypesStart, - }); - }, - types: aggTypesStart, - __LEGACY: { - AggConfig, // TODO make static - AggType, - aggTypeFieldFilters, - FieldParamType, - MetricAggType, - parentPipelineAggHelper, // TODO make static - siblingPipelineAggHelper, // TODO make static - }, - }, - }; - } - - public stop() {} -} diff --git a/src/legacy/core_plugins/input_control_vis/public/components/vis/range_control.tsx b/src/legacy/core_plugins/input_control_vis/public/components/vis/range_control.tsx index cd3982afd9afd5..0cd2a2b3319801 100644 --- a/src/legacy/core_plugins/input_control_vis/public/components/vis/range_control.tsx +++ b/src/legacy/core_plugins/input_control_vis/public/components/vis/range_control.tsx @@ -19,8 +19,7 @@ import _ from 'lodash'; import React, { PureComponent } from 'react'; - -import { ValidatedDualRange } from '../../legacy_imports'; +import { ValidatedDualRange } from '../../../../../../../src/plugins/kibana_react/public'; import { FormRow } from './form_row'; import { RangeControl as RangeControlClass } from '../../control/range_control_factory'; diff --git a/src/legacy/core_plugins/input_control_vis/public/legacy_imports.ts b/src/legacy/core_plugins/input_control_vis/public/legacy_imports.ts index b6c4eb28e974f2..8c58ac2386da43 100644 --- a/src/legacy/core_plugins/input_control_vis/public/legacy_imports.ts +++ b/src/legacy/core_plugins/input_control_vis/public/legacy_imports.ts @@ -22,7 +22,5 @@ import { SearchSource as SearchSourceClass, ISearchSource } from '../../../../pl export { SearchSourceFields } from '../../../../plugins/data/public'; -export { ValidatedDualRange } from 'ui/validated_range'; - export type SearchSource = Class; export const SearchSource = SearchSourceClass; diff --git a/src/legacy/core_plugins/kibana/index.js b/src/legacy/core_plugins/kibana/index.js index 092eed924f3306..1d772536fa1ea2 100644 --- a/src/legacy/core_plugins/kibana/index.js +++ b/src/legacy/core_plugins/kibana/index.js @@ -126,57 +126,6 @@ export default function(kibana) { ], savedObjectsManagement: { - 'index-pattern': { - icon: 'indexPatternApp', - defaultSearchField: 'title', - isImportableAndExportable: true, - getTitle(obj) { - return obj.attributes.title; - }, - getEditUrl(obj) { - return `/management/kibana/index_patterns/${encodeURIComponent(obj.id)}`; - }, - getInAppUrl(obj) { - return { - path: `/app/kibana#/management/kibana/index_patterns/${encodeURIComponent(obj.id)}`, - uiCapabilitiesPath: 'management.kibana.index_patterns', - }; - }, - }, - visualization: { - icon: 'visualizeApp', - defaultSearchField: 'title', - isImportableAndExportable: true, - getTitle(obj) { - return obj.attributes.title; - }, - getEditUrl(obj) { - return `/management/kibana/objects/savedVisualizations/${encodeURIComponent(obj.id)}`; - }, - getInAppUrl(obj) { - return { - path: `/app/kibana#/visualize/edit/${encodeURIComponent(obj.id)}`, - uiCapabilitiesPath: 'visualize.show', - }; - }, - }, - search: { - icon: 'discoverApp', - defaultSearchField: 'title', - isImportableAndExportable: true, - getTitle(obj) { - return obj.attributes.title; - }, - getEditUrl(obj) { - return `/management/kibana/objects/savedSearches/${encodeURIComponent(obj.id)}`; - }, - getInAppUrl(obj) { - return { - path: `/app/kibana#/discover/${encodeURIComponent(obj.id)}`, - uiCapabilitiesPath: 'discover.show', - }; - }, - }, dashboard: { icon: 'dashboardApp', defaultSearchField: 'title', diff --git a/src/legacy/core_plugins/kibana/mappings.json b/src/legacy/core_plugins/kibana/mappings.json index 4cf9ea1d301c09..af3f79588552b6 100644 --- a/src/legacy/core_plugins/kibana/mappings.json +++ b/src/legacy/core_plugins/kibana/mappings.json @@ -1,93 +1,4 @@ { - "index-pattern": { - "properties": { - "fieldFormatMap": { - "type": "text" - }, - "fields": { - "type": "text" - }, - "intervalName": { - "type": "keyword" - }, - "notExpandable": { - "type": "boolean" - }, - "sourceFilters": { - "type": "text" - }, - "timeFieldName": { - "type": "keyword" - }, - "title": { - "type": "text" - }, - "type": { - "type": "keyword" - }, - "typeMeta": { - "type": "keyword" - } - } - }, - "visualization": { - "properties": { - "description": { - "type": "text" - }, - "kibanaSavedObjectMeta": { - "properties": { - "searchSourceJSON": { - "type": "text" - } - } - }, - "savedSearchRefName": { - "type": "keyword" - }, - "title": { - "type": "text" - }, - "uiStateJSON": { - "type": "text" - }, - "version": { - "type": "integer" - }, - "visState": { - "type": "text" - } - } - }, - "search": { - "properties": { - "columns": { - "type": "keyword" - }, - "description": { - "type": "text" - }, - "hits": { - "type": "integer" - }, - "kibanaSavedObjectMeta": { - "properties": { - "searchSourceJSON": { - "type": "text" - } - } - }, - "sort": { - "type": "keyword" - }, - "title": { - "type": "text" - }, - "version": { - "type": "integer" - } - } - }, "dashboard": { "properties": { "description": { diff --git a/src/legacy/core_plugins/kibana/migrations/migrations.js b/src/legacy/core_plugins/kibana/migrations/migrations.js index 29b6e632d19fd1..d37887c640b90b 100644 --- a/src/legacy/core_plugins/kibana/migrations/migrations.js +++ b/src/legacy/core_plugins/kibana/migrations/migrations.js @@ -17,7 +17,7 @@ * under the License. */ -import { cloneDeep, get, omit, has, flow } from 'lodash'; +import { get } from 'lodash'; import { migrations730 as dashboardMigrations730 } from '../public/dashboard/migrations'; function migrateIndexPattern(doc) { @@ -58,559 +58,7 @@ function migrateIndexPattern(doc) { doc.attributes.kibanaSavedObjectMeta.searchSourceJSON = JSON.stringify(searchSource); } -// [TSVB] Migrate percentile-rank aggregation (value -> values) -const migratePercentileRankAggregation = 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 = get(visState, 'params.series') || []; - - series.forEach(part => { - (part.metrics || []).forEach(metric => { - if (metric.type === 'percentile_rank' && has(metric, 'value')) { - metric.values = [metric.value]; - - delete metric.value; - } - }); - }); - return { - ...doc, - attributes: { - ...doc.attributes, - visState: JSON.stringify(visState), - }, - }; - } - } - return doc; -}; - -// Migrate date histogram aggregation (remove customInterval) -const migrateDateHistogramAggregation = 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.aggs) { - visState.aggs.forEach(agg => { - if (agg.type === 'date_histogram' && agg.params) { - if (agg.params.interval === 'custom') { - agg.params.interval = agg.params.customInterval; - } - delete agg.params.customInterval; - } - - if ( - get(agg, 'params.customBucket.type', null) === 'date_histogram' && - agg.params.customBucket.params - ) { - if (agg.params.customBucket.params.interval === 'custom') { - agg.params.customBucket.params.interval = agg.params.customBucket.params.customInterval; - } - delete agg.params.customBucket.params.customInterval; - } - }); - return { - ...doc, - attributes: { - ...doc.attributes, - visState: JSON.stringify(visState), - }, - }; - } - } - return doc; -}; - -function removeDateHistogramTimeZones(doc) { - const visStateJSON = get(doc, 'attributes.visState'); - if (visStateJSON) { - let visState; - try { - visState = JSON.parse(visStateJSON); - } catch (e) { - // Let it go, the data is invalid and we'll leave it as is - } - if (visState && visState.aggs) { - visState.aggs.forEach(agg => { - // We're checking always for the existance of agg.params here. This should always exist, but better - // be safe then sorry during migrations. - if (agg.type === 'date_histogram' && agg.params) { - delete agg.params.time_zone; - } - - if ( - get(agg, 'params.customBucket.type', null) === 'date_histogram' && - agg.params.customBucket.params - ) { - delete agg.params.customBucket.params.time_zone; - } - }); - doc.attributes.visState = JSON.stringify(visState); - } - } - return doc; -} - -// migrate gauge verticalSplit to alignment -// https://github.com/elastic/kibana/issues/34636 -function migrateGaugeVerticalSplitToAlignment(doc, logger) { - const visStateJSON = get(doc, 'attributes.visState'); - - if (visStateJSON) { - try { - const visState = JSON.parse(visStateJSON); - if (visState && visState.type === 'gauge' && !visState.params.gauge.alignment) { - visState.params.gauge.alignment = visState.params.gauge.verticalSplit - ? 'vertical' - : 'horizontal'; - delete visState.params.gauge.verticalSplit; - return { - ...doc, - attributes: { - ...doc.attributes, - visState: JSON.stringify(visState), - }, - }; - } - } catch (e) { - logger.warning(`Exception @ migrateGaugeVerticalSplitToAlignment! ${e}`); - logger.warning(`Exception @ migrateGaugeVerticalSplitToAlignment! Payload: ${visStateJSON}`); - } - } - return doc; -} -// Migrate filters (string -> { query: string, language: lucene }) -/* - Enabling KQL in TSVB causes problems with savedObject visualizations when these are saved with filters. - In a visualisation type of saved object, if the visState param is of type metric, the filter is saved as a string that is not interpretted correctly as a lucene query in the visualization itself. - We need to transform the filter string into an object containing the original string as a query and specify the query language as lucene. - For Metrics visualizations (param.type === "metric"), filters can be applied to each series object in the series array within the SavedObject.visState.params object. - Path to the series array is thus: - attributes.visState. -*/ -function transformFilterStringToQueryObject(doc) { - // Migrate filters - // If any filters exist and they are a string, we assume it to be lucene and transform the filter into an object accordingly - const newDoc = cloneDeep(doc); - const visStateJSON = get(doc, 'attributes.visState'); - if (visStateJSON) { - let visState; - try { - visState = JSON.parse(visStateJSON); - } catch (e) { - // let it go, the data is invalid and we'll leave it as is - } - if (visState) { - const visType = get(visState, 'params.type'); - const tsvbTypes = ['metric', 'markdown', 'top_n', 'gauge', 'table', 'timeseries']; - if (tsvbTypes.indexOf(visType) === -1) { - // skip - return doc; - } - // migrate the params fitler - const params = get(visState, 'params'); - if (params.filter && typeof params.filter === 'string') { - const paramsFilterObject = { - query: params.filter, - language: 'lucene', - }; - params.filter = paramsFilterObject; - } - - // migrate the annotations query string: - const annotations = get(visState, 'params.annotations') || []; - annotations.forEach(item => { - if (!item.query_string) { - // we don't need to transform anything if there isn't a filter at all - return; - } - if (typeof item.query_string === 'string') { - const itemQueryStringObject = { - query: item.query_string, - language: 'lucene', - }; - item.query_string = itemQueryStringObject; - } - }); - // migrate the series filters - const series = get(visState, 'params.series') || []; - series.forEach(item => { - if (!item.filter) { - // we don't need to transform anything if there isn't a filter at all - return; - } - // series item filter - if (typeof item.filter === 'string') { - const itemfilterObject = { - query: item.filter, - language: 'lucene', - }; - item.filter = itemfilterObject; - } - // series item split filters filter - if (item.split_filters) { - const splitFilters = get(item, 'split_filters') || []; - splitFilters.forEach(filter => { - if (!filter.filter) { - // we don't need to transform anything if there isn't a filter at all - return; - } - if (typeof filter.filter === 'string') { - const filterfilterObject = { - query: filter.filter, - language: 'lucene', - }; - filter.filter = filterfilterObject; - } - }); - } - }); - newDoc.attributes.visState = JSON.stringify(visState); - } - } - return newDoc; -} -function transformSplitFiltersStringToQueryObject(doc) { - // Migrate split_filters in TSVB objects that weren't migrated in 7.3 - // If any filters exist and they are a string, we assume them to be lucene syntax and transform the filter into an object accordingly - const newDoc = cloneDeep(doc); - const visStateJSON = get(doc, 'attributes.visState'); - if (visStateJSON) { - let visState; - try { - visState = JSON.parse(visStateJSON); - } catch (e) { - // let it go, the data is invalid and we'll leave it as is - } - if (visState) { - const visType = get(visState, 'params.type'); - const tsvbTypes = ['metric', 'markdown', 'top_n', 'gauge', 'table', 'timeseries']; - if (tsvbTypes.indexOf(visType) === -1) { - // skip - return doc; - } - // migrate the series split_filter filters - const series = get(visState, 'params.series') || []; - series.forEach(item => { - // series item split filters filter - if (item.split_filters) { - const splitFilters = get(item, 'split_filters') || []; - if (splitFilters.length > 0) { - // only transform split_filter filters if we have filters - splitFilters.forEach(filter => { - if (typeof filter.filter === 'string') { - const filterfilterObject = { - query: filter.filter, - language: 'lucene', - }; - filter.filter = filterfilterObject; - } - }); - } - } - }); - newDoc.attributes.visState = JSON.stringify(visState); - } - } - return newDoc; -} - -function migrateFiltersAggQuery(doc) { - const visStateJSON = get(doc, 'attributes.visState'); - - if (visStateJSON) { - try { - const visState = JSON.parse(visStateJSON); - if (visState && visState.aggs) { - visState.aggs.forEach(agg => { - if (agg.type !== 'filters') return; - - agg.params.filters.forEach(filter => { - if (filter.input.language) return filter; - filter.input.language = 'lucene'; - }); - }); - - return { - ...doc, - attributes: { - ...doc.attributes, - visState: JSON.stringify(visState), - }, - }; - } - } catch (e) { - // Let it go, the data is invalid and we'll leave it as is - } - } - return doc; -} - -function replaceMovAvgToMovFn(doc, logger) { - const visStateJSON = get(doc, 'attributes.visState'); - let visState; - - if (visStateJSON) { - try { - visState = JSON.parse(visStateJSON); - - if (visState && visState.type === 'metrics') { - const series = get(visState, 'params.series', []); - - series.forEach(part => { - if (part.metrics && Array.isArray(part.metrics)) { - part.metrics.forEach(metric => { - if (metric.type === 'moving_average') { - metric.model_type = metric.model; - metric.alpha = get(metric, 'settings.alpha', 0.3); - metric.beta = get(metric, 'settings.beta', 0.1); - metric.gamma = get(metric, 'settings.gamma', 0.3); - metric.period = get(metric, 'settings.period', 1); - metric.multiplicative = get(metric, 'settings.type') === 'mult'; - - delete metric.minimize; - delete metric.model; - delete metric.settings; - delete metric.predict; - } - }); - } - }); - - return { - ...doc, - attributes: { - ...doc.attributes, - visState: JSON.stringify(visState), - }, - }; - } - } catch (e) { - logger.warning(`Exception @ replaceMovAvgToMovFn! ${e}`); - logger.warning(`Exception @ replaceMovAvgToMovFn! Payload: ${visStateJSON}`); - } - } - - return doc; -} - -function migrateSearchSortToNestedArray(doc) { - const sort = get(doc, 'attributes.sort'); - if (!sort) return doc; - - // Don't do anything if we already have a two dimensional array - if (Array.isArray(sort) && sort.length > 0 && Array.isArray(sort[0])) { - return doc; - } - - return { - ...doc, - attributes: { - ...doc.attributes, - sort: [doc.attributes.sort], - }, - }; -} - -function migrateFiltersAggQueryStringQueries(doc) { - const visStateJSON = get(doc, 'attributes.visState'); - - if (visStateJSON) { - try { - const visState = JSON.parse(visStateJSON); - if (visState && visState.aggs) { - visState.aggs.forEach(agg => { - if (agg.type !== 'filters') return doc; - - agg.params.filters.forEach(filter => { - if (filter.input.query.query_string) { - filter.input.query = filter.input.query.query_string.query; - } - }); - }); - - return { - ...doc, - attributes: { - ...doc.attributes, - visState: JSON.stringify(visState), - }, - }; - } - } catch (e) { - // Let it go, the data is invalid and we'll leave it as is - } - } - return doc; -} - -function migrateSubTypeAndParentFieldProperties(doc) { - if (!doc.attributes.fields) return doc; - - const fieldsString = doc.attributes.fields; - const fields = JSON.parse(fieldsString); - const migratedFields = fields.map(field => { - if (field.subType === 'multi') { - return { - ...omit(field, 'parent'), - subType: { multi: { parent: field.parent } }, - }; - } - - return field; - }); - - return { - ...doc, - attributes: { - ...doc.attributes, - fields: JSON.stringify(migratedFields), - }, - }; -} - -const executeMigrations720 = flow( - migratePercentileRankAggregation, - migrateDateHistogramAggregation -); -const executeMigrations730 = flow( - migrateGaugeVerticalSplitToAlignment, - transformFilterStringToQueryObject, - migrateFiltersAggQuery, - replaceMovAvgToMovFn -); - -const executeVisualizationMigrations731 = flow(migrateFiltersAggQueryStringQueries); - -const executeSearchMigrations740 = flow(migrateSearchSortToNestedArray); - -const executeMigrations742 = flow(transformSplitFiltersStringToQueryObject); - export const migrations = { - 'index-pattern': { - '6.5.0': doc => { - doc.attributes.type = doc.attributes.type || undefined; - doc.attributes.typeMeta = doc.attributes.typeMeta || undefined; - return doc; - }, - '7.6.0': flow(migrateSubTypeAndParentFieldProperties), - }, - visualization: { - /** - * We need to have this migration twice, once with a version prior to 7.0.0 once with a version - * after it. The reason for that is, that this migration has been introduced once 7.0.0 was already - * released. Thus a user who already had 7.0.0 installed already got the 7.0.0 migrations below running, - * so we need a version higher than that. But this fix was backported to the 6.7 release, meaning if we - * would only have the 7.0.1 migration in here a user on the 6.7 release will migrate their saved objects - * to the 7.0.1 state, and thus when updating their Kibana to 7.0, will never run the 7.0.0 migrations introduced - * in that version. So we apply this twice, once with 6.7.2 and once with 7.0.1 while the backport to 6.7 - * only contained the 6.7.2 migration and not the 7.0.1 migration. - */ - '6.7.2': removeDateHistogramTimeZones, - '7.0.0': doc => { - // Set new "references" attribute - doc.references = doc.references || []; - - // Migrate index pattern - migrateIndexPattern(doc); - - // Migrate saved search - const savedSearchId = get(doc, 'attributes.savedSearchId'); - if (savedSearchId) { - doc.references.push({ - type: 'search', - name: 'search_0', - id: savedSearchId, - }); - doc.attributes.savedSearchRefName = 'search_0'; - } - delete doc.attributes.savedSearchId; - - // Migrate controls - const visStateJSON = get(doc, 'attributes.visState'); - if (visStateJSON) { - let visState; - try { - visState = JSON.parse(visStateJSON); - } catch (e) { - // Let it go, the data is invalid and we'll leave it as is - } - if (visState) { - const controls = get(visState, 'params.controls') || []; - controls.forEach((control, i) => { - if (!control.indexPattern) { - return; - } - control.indexPatternRefName = `control_${i}_index_pattern`; - doc.references.push({ - name: control.indexPatternRefName, - type: 'index-pattern', - id: control.indexPattern, - }); - delete control.indexPattern; - }); - doc.attributes.visState = JSON.stringify(visState); - } - } - - // Migrate table splits - try { - const visState = JSON.parse(doc.attributes.visState); - if (get(visState, 'type') !== 'table') { - return doc; // do nothing; we only want to touch tables - } - - let splitCount = 0; - visState.aggs = visState.aggs.map(agg => { - if (agg.schema !== 'split') { - return agg; - } - - splitCount++; - if (splitCount === 1) { - return agg; // leave the first split agg unchanged - } - agg.schema = 'bucket'; - // the `row` param is exclusively used by split aggs, so we remove it - agg.params = omit(agg.params, ['row']); - return agg; - }); - - if (splitCount <= 1) { - return doc; // do nothing; we only want to touch tables with multiple split aggs - } - - const newDoc = cloneDeep(doc); - newDoc.attributes.visState = JSON.stringify(visState); - return newDoc; - } catch (e) { - throw new Error( - `Failure attempting to migrate saved object '${doc.attributes.title}' - ${e}` - ); - } - }, - '7.0.1': removeDateHistogramTimeZones, - '7.2.0': doc => executeMigrations720(doc), - '7.3.0': executeMigrations730, - '7.3.1': executeVisualizationMigrations731, - // migrate split_filters that were not migrated in 7.3.0 (transformFilterStringToQueryObject). - '7.4.2': executeMigrations742, - }, dashboard: { '7.0.0': doc => { // Set new "references" attribute @@ -651,14 +99,4 @@ export const migrations = { }, '7.3.0': dashboardMigrations730, }, - search: { - '7.0.0': doc => { - // Set new "references" attribute - doc.references = doc.references || []; - // Migrate index pattern - migrateIndexPattern(doc); - return doc; - }, - '7.4.0': executeSearchMigrations740, - }, }; diff --git a/src/legacy/core_plugins/kibana/migrations/migrations.test.js b/src/legacy/core_plugins/kibana/migrations/migrations.test.js index e39bc59201e7fd..b02081128c8585 100644 --- a/src/legacy/core_plugins/kibana/migrations/migrations.test.js +++ b/src/legacy/core_plugins/kibana/migrations/migrations.test.js @@ -19,1312 +19,6 @@ import { migrations } from './migrations'; -describe('index-pattern', () => { - describe('6.5.0', () => { - const migrate = doc => migrations['index-pattern']['6.5.0'](doc); - - it('adds "type" and "typeMeta" properties to object when not declared', () => { - expect( - migrate({ - attributes: {}, - }) - ).toMatchInlineSnapshot(` -Object { - "attributes": Object { - "type": undefined, - "typeMeta": undefined, - }, -} -`); - }); - - it('keeps "type" and "typeMeta" properties as is when declared', () => { - expect( - migrate({ - attributes: { - type: '123', - typeMeta: '123', - }, - }) - ).toMatchInlineSnapshot(` -Object { - "attributes": Object { - "type": "123", - "typeMeta": "123", - }, -} -`); - }); - }); - - describe('7.6.0', function() { - const migrate = doc => migrations['index-pattern']['7.6.0'](doc); - - it('should remove the parent property and update the subType prop on every field that has them', () => { - const input = { - attributes: { - title: 'test', - fields: - '[{"name":"customer_name","type":"string","esTypes":["text"],"count":0,"scripted":false,"searchable":true,"aggregatable":false,"readFromDocValues":false},{"name":"customer_name.keyword","type":"string","esTypes":["keyword"],"count":0,"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true,"subType":"multi","parent":"customer_name"}]', - }, - }; - const expected = { - attributes: { - title: 'test', - fields: - '[{"name":"customer_name","type":"string","esTypes":["text"],"count":0,"scripted":false,"searchable":true,"aggregatable":false,"readFromDocValues":false},{"name":"customer_name.keyword","type":"string","esTypes":["keyword"],"count":0,"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true,"subType":{"multi":{"parent":"customer_name"}}}]', - }, - }; - - expect(migrate(input)).toEqual(expected); - }); - }); -}); - -describe('visualization', () => { - describe('date histogram time zone removal', () => { - const migrate = doc => migrations.visualization['6.7.2'](doc); - let doc; - beforeEach(() => { - doc = { - attributes: { - visState: JSON.stringify({ - aggs: [ - { - enabled: true, - id: '1', - params: { - // Doesn't make much sense but we want to test it's not removing it from anything else - time_zone: 'Europe/Berlin', - }, - schema: 'metric', - type: 'count', - }, - { - enabled: true, - id: '2', - params: { - customInterval: '2h', - drop_partials: false, - extended_bounds: {}, - field: 'timestamp', - time_zone: 'Europe/Berlin', - interval: 'auto', - min_doc_count: 1, - useNormalizedEsInterval: true, - }, - schema: 'segment', - type: 'date_histogram', - }, - { - enabled: true, - id: '4', - params: { - customInterval: '2h', - drop_partials: false, - extended_bounds: {}, - field: 'timestamp', - interval: 'auto', - min_doc_count: 1, - useNormalizedEsInterval: true, - }, - schema: 'segment', - type: 'date_histogram', - }, - { - enabled: true, - id: '3', - params: { - customBucket: { - enabled: true, - id: '1-bucket', - params: { - customInterval: '2h', - drop_partials: false, - extended_bounds: {}, - field: 'timestamp', - interval: 'auto', - min_doc_count: 1, - time_zone: 'Europe/Berlin', - useNormalizedEsInterval: true, - }, - type: 'date_histogram', - }, - customMetric: { - enabled: true, - id: '1-metric', - params: {}, - type: 'count', - }, - }, - schema: 'metric', - type: 'max_bucket', - }, - ], - }), - }, - }; - }); - - it('should remove time_zone from date_histogram aggregations', () => { - const migratedDoc = migrate(doc); - const aggs = JSON.parse(migratedDoc.attributes.visState).aggs; - expect(aggs[1]).not.toHaveProperty('params.time_zone'); - }); - - it('should not remove time_zone from non date_histogram aggregations', () => { - const migratedDoc = migrate(doc); - const aggs = JSON.parse(migratedDoc.attributes.visState).aggs; - expect(aggs[0]).toHaveProperty('params.time_zone'); - }); - - it('should remove time_zone from nested aggregations', () => { - const migratedDoc = migrate(doc); - const aggs = JSON.parse(migratedDoc.attributes.visState).aggs; - expect(aggs[3]).not.toHaveProperty('params.customBucket.params.time_zone'); - }); - - it('should not fail on date histograms without a time_zone', () => { - const migratedDoc = migrate(doc); - const aggs = JSON.parse(migratedDoc.attributes.visState).aggs; - expect(aggs[2]).not.toHaveProperty('params.time_zone'); - }); - - it('should be able to apply the migration twice, since we need it for 6.7.2 and 7.0.1', () => { - const migratedDoc = migrate(migrate(doc)); - const aggs = JSON.parse(migratedDoc.attributes.visState).aggs; - expect(aggs[1]).not.toHaveProperty('params.time_zone'); - expect(aggs[0]).toHaveProperty('params.time_zone'); - expect(aggs[3]).not.toHaveProperty('params.customBucket.params.time_zone'); - expect(aggs[2]).not.toHaveProperty('params.time_zone'); - }); - }); - - describe('7.0.0', () => { - const migrate = doc => migrations.visualization['7.0.0'](doc); - const generateDoc = ({ type, aggs }) => ({ - attributes: { - title: 'My Vis', - description: 'This is my super cool vis.', - visState: JSON.stringify({ type, aggs }), - uiStateJSON: '{}', - version: 1, - kibanaSavedObjectMeta: { - searchSourceJSON: '{}', - }, - }, - }); - - it('does not throw error on empty object', () => { - const migratedDoc = migrate({ - attributes: { - visState: '{}', - }, - }); - expect(migratedDoc).toMatchInlineSnapshot(` -Object { - "attributes": Object { - "visState": "{}", - }, - "references": Array [], -} -`); - }); - - it('skips errors when searchSourceJSON is null', () => { - const doc = { - id: '1', - type: 'visualization', - attributes: { - visState: '{}', - kibanaSavedObjectMeta: { - searchSourceJSON: null, - }, - savedSearchId: '123', - }, - }; - const migratedDoc = migrate(doc); - expect(migratedDoc).toMatchInlineSnapshot(` -Object { - "attributes": Object { - "kibanaSavedObjectMeta": Object { - "searchSourceJSON": null, - }, - "savedSearchRefName": "search_0", - "visState": "{}", - }, - "id": "1", - "references": Array [ - Object { - "id": "123", - "name": "search_0", - "type": "search", - }, - ], - "type": "visualization", -} -`); - }); - - it('skips errors when searchSourceJSON is undefined', () => { - const doc = { - id: '1', - type: 'visualization', - attributes: { - visState: '{}', - kibanaSavedObjectMeta: { - searchSourceJSON: undefined, - }, - savedSearchId: '123', - }, - }; - const migratedDoc = migrate(doc); - expect(migratedDoc).toMatchInlineSnapshot(` -Object { - "attributes": Object { - "kibanaSavedObjectMeta": Object { - "searchSourceJSON": undefined, - }, - "savedSearchRefName": "search_0", - "visState": "{}", - }, - "id": "1", - "references": Array [ - Object { - "id": "123", - "name": "search_0", - "type": "search", - }, - ], - "type": "visualization", -} -`); - }); - - it('skips error when searchSourceJSON is not a string', () => { - const doc = { - id: '1', - type: 'visualization', - attributes: { - visState: '{}', - kibanaSavedObjectMeta: { - searchSourceJSON: 123, - }, - savedSearchId: '123', - }, - }; - expect(migrate(doc)).toMatchInlineSnapshot(` -Object { - "attributes": Object { - "kibanaSavedObjectMeta": Object { - "searchSourceJSON": 123, - }, - "savedSearchRefName": "search_0", - "visState": "{}", - }, - "id": "1", - "references": Array [ - Object { - "id": "123", - "name": "search_0", - "type": "search", - }, - ], - "type": "visualization", -} -`); - }); - - it('skips error when searchSourceJSON is invalid json', () => { - const doc = { - id: '1', - type: 'visualization', - attributes: { - visState: '{}', - kibanaSavedObjectMeta: { - searchSourceJSON: '{abc123}', - }, - savedSearchId: '123', - }, - }; - expect(migrate(doc)).toMatchInlineSnapshot(` -Object { - "attributes": Object { - "kibanaSavedObjectMeta": Object { - "searchSourceJSON": "{abc123}", - }, - "savedSearchRefName": "search_0", - "visState": "{}", - }, - "id": "1", - "references": Array [ - Object { - "id": "123", - "name": "search_0", - "type": "search", - }, - ], - "type": "visualization", -} -`); - }); - - it('skips error when "index" and "filter" is missing from searchSourceJSON', () => { - const doc = { - id: '1', - type: 'visualization', - attributes: { - visState: '{}', - kibanaSavedObjectMeta: { - searchSourceJSON: JSON.stringify({ bar: true }), - }, - savedSearchId: '123', - }, - }; - const migratedDoc = migrate(doc); - expect(migratedDoc).toMatchInlineSnapshot(` -Object { - "attributes": Object { - "kibanaSavedObjectMeta": Object { - "searchSourceJSON": "{\\"bar\\":true}", - }, - "savedSearchRefName": "search_0", - "visState": "{}", - }, - "id": "1", - "references": Array [ - Object { - "id": "123", - "name": "search_0", - "type": "search", - }, - ], - "type": "visualization", -} -`); - }); - - it('extracts "index" attribute from doc', () => { - const doc = { - id: '1', - type: 'visualization', - attributes: { - visState: '{}', - kibanaSavedObjectMeta: { - searchSourceJSON: JSON.stringify({ bar: true, index: 'pattern*' }), - }, - savedSearchId: '123', - }, - }; - const migratedDoc = migrate(doc); - expect(migratedDoc).toMatchInlineSnapshot(` -Object { - "attributes": Object { - "kibanaSavedObjectMeta": Object { - "searchSourceJSON": "{\\"bar\\":true,\\"indexRefName\\":\\"kibanaSavedObjectMeta.searchSourceJSON.index\\"}", - }, - "savedSearchRefName": "search_0", - "visState": "{}", - }, - "id": "1", - "references": Array [ - Object { - "id": "pattern*", - "name": "kibanaSavedObjectMeta.searchSourceJSON.index", - "type": "index-pattern", - }, - Object { - "id": "123", - "name": "search_0", - "type": "search", - }, - ], - "type": "visualization", -} -`); - }); - - it('extracts index patterns from the filter', () => { - const doc = { - id: '1', - type: 'visualization', - attributes: { - visState: '{}', - kibanaSavedObjectMeta: { - searchSourceJSON: JSON.stringify({ - bar: true, - filter: [ - { - meta: { index: 'my-index', foo: true }, - }, - ], - }), - }, - savedSearchId: '123', - }, - }; - const migratedDoc = migrate(doc); - - expect(migratedDoc).toMatchInlineSnapshot(` -Object { - "attributes": Object { - "kibanaSavedObjectMeta": Object { - "searchSourceJSON": "{\\"bar\\":true,\\"filter\\":[{\\"meta\\":{\\"foo\\":true,\\"indexRefName\\":\\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\\"}}]}", - }, - "savedSearchRefName": "search_0", - "visState": "{}", - }, - "id": "1", - "references": Array [ - Object { - "id": "my-index", - "name": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index", - "type": "index-pattern", - }, - Object { - "id": "123", - "name": "search_0", - "type": "search", - }, - ], - "type": "visualization", -} -`); - }); - - it('extracts index patterns from controls', () => { - const doc = { - id: '1', - type: 'visualization', - attributes: { - foo: true, - visState: JSON.stringify({ - bar: false, - params: { - controls: [ - { - bar: true, - indexPattern: 'pattern*', - }, - { - foo: true, - }, - ], - }, - }), - }, - }; - const migratedDoc = migrate(doc); - - expect(migratedDoc).toMatchInlineSnapshot(` -Object { - "attributes": Object { - "foo": true, - "visState": "{\\"bar\\":false,\\"params\\":{\\"controls\\":[{\\"bar\\":true,\\"indexPatternRefName\\":\\"control_0_index_pattern\\"},{\\"foo\\":true}]}}", - }, - "id": "1", - "references": Array [ - Object { - "id": "pattern*", - "name": "control_0_index_pattern", - "type": "index-pattern", - }, - ], - "type": "visualization", -} -`); - }); - - it('skips extracting savedSearchId when missing', () => { - const doc = { - id: '1', - attributes: { - visState: '{}', - kibanaSavedObjectMeta: { - searchSourceJSON: '{}', - }, - }, - }; - const migratedDoc = migrate(doc); - expect(migratedDoc).toMatchInlineSnapshot(` -Object { - "attributes": Object { - "kibanaSavedObjectMeta": Object { - "searchSourceJSON": "{}", - }, - "visState": "{}", - }, - "id": "1", - "references": Array [], -} -`); - }); - - it('extract savedSearchId from doc', () => { - const doc = { - id: '1', - attributes: { - visState: '{}', - kibanaSavedObjectMeta: { - searchSourceJSON: '{}', - }, - savedSearchId: '123', - }, - }; - const migratedDoc = migrate(doc); - expect(migratedDoc).toMatchInlineSnapshot(` -Object { - "attributes": Object { - "kibanaSavedObjectMeta": Object { - "searchSourceJSON": "{}", - }, - "savedSearchRefName": "search_0", - "visState": "{}", - }, - "id": "1", - "references": Array [ - Object { - "id": "123", - "name": "search_0", - "type": "search", - }, - ], -} -`); - }); - - it('delete savedSearchId when empty string in doc', () => { - const doc = { - id: '1', - attributes: { - visState: '{}', - kibanaSavedObjectMeta: { - searchSourceJSON: '{}', - }, - savedSearchId: '', - }, - }; - const migratedDoc = migrate(doc); - expect(migratedDoc).toMatchInlineSnapshot(` -Object { - "attributes": Object { - "kibanaSavedObjectMeta": Object { - "searchSourceJSON": "{}", - }, - "visState": "{}", - }, - "id": "1", - "references": Array [], -} -`); - }); - - it('should return a new object if vis is table and has multiple split aggs', () => { - const aggs = [ - { - id: '1', - schema: 'metric', - params: {}, - }, - { - id: '2', - schema: 'split', - params: { foo: 'bar', row: true }, - }, - { - id: '3', - schema: 'split', - params: { hey: 'ya', row: false }, - }, - ]; - const tableDoc = generateDoc({ type: 'table', aggs }); - const expected = tableDoc; - const actual = migrate(tableDoc); - expect(actual).not.toBe(expected); - }); - - it('should not touch any vis that is not table', () => { - const aggs = []; - const pieDoc = generateDoc({ type: 'pie', aggs }); - const expected = pieDoc; - const actual = migrate(pieDoc); - expect(actual).toBe(expected); - }); - - it('should not change values in any vis that is not table', () => { - const aggs = [ - { - id: '1', - schema: 'metric', - params: {}, - }, - { - id: '2', - schema: 'split', - params: { foo: 'bar', row: true }, - }, - { - id: '3', - schema: 'segment', - params: { hey: 'ya' }, - }, - ]; - const pieDoc = generateDoc({ type: 'pie', aggs }); - const expected = pieDoc; - const actual = migrate(pieDoc); - expect(actual).toEqual(expected); - }); - - it('should not touch table vis if there are not multiple split aggs', () => { - const aggs = [ - { - id: '1', - schema: 'metric', - params: {}, - }, - { - id: '2', - schema: 'split', - params: { foo: 'bar', row: true }, - }, - ]; - const tableDoc = generateDoc({ type: 'table', aggs }); - const expected = tableDoc; - const actual = migrate(tableDoc); - expect(actual).toBe(expected); - }); - - it('should change all split aggs to `bucket` except the first', () => { - const aggs = [ - { - id: '1', - schema: 'metric', - params: {}, - }, - { - id: '2', - schema: 'split', - params: { foo: 'bar', row: true }, - }, - { - id: '3', - schema: 'split', - params: { hey: 'ya', row: false }, - }, - { - id: '4', - schema: 'bucket', - params: { heyyy: 'yaaa' }, - }, - ]; - const expected = ['metric', 'split', 'bucket', 'bucket']; - const migrated = migrate(generateDoc({ type: 'table', aggs })); - const actual = JSON.parse(migrated.attributes.visState); - expect(actual.aggs.map(agg => agg.schema)).toEqual(expected); - }); - - it('should remove `rows` param from any aggs that are not `split`', () => { - const aggs = [ - { - id: '1', - schema: 'metric', - params: {}, - }, - { - id: '2', - schema: 'split', - params: { foo: 'bar', row: true }, - }, - { - id: '3', - schema: 'split', - params: { hey: 'ya', row: false }, - }, - ]; - const expected = [{}, { foo: 'bar', row: true }, { hey: 'ya' }]; - const migrated = migrate(generateDoc({ type: 'table', aggs })); - const actual = JSON.parse(migrated.attributes.visState); - expect(actual.aggs.map(agg => agg.params)).toEqual(expected); - }); - - it('should throw with a reference to the doc name if something goes wrong', () => { - const doc = { - attributes: { - title: 'My Vis', - description: 'This is my super cool vis.', - visState: '!/// Intentionally malformed JSON ///!', - uiStateJSON: '{}', - version: 1, - kibanaSavedObjectMeta: { - searchSourceJSON: '{}', - }, - }, - }; - expect(() => migrate(doc)).toThrowError(/My Vis/); - }); - }); - - describe('date histogram custom interval removal', () => { - const migrate = doc => migrations.visualization['7.2.0'](doc); - let doc; - beforeEach(() => { - doc = { - attributes: { - visState: JSON.stringify({ - aggs: [ - { - enabled: true, - id: '1', - params: { - customInterval: '1h', - }, - schema: 'metric', - type: 'count', - }, - { - enabled: true, - id: '2', - params: { - customInterval: '2h', - drop_partials: false, - extended_bounds: {}, - field: 'timestamp', - interval: 'auto', - min_doc_count: 1, - useNormalizedEsInterval: true, - }, - schema: 'segment', - type: 'date_histogram', - }, - { - enabled: true, - id: '4', - params: { - customInterval: '2h', - drop_partials: false, - extended_bounds: {}, - field: 'timestamp', - interval: 'custom', - min_doc_count: 1, - useNormalizedEsInterval: true, - }, - schema: 'segment', - type: 'date_histogram', - }, - { - enabled: true, - id: '3', - params: { - customBucket: { - enabled: true, - id: '1-bucket', - params: { - customInterval: '2h', - drop_partials: false, - extended_bounds: {}, - field: 'timestamp', - interval: 'custom', - min_doc_count: 1, - useNormalizedEsInterval: true, - }, - type: 'date_histogram', - }, - customMetric: { - enabled: true, - id: '1-metric', - params: {}, - type: 'count', - }, - }, - schema: 'metric', - type: 'max_bucket', - }, - ], - }), - }, - }; - }); - - it('should remove customInterval from date_histogram aggregations', () => { - const migratedDoc = migrate(doc); - const aggs = JSON.parse(migratedDoc.attributes.visState).aggs; - expect(aggs[1]).not.toHaveProperty('params.customInterval'); - }); - - it('should not change interval from date_histogram aggregations', () => { - const migratedDoc = migrate(doc); - const aggs = JSON.parse(migratedDoc.attributes.visState).aggs; - expect(aggs[1].params.interval).toBe( - JSON.parse(doc.attributes.visState).aggs[1].params.interval - ); - }); - - it('should not remove customInterval from non date_histogram aggregations', () => { - const migratedDoc = migrate(doc); - const aggs = JSON.parse(migratedDoc.attributes.visState).aggs; - expect(aggs[0]).toHaveProperty('params.customInterval'); - }); - - it('should set interval with customInterval value and remove customInterval when interval equals "custom"', () => { - const migratedDoc = migrate(doc); - const aggs = JSON.parse(migratedDoc.attributes.visState).aggs; - expect(aggs[2].params.interval).toBe( - JSON.parse(doc.attributes.visState).aggs[2].params.customInterval - ); - expect(aggs[2]).not.toHaveProperty('params.customInterval'); - }); - - it('should remove customInterval from nested aggregations', () => { - const migratedDoc = migrate(doc); - const aggs = JSON.parse(migratedDoc.attributes.visState).aggs; - expect(aggs[3]).not.toHaveProperty('params.customBucket.params.customInterval'); - }); - - it('should remove customInterval from nested aggregations and set interval with customInterval value', () => { - const migratedDoc = migrate(doc); - const aggs = JSON.parse(migratedDoc.attributes.visState).aggs; - expect(aggs[3].params.customBucket.params.interval).toBe( - JSON.parse(doc.attributes.visState).aggs[3].params.customBucket.params.customInterval - ); - expect(aggs[3]).not.toHaveProperty('params.customBucket.params.customInterval'); - }); - - it('should not fail on date histograms without a customInterval', () => { - const migratedDoc = migrate(doc); - const aggs = JSON.parse(migratedDoc.attributes.visState).aggs; - expect(aggs[3]).not.toHaveProperty('params.customInterval'); - }); - }); - describe('7.3.0', () => { - const logMsgArr = []; - const logger = { - warning: msg => logMsgArr.push(msg), - }; - const migrate = doc => migrations.visualization['7.3.0'](doc, logger); - - it('migrates type = gauge verticalSplit: false to alignment: vertical', () => { - const migratedDoc = migrate({ - attributes: { - visState: JSON.stringify({ type: 'gauge', params: { gauge: { verticalSplit: false } } }), - }, - }); - expect(migratedDoc).toMatchInlineSnapshot(` -Object { - "attributes": Object { - "visState": "{\\"type\\":\\"gauge\\",\\"params\\":{\\"gauge\\":{\\"alignment\\":\\"horizontal\\"}}}", - }, -} -`); - }); - - it('migrates type = gauge verticalSplit: false to alignment: horizontal', () => { - const migratedDoc = migrate({ - attributes: { - visState: JSON.stringify({ type: 'gauge', params: { gauge: { verticalSplit: true } } }), - }, - }); - expect(migratedDoc).toMatchInlineSnapshot(` -Object { - "attributes": Object { - "visState": "{\\"type\\":\\"gauge\\",\\"params\\":{\\"gauge\\":{\\"alignment\\":\\"vertical\\"}}}", - }, -} -`); - }); - - it('doesnt migrate type = gauge containing invalid visState object, adds message to log', () => { - const migratedDoc = migrate({ - attributes: { - visState: JSON.stringify({ type: 'gauge' }), - }, - }); - expect(migratedDoc).toMatchInlineSnapshot(` -Object { - "attributes": Object { - "visState": "{\\"type\\":\\"gauge\\"}", - }, -} -`); - expect(logMsgArr).toMatchInlineSnapshot(` -Array [ - "Exception @ migrateGaugeVerticalSplitToAlignment! TypeError: Cannot read property 'gauge' of undefined", - "Exception @ migrateGaugeVerticalSplitToAlignment! Payload: {\\"type\\":\\"gauge\\"}", -] -`); - }); - - describe('filters agg query migration', () => { - const doc = { - attributes: { - visState: JSON.stringify({ - aggs: [ - { - type: 'filters', - params: { - filters: [ - { - input: { - query: 'response:200', - }, - label: '', - }, - { - input: { - query: 'response:404', - }, - label: 'bad response', - }, - { - input: { - query: { - exists: { - field: 'phpmemory', - }, - }, - }, - label: '', - }, - ], - }, - }, - ], - }), - }, - }; - - it('should add language property to filters without one, assuming lucene', () => { - const migrationResult = migrate(doc); - expect(migrationResult).toEqual({ - attributes: { - visState: JSON.stringify({ - aggs: [ - { - type: 'filters', - params: { - filters: [ - { - input: { - query: 'response:200', - language: 'lucene', - }, - label: '', - }, - { - input: { - query: 'response:404', - language: 'lucene', - }, - label: 'bad response', - }, - { - input: { - query: { - exists: { - field: 'phpmemory', - }, - }, - language: 'lucene', - }, - label: '', - }, - ], - }, - }, - ], - }), - }, - }); - }); - }); - - describe('replaceMovAvgToMovFn()', () => { - let doc; - - beforeEach(() => { - doc = { - attributes: { - title: 'VIS', - visState: `{"title":"VIS","type":"metrics","params":{"id":"61ca57f0-469d-11e7-af02-69e470af7417", - "type":"timeseries","series":[{"id":"61ca57f1-469d-11e7-af02-69e470af7417","color":"rgba(0,156,224,1)", - "split_mode":"terms","metrics":[{"id":"61ca57f2-469d-11e7-af02-69e470af7417","type":"count", - "numerator":"FlightDelay:true"},{"settings":"","minimize":0,"window":5,"model": - "holt_winters","id":"23054fe0-8915-11e9-9b86-d3f94982620f","type":"moving_average","field": - "61ca57f2-469d-11e7-af02-69e470af7417","predict":1}],"separate_axis":0,"axis_position":"right", - "formatter":"number","chart_type":"line","line_width":"2","point_size":"0","fill":0.5,"stacked":"none", - "label":"Percent Delays","terms_size":"2","terms_field":"OriginCityName"}],"time_field":"timestamp", - "index_pattern":"kibana_sample_data_flights","interval":">=12h","axis_position":"left","axis_formatter": - "number","show_legend":1,"show_grid":1,"annotations":[{"fields":"FlightDelay,Cancelled,Carrier", - "template":"{{Carrier}}: Flight Delayed and Cancelled!","index_pattern":"kibana_sample_data_flights", - "query_string":"FlightDelay:true AND Cancelled:true","id":"53b7dff0-4c89-11e8-a66a-6989ad5a0a39", - "color":"rgba(0,98,177,1)","time_field":"timestamp","icon":"fa-exclamation-triangle", - "ignore_global_filters":1,"ignore_panel_filters":1,"hidden":true}],"legend_position":"bottom", - "axis_scale":"normal","default_index_pattern":"kibana_sample_data_flights","default_timefield":"timestamp"}, - "aggs":[]}`, - }, - migrationVersion: { - visualization: '7.2.0', - }, - type: 'visualization', - }; - }); - - test('should add some necessary moving_fn fields', () => { - const migratedDoc = migrate(doc); - const visState = JSON.parse(migratedDoc.attributes.visState); - const metric = visState.params.series[0].metrics[1]; - - expect(metric).toHaveProperty('model_type'); - expect(metric).toHaveProperty('alpha'); - expect(metric).toHaveProperty('beta'); - expect(metric).toHaveProperty('gamma'); - expect(metric).toHaveProperty('period'); - expect(metric).toHaveProperty('multiplicative'); - }); - }); - }); - describe('7.3.0 tsvb', () => { - const migrate = doc => migrations.visualization['7.3.0'](doc); - const generateDoc = ({ params }) => ({ - attributes: { - title: 'My Vis', - description: 'This is my super cool vis.', - visState: JSON.stringify({ params }), - uiStateJSON: '{}', - version: 1, - kibanaSavedObjectMeta: { - searchSourceJSON: '{}', - }, - }, - }); - it('should change series item filters from a string into an object', () => { - const params = { type: 'metric', series: [{ filter: 'Filter Bytes Test:>1000' }] }; - const testDoc1 = generateDoc({ params }); - const migratedTestDoc1 = migrate(testDoc1); - const series = JSON.parse(migratedTestDoc1.attributes.visState).params.series; - expect(series[0].filter).toHaveProperty('query'); - expect(series[0].filter).toHaveProperty('language'); - }); - it('should not change a series item filter string in the object after migration', () => { - const markdownParams = { - type: 'markdown', - series: [ - { - filter: 'Filter Bytes Test:>1000', - split_filters: [{ filter: 'bytes:>1000' }], - }, - ], - }; - const markdownDoc = generateDoc({ params: markdownParams }); - const migratedMarkdownDoc = migrate(markdownDoc); - const markdownSeries = JSON.parse(migratedMarkdownDoc.attributes.visState).params.series; - expect(markdownSeries[0].filter.query).toBe( - JSON.parse(markdownDoc.attributes.visState).params.series[0].filter - ); - expect(markdownSeries[0].split_filters[0].filter.query).toBe( - JSON.parse(markdownDoc.attributes.visState).params.series[0].split_filters[0].filter - ); - }); - it('should change series item filters from a string into an object for all filters', () => { - const params = { - type: 'timeseries', - filter: 'bytes:>1000', - series: [ - { - filter: 'Filter Bytes Test:>1000', - split_filters: [{ filter: 'bytes:>1000' }], - }, - ], - annotations: [{ query_string: 'bytes:>1000' }], - }; - const timeSeriesDoc = generateDoc({ params: params }); - const migratedtimeSeriesDoc = migrate(timeSeriesDoc); - const timeSeriesParams = JSON.parse(migratedtimeSeriesDoc.attributes.visState).params; - expect(Object.keys(timeSeriesParams.series[0].filter)).toEqual( - expect.arrayContaining(['query', 'language']) - ); - expect(Object.keys(timeSeriesParams.series[0].split_filters[0].filter)).toEqual( - expect.arrayContaining(['query', 'language']) - ); - expect(Object.keys(timeSeriesParams.annotations[0].query_string)).toEqual( - expect.arrayContaining(['query', 'language']) - ); - }); - it('should not fail on a metric visualization without a filter in a series item', () => { - const params = { type: 'metric', series: [{}, {}, {}] }; - const testDoc1 = generateDoc({ params }); - const migratedTestDoc1 = migrate(testDoc1); - const series = JSON.parse(migratedTestDoc1.attributes.visState).params.series; - expect(series[2]).not.toHaveProperty('filter.query'); - }); - it('should not migrate a visualization of unknown type', () => { - const params = { type: 'unknown', series: [{ filter: 'foo:bar' }] }; - const doc = generateDoc({ params }); - const migratedDoc = migrate(doc); - const series = JSON.parse(migratedDoc.attributes.visState).params.series; - expect(series[0].filter).toEqual(params.series[0].filter); - }); - }); - - describe('7.3.1', () => { - const migrate = migrations.visualization['7.3.1']; - - it('should migrate filters agg query string queries', () => { - const state = { - aggs: [ - { type: 'count', params: {} }, - { - type: 'filters', - params: { - filters: [ - { - input: { - query: { - query_string: { query: 'machine.os.keyword:"win 8"' }, - }, - }, - }, - ], - }, - }, - ], - }; - const expected = { - aggs: [ - { type: 'count', params: {} }, - { - type: 'filters', - params: { - filters: [{ input: { query: 'machine.os.keyword:"win 8"' } }], - }, - }, - ], - }; - const migratedDoc = migrate({ attributes: { visState: JSON.stringify(state) } }); - expect(migratedDoc).toEqual({ attributes: { visState: JSON.stringify(expected) } }); - }); - }); - describe('7.4.2 tsvb split_filters migration', () => { - const migrate = doc => migrations.visualization['7.4.2'](doc); - const generateDoc = ({ params }) => ({ - attributes: { - title: 'My Vis', - description: 'This is my super cool vis.', - visState: JSON.stringify({ params }), - uiStateJSON: '{}', - version: 1, - kibanaSavedObjectMeta: { - searchSourceJSON: '{}', - }, - }, - }); - it('should change series item filters from a string into an object for all filters', () => { - const params = { - type: 'timeseries', - filter: { - query: 'bytes:>1000', - language: 'lucene', - }, - series: [ - { - split_filters: [{ filter: 'bytes:>1000' }], - }, - ], - }; - const timeSeriesDoc = generateDoc({ params: params }); - const migratedtimeSeriesDoc = migrate(timeSeriesDoc); - const timeSeriesParams = JSON.parse(migratedtimeSeriesDoc.attributes.visState).params; - expect(Object.keys(timeSeriesParams.filter)).toEqual( - expect.arrayContaining(['query', 'language']) - ); - expect(timeSeriesParams.series[0].split_filters[0].filter).toEqual({ - query: 'bytes:>1000', - language: 'lucene', - }); - }); - it('should change series item split filters when there is no filter item', () => { - const params = { - type: 'timeseries', - filter: { - query: 'bytes:>1000', - language: 'lucene', - }, - series: [ - { - split_filters: [{ filter: 'bytes:>1000' }], - }, - ], - annotations: [ - { - query_string: { - query: 'bytes:>1000', - language: 'lucene', - }, - }, - ], - }; - const timeSeriesDoc = generateDoc({ params: params }); - const migratedtimeSeriesDoc = migrate(timeSeriesDoc); - const timeSeriesParams = JSON.parse(migratedtimeSeriesDoc.attributes.visState).params; - expect(timeSeriesParams.series[0].split_filters[0].filter).toEqual({ - query: 'bytes:>1000', - language: 'lucene', - }); - }); - it('should not convert split_filters to objects if there are no split filter filters', () => { - const params = { - type: 'timeseries', - filter: { - query: 'bytes:>1000', - language: 'lucene', - }, - series: [ - { - split_filters: [], - }, - ], - }; - const timeSeriesDoc = generateDoc({ params: params }); - const migratedtimeSeriesDoc = migrate(timeSeriesDoc); - const timeSeriesParams = JSON.parse(migratedtimeSeriesDoc.attributes.visState).params; - expect(timeSeriesParams.series[0].split_filters).not.toHaveProperty('query'); - }); - it('should do nothing if a split_filter is already a query:language object', () => { - const params = { - type: 'timeseries', - filter: { - query: 'bytes:>1000', - language: 'lucene', - }, - series: [ - { - split_filters: [ - { - filter: { - query: 'bytes:>1000', - language: 'lucene', - }, - }, - ], - }, - ], - annotations: [ - { - query_string: { - query: 'bytes:>1000', - language: 'lucene', - }, - }, - ], - }; - const timeSeriesDoc = generateDoc({ params: params }); - const migratedtimeSeriesDoc = migrate(timeSeriesDoc); - const timeSeriesParams = JSON.parse(migratedtimeSeriesDoc.attributes.visState).params; - expect(timeSeriesParams.series[0].split_filters[0].filter.query).toEqual('bytes:>1000'); - expect(timeSeriesParams.series[0].split_filters[0].filter.language).toEqual('lucene'); - }); - }); -}); - describe('dashboard', () => { describe('7.0.0', () => { const migration = migrations.dashboard['7.0.0']; @@ -1751,271 +445,3 @@ Object { }); }); }); - -describe('search', () => { - describe('7.0.0', () => { - const migration = migrations.search['7.0.0']; - - test('skips errors when searchSourceJSON is null', () => { - const doc = { - id: '123', - type: 'search', - attributes: { - foo: true, - kibanaSavedObjectMeta: { - searchSourceJSON: null, - }, - }, - }; - const migratedDoc = migration(doc); - expect(migratedDoc).toMatchInlineSnapshot(` -Object { - "attributes": Object { - "foo": true, - "kibanaSavedObjectMeta": Object { - "searchSourceJSON": null, - }, - }, - "id": "123", - "references": Array [], - "type": "search", -} -`); - }); - - test('skips errors when searchSourceJSON is undefined', () => { - const doc = { - id: '123', - type: 'search', - attributes: { - foo: true, - kibanaSavedObjectMeta: { - searchSourceJSON: undefined, - }, - }, - }; - const migratedDoc = migration(doc); - expect(migratedDoc).toMatchInlineSnapshot(` -Object { - "attributes": Object { - "foo": true, - "kibanaSavedObjectMeta": Object { - "searchSourceJSON": undefined, - }, - }, - "id": "123", - "references": Array [], - "type": "search", -} -`); - }); - - test('skips error when searchSourceJSON is not a string', () => { - const doc = { - id: '123', - type: 'search', - attributes: { - foo: true, - kibanaSavedObjectMeta: { - searchSourceJSON: 123, - }, - }, - }; - expect(migration(doc)).toMatchInlineSnapshot(` -Object { - "attributes": Object { - "foo": true, - "kibanaSavedObjectMeta": Object { - "searchSourceJSON": 123, - }, - }, - "id": "123", - "references": Array [], - "type": "search", -} -`); - }); - - test('skips error when searchSourceJSON is invalid json', () => { - const doc = { - id: '123', - type: 'search', - attributes: { - foo: true, - kibanaSavedObjectMeta: { - searchSourceJSON: '{abc123}', - }, - }, - }; - expect(migration(doc)).toMatchInlineSnapshot(` -Object { - "attributes": Object { - "foo": true, - "kibanaSavedObjectMeta": Object { - "searchSourceJSON": "{abc123}", - }, - }, - "id": "123", - "references": Array [], - "type": "search", -} -`); - }); - - test('skips error when "index" and "filter" is missing from searchSourceJSON', () => { - const doc = { - id: '123', - type: 'search', - attributes: { - foo: true, - kibanaSavedObjectMeta: { - searchSourceJSON: JSON.stringify({ bar: true }), - }, - }, - }; - const migratedDoc = migration(doc); - expect(migratedDoc).toMatchInlineSnapshot(` -Object { - "attributes": Object { - "foo": true, - "kibanaSavedObjectMeta": Object { - "searchSourceJSON": "{\\"bar\\":true}", - }, - }, - "id": "123", - "references": Array [], - "type": "search", -} -`); - }); - - test('extracts "index" attribute from doc', () => { - const doc = { - id: '123', - type: 'search', - attributes: { - foo: true, - kibanaSavedObjectMeta: { - searchSourceJSON: JSON.stringify({ bar: true, index: 'pattern*' }), - }, - }, - }; - const migratedDoc = migration(doc); - expect(migratedDoc).toMatchInlineSnapshot(` -Object { - "attributes": Object { - "foo": true, - "kibanaSavedObjectMeta": Object { - "searchSourceJSON": "{\\"bar\\":true,\\"indexRefName\\":\\"kibanaSavedObjectMeta.searchSourceJSON.index\\"}", - }, - }, - "id": "123", - "references": Array [ - Object { - "id": "pattern*", - "name": "kibanaSavedObjectMeta.searchSourceJSON.index", - "type": "index-pattern", - }, - ], - "type": "search", -} -`); - }); - - test('extracts index patterns from filter', () => { - const doc = { - id: '123', - type: 'search', - attributes: { - foo: true, - kibanaSavedObjectMeta: { - searchSourceJSON: JSON.stringify({ - bar: true, - filter: [ - { - meta: { - foo: true, - index: 'my-index', - }, - }, - ], - }), - }, - }, - }; - const migratedDoc = migration(doc); - - expect(migratedDoc).toMatchInlineSnapshot(` -Object { - "attributes": Object { - "foo": true, - "kibanaSavedObjectMeta": Object { - "searchSourceJSON": "{\\"bar\\":true,\\"filter\\":[{\\"meta\\":{\\"foo\\":true,\\"indexRefName\\":\\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\\"}}]}", - }, - }, - "id": "123", - "references": Array [ - Object { - "id": "my-index", - "name": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index", - "type": "index-pattern", - }, - ], - "type": "search", -} -`); - }); - }); - - describe('7.4.0', function() { - const migration = migrations.search['7.4.0']; - - test('transforms one dimensional sort arrays into two dimensional arrays', () => { - const doc = { - id: '123', - type: 'search', - attributes: { - sort: ['bytes', 'desc'], - }, - }; - - const expected = { - id: '123', - type: 'search', - attributes: { - sort: [['bytes', 'desc']], - }, - }; - - const migratedDoc = migration(doc); - - expect(migratedDoc).toEqual(expected); - }); - - test("doesn't modify search docs that already have two dimensional sort arrays", () => { - const doc = { - id: '123', - type: 'search', - attributes: { - sort: [['bytes', 'desc']], - }, - }; - - const migratedDoc = migration(doc); - - expect(migratedDoc).toEqual(doc); - }); - - test("doesn't modify search docs that have no sort array", () => { - const doc = { - id: '123', - type: 'search', - attributes: {}, - }; - - const migratedDoc = migration(doc); - - expect(migratedDoc).toEqual(doc); - }); - }); -}); diff --git a/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts b/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts index beadcda5952880..0c5329d8b259f8 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/legacy_imports.ts @@ -25,7 +25,7 @@ */ export { npSetup, npStart } from 'ui/new_platform'; -export { subscribeWithScope } from 'ui/utils/subscribe_with_scope'; + export { KbnUrl } from 'ui/url/kbn_url'; // @ts-ignore export { KbnUrlProvider, RedirectWhenMissingProvider } from 'ui/url/index'; @@ -38,4 +38,5 @@ export { migrateLegacyQuery, PrivateProvider, PromiseServiceCreator, + subscribeWithScope, } from '../../../../../plugins/kibana_legacy/public'; diff --git a/src/legacy/core_plugins/kibana/public/dashboard/migrations/migrate_to_730_panels.test.ts b/src/legacy/core_plugins/kibana/public/dashboard/migrations/migrate_to_730_panels.test.ts index ad4feacde08156..2189b53ac81ee5 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/migrations/migrate_to_730_panels.test.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/migrations/migrate_to_730_panels.test.ts @@ -48,7 +48,7 @@ import { import { DEFAULT_PANEL_WIDTH, DEFAULT_PANEL_HEIGHT, -} from '../../../../dashboard_embeddable_container/public/np_ready/public'; +} from '../../../../../../plugins/dashboard/public'; test('6.0 migrates uiState, sort, scales, and gridData', async () => { const uiState = { diff --git a/src/legacy/core_plugins/kibana/public/dashboard/migrations/migrate_to_730_panels.ts b/src/legacy/core_plugins/kibana/public/dashboard/migrations/migrate_to_730_panels.ts index b0d20b44827281..6b037fa63cf685 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/migrations/migrate_to_730_panels.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/migrations/migrate_to_730_panels.ts @@ -18,7 +18,7 @@ */ import { i18n } from '@kbn/i18n'; import semver from 'semver'; -import { GridData } from 'src/legacy/core_plugins/dashboard_embeddable_container/public/np_ready/public'; +import { GridData } from 'src/plugins/dashboard/public'; import uuid from 'uuid'; import { @@ -113,7 +113,7 @@ function migratePre61PanelToLatest( ? PANEL_HEIGHT_SCALE_FACTOR_WITH_MARGINS : PANEL_HEIGHT_SCALE_FACTOR; - // These are snapshotted here instead of imported form dashboard_embeddable_container because + // These are snapshotted here instead of imported from dashboard because // this function is called from both client and server side, and having an import from a public // folder will cause errors for the server side version. Also, this is only run for the point in time // from panels created in < 7.3 so maybe using a snapshot of the default values when this migration was diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/application.ts b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/application.ts index 9ca84735cac168..fe0e7a1d3e6d00 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/application.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/application.ts @@ -39,7 +39,7 @@ import { } from '../legacy_imports'; // @ts-ignore import { initDashboardApp } from './legacy_app'; -import { IEmbeddableStart } from '../../../../../../plugins/embeddable/public'; +import { EmbeddableStart } from '../../../../../../plugins/embeddable/public'; import { NavigationPublicPluginStart as NavigationStart } from '../../../../../../plugins/navigation/public'; import { DataPublicPluginStart } from '../../../../../../plugins/data/public'; import { SharePluginStart } from '../../../../../../plugins/share/public'; @@ -67,7 +67,7 @@ export interface RenderDeps { chrome: ChromeStart; addBasePath: (path: string) => string; savedQueryService: DataPublicPluginStart['query']['savedQueries']; - embeddable: IEmbeddableStart; + embeddable: EmbeddableStart; localStorage: Storage; share: SharePluginStart; config: KibanaLegacyStart['config']; diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx index af3347afa9c5f2..d1e4c9d2d2a0c0 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app_controller.tsx @@ -51,7 +51,7 @@ import { DashboardContainerFactory, DashboardContainerInput, DashboardPanelState, -} from '../../../../dashboard_embeddable_container/public/np_ready/public'; +} from '../../../../../../plugins/dashboard/public'; import { EmbeddableFactoryNotFoundError, ErrorEmbeddable, @@ -78,7 +78,11 @@ import { removeQueryParam, unhashUrl, } from '../../../../../../plugins/kibana_utils/public'; -import { KibanaLegacyStart } from '../../../../../../plugins/kibana_legacy/public'; +import { + addFatalError, + AngularHttpError, + KibanaLegacyStart, +} from '../../../../../../plugins/kibana_legacy/public'; export interface DashboardAppControllerDependencies extends RenderDeps { $scope: DashboardAppScope; @@ -115,6 +119,7 @@ export class DashboardAppController { overlays, chrome, injectedMetadata, + fatalErrors, uiSettings, savedObjects, http, @@ -592,21 +597,31 @@ export class DashboardAppController { $scope.timefilterSubscriptions$ = new Subscription(); $scope.timefilterSubscriptions$.add( - subscribeWithScope($scope, timefilter.getRefreshIntervalUpdate$(), { - next: () => { - updateState(); - refreshDashboardContainer(); + subscribeWithScope( + $scope, + timefilter.getRefreshIntervalUpdate$(), + { + next: () => { + updateState(); + refreshDashboardContainer(); + }, }, - }) + (error: AngularHttpError | Error | string) => addFatalError(fatalErrors, error) + ) ); $scope.timefilterSubscriptions$.add( - subscribeWithScope($scope, timefilter.getTimeUpdate$(), { - next: () => { - updateState(); - refreshDashboardContainer(); + subscribeWithScope( + $scope, + timefilter.getTimeUpdate$(), + { + next: () => { + updateState(); + refreshDashboardContainer(); + }, }, - }) + (error: AngularHttpError | Error | string) => addFatalError(fatalErrors, error) + ) ); function updateViewMode(newMode: ViewMode) { diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_state_manager.ts b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_state_manager.ts index fe7beafcad18c2..f29721e3c3d5c8 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_state_manager.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_state_manager.ts @@ -23,7 +23,7 @@ import { Observable, Subscription } from 'rxjs'; import { Moment } from 'moment'; import { History } from 'history'; -import { DashboardContainer } from 'src/legacy/core_plugins/dashboard_embeddable_container/public/np_ready/public'; +import { DashboardContainer } from 'src/plugins/dashboard/public'; import { ViewMode } from '../../../../../../plugins/embeddable/public'; import { migrateLegacyQuery } from '../legacy_imports'; import { diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/lib/embeddable_saved_object_converters.test.ts b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/lib/embeddable_saved_object_converters.test.ts index 3f04cad4f322b6..b2a2f43b9152d2 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/lib/embeddable_saved_object_converters.test.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/lib/embeddable_saved_object_converters.test.ts @@ -23,7 +23,7 @@ import { convertPanelStateToSavedDashboardPanel, } from './embeddable_saved_object_converters'; import { SavedDashboardPanel } from '../types'; -import { DashboardPanelState } from 'src/legacy/core_plugins/dashboard_embeddable_container/public/np_ready/public'; +import { DashboardPanelState } from 'src/plugins/dashboard/public'; import { EmbeddableInput } from 'src/legacy/core_plugins/embeddable_api/public/np_ready/public'; interface CustomInput extends EmbeddableInput { diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/lib/embeddable_saved_object_converters.ts b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/lib/embeddable_saved_object_converters.ts index 2d42609e1e25fe..7d5a378885470a 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/lib/embeddable_saved_object_converters.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/lib/embeddable_saved_object_converters.ts @@ -17,7 +17,7 @@ * under the License. */ import { omit } from 'lodash'; -import { DashboardPanelState } from 'src/legacy/core_plugins/dashboard_embeddable_container/public/np_ready/public'; +import { DashboardPanelState } from 'src/plugins/dashboard/public'; import { SavedDashboardPanel } from '../types'; export function convertSavedDashboardPanelToPanelState( diff --git a/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts b/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts index d94612225782dc..a9ee77921ed4aa 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts +++ b/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts @@ -35,7 +35,7 @@ import { DataPublicPluginSetup, esFilters, } from '../../../../../plugins/data/public'; -import { IEmbeddableStart } from '../../../../../plugins/embeddable/public'; +import { EmbeddableStart } from '../../../../../plugins/embeddable/public'; import { Storage } from '../../../../../plugins/kibana_utils/public'; import { NavigationPublicPluginStart as NavigationStart } from '../../../../../plugins/navigation/public'; import { DashboardConstants } from './np_ready/dashboard_constants'; @@ -54,7 +54,7 @@ import { createKbnUrlTracker } from '../../../../../plugins/kibana_utils/public' export interface DashboardPluginStartDependencies { data: DataPublicPluginStart; - embeddable: IEmbeddableStart; + embeddable: EmbeddableStart; navigation: NavigationStart; share: SharePluginStart; kibanaLegacy: KibanaLegacyStart; @@ -70,7 +70,7 @@ export class DashboardPlugin implements Plugin { private startDependencies: { data: DataPublicPluginStart; savedObjectsClient: SavedObjectsClientContract; - embeddable: IEmbeddableStart; + embeddable: EmbeddableStart; navigation: NavigationStart; share: SharePluginStart; dashboardConfig: KibanaLegacyStart['dashboardConfig']; 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 8a8b5d8e0e3ea3..57a9e4966d6d6f 100644 --- a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts +++ b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts @@ -50,13 +50,15 @@ export function setServices(newServices: any) { // EXPORT legacy static dependencies, should be migrated when available in a new version; export { angular }; export { wrapInI18nContext } from 'ui/i18n'; -export { getRequestInspectorStats, getResponseInspectorStats } from '../../../data/public'; +import { search } from '../../../../../plugins/data/public'; +export const { getRequestInspectorStats, getResponseInspectorStats, tabifyAggResponse } = search; +// @ts-ignore +export { shortenDottedString } from '../../common/utils/shorten_dotted_string'; // @ts-ignore export { intervalOptions } from 'ui/agg_types'; -export { subscribeWithScope } from 'ui/utils/subscribe_with_scope'; +export { subscribeWithScope } from '../../../../../plugins/kibana_legacy/public'; // @ts-ignore export { timezoneProvider } from 'ui/vis/lib/timezone'; -export { tabifyAggResponse } from '../../../data/public'; export { unhashUrl } from '../../../../../plugins/kibana_utils/public'; export { ensureDefaultIndexPattern, diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name/field_name.test.tsx b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name/field_name.test.tsx index 93b0c1827806f2..7659d4fe95bab9 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name/field_name.test.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name/field_name.test.tsx @@ -20,6 +20,8 @@ import React from 'react'; import { render } from 'enzyme'; import { FieldName } from './field_name'; +jest.mock('ui/new_platform'); + // Note that it currently provides just 2 basic tests, there should be more, but // the components involved will soon change test('FieldName renders a string field by providing fieldType and fieldName', () => { diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name/field_name.tsx b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name/field_name.tsx index e2aa33179f6326..26d8a5abb24719 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name/field_name.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name/field_name.tsx @@ -21,7 +21,7 @@ import classNames from 'classnames'; import { EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui'; import { FieldIcon, FieldIconProps } from '../../../../../../../../../plugins/kibana_react/public'; -import { shortenDottedString } from '../../../../../../../../../plugins/data/common/utils'; +import { shortenDottedString } from '../../../../kibana_services'; import { getFieldTypeName } from './field_type_name'; // property field is provided at discover's field chooser 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 c939de9b57078b..f3334c9211e4bd 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 @@ -76,6 +76,7 @@ import { getDefaultQuery, } from '../../../../../../../plugins/data/public'; import { getIndexPatternId } from '../helpers/get_index_pattern_id'; +import { addFatalError } from '../../../../../../../plugins/kibana_legacy/public'; const fetchStatuses = { UNINITIALIZED: 'uninitialized', @@ -255,11 +256,16 @@ function discoverController( // update data source when filters update subscriptions.add( - subscribeWithScope($scope, filterManager.getUpdates$(), { - next: () => { - $scope.updateDataSource(); + subscribeWithScope( + $scope, + filterManager.getUpdates$(), + { + next: () => { + $scope.updateDataSource(); + }, }, - }) + error => addFatalError(core.fatalErrors, error) + ) ); const inspectorAdapters = { @@ -621,16 +627,26 @@ function discoverController( ).pipe(debounceTime(100)); subscriptions.add( - subscribeWithScope($scope, searchBarChanges, { - next: $scope.fetch, - }) + subscribeWithScope( + $scope, + searchBarChanges, + { + next: $scope.fetch, + }, + error => addFatalError(core.fatalErrors, error) + ) ); subscriptions.add( - subscribeWithScope($scope, timefilter.getTimeUpdate$(), { - next: () => { - $scope.updateTime(); + subscribeWithScope( + $scope, + timefilter.getTimeUpdate$(), + { + next: () => { + $scope.updateTime(); + }, }, - }) + error => addFatalError(core.fatalErrors, error) + ) ); //Handling change oft the histogram interval $scope.$watch('state.interval', function(newInterval, oldInterval) { diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header/helpers.tsx b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header/helpers.tsx index 68ba508ffebdd6..a2ad18d59d935c 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header/helpers.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header/helpers.tsx @@ -16,8 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { IndexPattern } from '../../../../../kibana_services'; -import { shortenDottedString } from '../../../../../../../../../../plugins/data/common/utils'; +import { IndexPattern, shortenDottedString } from '../../../../../kibana_services'; export type SortOrder = [string, string]; export interface ColumnProps { diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header/table_header.test.tsx b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header/table_header.test.tsx index b201bea26503ea..89f73022627c50 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header/table_header.test.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header/table_header.test.tsx @@ -25,6 +25,8 @@ import { findTestSubject } from '@elastic/eui/lib/test'; import { SortOrder } from './helpers'; import { IndexPattern, IFieldType } from '../../../../../kibana_services'; +jest.mock('ui/new_platform'); + function getMockIndexPattern() { return ({ id: 'test', diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/embeddable/search_embeddable.ts b/src/legacy/core_plugins/kibana/public/discover/np_ready/embeddable/search_embeddable.ts index 91726c69189f36..d09b7612af49c6 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/embeddable/search_embeddable.ts +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/embeddable/search_embeddable.ts @@ -20,7 +20,10 @@ import _ from 'lodash'; import * as Rx from 'rxjs'; import { Subscription } from 'rxjs'; import { i18n } from '@kbn/i18n'; -import { UiActionsStart } from 'src/plugins/ui_actions/public'; +import { + UiActionsStart, + APPLY_FILTER_TRIGGER, +} from '../../../../../../..//plugins/ui_actions/public'; import { RequestAdapter, Adapters } from '../../../../../../../plugins/inspector/public'; import { esFilters, @@ -31,11 +34,7 @@ import { Query, IFieldType, } from '../../../../../../../plugins/data/public'; -import { - APPLY_FILTER_TRIGGER, - Container, - Embeddable, -} from '../../../../../embeddable_api/public/np_ready/public'; +import { Container, Embeddable } from '../../../../../embeddable_api/public/np_ready/public'; import * as columnActions from '../angular/doc_table/actions/columns'; import searchTemplate from './search_template.html'; import { ISearchEmbeddable, SearchInput, SearchOutput } from './types'; diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/embeddable/search_embeddable_factory.ts b/src/legacy/core_plugins/kibana/public/discover/np_ready/embeddable/search_embeddable_factory.ts index 90f1549c9f369e..6f3adc1f4fcce6 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/embeddable/search_embeddable_factory.ts +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/embeddable/search_embeddable_factory.ts @@ -32,6 +32,11 @@ import { SearchEmbeddable } from './search_embeddable'; import { SearchInput, SearchOutput } from './types'; import { SEARCH_EMBEDDABLE_TYPE } from './constants'; +interface StartServices { + executeTriggerActions: UiActionsStart['executeTriggerActions']; + isEditable: () => boolean; +} + export class SearchEmbeddableFactory extends EmbeddableFactory< SearchInput, SearchOutput, @@ -40,12 +45,10 @@ export class SearchEmbeddableFactory extends EmbeddableFactory< public readonly type = SEARCH_EMBEDDABLE_TYPE; private $injector: auto.IInjectorService | null; private getInjector: () => Promise | null; - public isEditable: () => boolean; constructor( - private readonly executeTriggerActions: UiActionsStart['executeTriggerActions'], - getInjector: () => Promise, - isEditable: () => boolean + private getStartServices: () => Promise, + getInjector: () => Promise ) { super({ savedObjectMetaData: { @@ -58,13 +61,16 @@ export class SearchEmbeddableFactory extends EmbeddableFactory< }); this.$injector = null; this.getInjector = getInjector; - this.isEditable = isEditable; } public canCreateNew() { return false; } + public async isEditable() { + return (await this.getStartServices()).isEditable(); + } + public getDisplayName() { return i18n.translate('kbn.embeddable.search.displayName', { defaultMessage: 'search', @@ -90,6 +96,7 @@ export class SearchEmbeddableFactory extends EmbeddableFactory< try { const savedObject = await getServices().getSavedSearchById(savedObjectId); const indexPattern = savedObject.searchSource.getField('index'); + const { executeTriggerActions } = await this.getStartServices(); return new SearchEmbeddable( { savedSearch: savedObject, @@ -101,7 +108,7 @@ export class SearchEmbeddableFactory extends EmbeddableFactory< indexPatterns: indexPattern ? [indexPattern] : [], }, input, - this.executeTriggerActions, + executeTriggerActions, parent ); } catch (e) { diff --git a/src/legacy/core_plugins/kibana/public/discover/plugin.ts b/src/legacy/core_plugins/kibana/public/discover/plugin.ts index 3ba0418d35f718..ba671a64592a57 100644 --- a/src/legacy/core_plugins/kibana/public/discover/plugin.ts +++ b/src/legacy/core_plugins/kibana/public/discover/plugin.ts @@ -30,7 +30,7 @@ import { } from '../../../../../plugins/data/public'; import { registerFeature } from './np_ready/register_feature'; import './kibana_services'; -import { IEmbeddableStart, IEmbeddableSetup } from '../../../../../plugins/embeddable/public'; +import { EmbeddableStart, EmbeddableSetup } from '../../../../../plugins/embeddable/public'; import { getInnerAngularModule, getInnerAngularModuleEmbeddable } from './get_inner_angular'; import { setAngularModule, setServices } from './kibana_services'; import { NavigationPublicPluginStart as NavigationStart } from '../../../../../plugins/navigation/public'; @@ -63,7 +63,7 @@ export interface DiscoverSetup { export type DiscoverStart = void; export interface DiscoverSetupPlugins { uiActions: UiActionsSetup; - embeddable: IEmbeddableSetup; + embeddable: EmbeddableSetup; kibanaLegacy: KibanaLegacySetup; home: HomePublicPluginSetup; visualizations: VisualizationsSetup; @@ -71,7 +71,7 @@ export interface DiscoverSetupPlugins { } export interface DiscoverStartPlugins { uiActions: UiActionsStart; - embeddable: IEmbeddableStart; + embeddable: EmbeddableStart; navigation: NavigationStart; charts: ChartsPluginStart; data: DataPublicPluginStart; @@ -103,7 +103,7 @@ export class DiscoverPlugin implements Plugin { public initializeInnerAngular?: () => void; public initializeServices?: () => Promise<{ core: CoreStart; plugins: DiscoverStartPlugins }>; - setup(core: CoreSetup, plugins: DiscoverSetupPlugins): DiscoverSetup { + setup(core: CoreSetup, plugins: DiscoverSetupPlugins): DiscoverSetup { const { appMounted, appUnMounted, stop: stopUrlTracker } = createKbnUrlTracker({ baseUrl: core.http.basePath.prepend('/app/kibana'), defaultSubUrl: '#/discover', @@ -173,6 +173,7 @@ export class DiscoverPlugin implements Plugin { }); registerFeature(plugins.home); + this.registerEmbeddable(core, plugins); return { addDocView: this.docViewsRegistry.addDocView.bind(this.docViewsRegistry), }; @@ -203,8 +204,6 @@ export class DiscoverPlugin implements Plugin { return { core, plugins }; }; - - this.registerEmbeddable(core, plugins); } stop() { @@ -216,19 +215,25 @@ export class DiscoverPlugin implements Plugin { /** * register embeddable with a slimmer embeddable version of inner angular */ - private async registerEmbeddable(core: CoreStart, plugins: DiscoverStartPlugins) { + private async registerEmbeddable( + core: CoreSetup, + plugins: DiscoverSetupPlugins + ) { const { SearchEmbeddableFactory } = await import('./np_ready/embeddable'); - const isEditable = () => core.application.capabilities.discover.save as boolean; if (!this.getEmbeddableInjector) { throw Error('Discover plugin method getEmbeddableInjector is undefined'); } - const factory = new SearchEmbeddableFactory( - plugins.uiActions.executeTriggerActions, - this.getEmbeddableInjector, - isEditable - ); + const getStartServices = async () => { + const [coreStart, deps] = await core.getStartServices(); + return { + executeTriggerActions: deps.uiActions.executeTriggerActions, + isEditable: () => coreStart.application.capabilities.discover.save as boolean, + }; + }; + + const factory = new SearchEmbeddableFactory(getStartServices, this.getEmbeddableInjector); plugins.embeddable.registerEmbeddableFactory(factory.type, factory); } 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 0cbac20a947bfc..6d302ac5a74f35 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 @@ -28,6 +28,7 @@ import uiRoutes from 'ui/routes'; import { uiModules } from 'ui/modules'; import template from './edit_index_pattern.html'; import { fieldWildcardMatcher } from '../../../../../../../../plugins/kibana_utils/public'; +import { subscribeWithScope } from '../../../../../../../../plugins/kibana_legacy/public'; import { setup as managementSetup } from '../../../../../../management/public/legacy'; import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; @@ -37,7 +38,6 @@ import { ScriptedFieldsTable } from './scripted_fields_table'; import { i18n } from '@kbn/i18n'; import { I18nContext } from 'ui/i18n'; import { npStart } from 'ui/new_platform'; -import { subscribeWithScope } from 'ui/utils/subscribe_with_scope'; import { getEditBreadcrumbs } from '../breadcrumbs'; import { createEditIndexPatternPageStateContainer } from './edit_index_pattern_state_container'; @@ -214,11 +214,16 @@ uiModules $scope.getCurrentTab = getCurrentTab; $scope.setCurrentTab = setCurrentTab; - const stateChangedSub = subscribeWithScope($scope, state$, { - next: ({ tab }) => { - handleTabChange($scope, tab); + const stateChangedSub = subscribeWithScope( + $scope, + state$, + { + next: ({ tab }) => { + handleTabChange($scope, tab); + }, }, - }); + fatalError + ); handleTabChange($scope, getCurrentTab()); // setup initial tab depending on initial tab state diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/indexed_fields_table/components/table/__jest__/__snapshots__/table.test.js.snap b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/indexed_fields_table/components/table/__jest__/__snapshots__/table.test.js.snap index 49f3b83ca28790..f3aa2c5da4b67b 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/indexed_fields_table/components/table/__jest__/__snapshots__/table.test.js.snap +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/indexed_fields_table/components/table/__jest__/__snapshots__/table.test.js.snap @@ -81,6 +81,7 @@ exports[`Table should render normally 1`] = ` Object { "actions": Array [ Object { + "data-test-subj": "editFieldFormat", "description": "Edit", "icon": "pencil", "name": "Edit", diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/indexed_fields_table/components/table/table.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/indexed_fields_table/components/table/table.js index 4b59a096c44405..29e160cf1c1826 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/indexed_fields_table/components/table/table.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/indexed_fields_table/components/table/table.js @@ -217,6 +217,7 @@ export class Table extends PureComponent { icon: 'pencil', onClick: editField, type: 'icon', + 'data-test-subj': 'editFieldFormat', }, ], width: '40px', diff --git a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts index cfd12b32834590..7e96d7bde6e13d 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts @@ -29,7 +29,7 @@ import { import { NavigationPublicPluginStart as NavigationStart } from '../../../../../plugins/navigation/public'; import { Storage } from '../../../../../plugins/kibana_utils/public'; -import { IEmbeddableStart } from '../../../../../plugins/embeddable/public'; +import { EmbeddableStart } from '../../../../../plugins/embeddable/public'; import { SharePluginStart } from '../../../../../plugins/share/public'; import { DataPublicPluginStart, IndexPatternsContract } from '../../../../../plugins/data/public'; import { VisualizationsStart } from '../../../visualizations/public'; @@ -44,7 +44,7 @@ export interface VisualizeKibanaServices { chrome: ChromeStart; core: CoreStart; data: DataPublicPluginStart; - embeddable: IEmbeddableStart; + embeddable: EmbeddableStart; getBasePath: () => string; indexPatterns: IndexPatternsContract; localStorage: Storage; diff --git a/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts b/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts index 66a7bd6f333737..0ddf3ee67aa94a 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/legacy_imports.ts @@ -24,7 +24,6 @@ * directly where they are needed. */ -export { subscribeWithScope } from 'ui/utils/subscribe_with_scope'; // @ts-ignore export { KbnUrlProvider, RedirectWhenMissingProvider } from 'ui/url'; export { absoluteToParsedUrl } from 'ui/url/absolute_to_parsed_url'; @@ -39,4 +38,5 @@ export { migrateLegacyQuery, PrivateProvider, PromiseServiceCreator, + subscribeWithScope, } from '../../../../../plugins/kibana_legacy/public'; diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js index 3fab650002c177..c023c402f5fead 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.js @@ -31,7 +31,7 @@ import { getEditBreadcrumbs } from '../breadcrumbs'; import { addHelpMenuToAppChrome } from '../help_menu/help_menu_util'; import { unhashUrl } from '../../../../../../../plugins/kibana_utils/public'; -import { kbnBaseUrl } from '../../../../../../../plugins/kibana_legacy/public'; +import { addFatalError, kbnBaseUrl } from '../../../../../../../plugins/kibana_legacy/public'; import { SavedObjectSaveModal, showSaveModal, @@ -88,7 +88,7 @@ function VisualizeAppController( toastNotifications, chrome, getBasePath, - core: { docLinks }, + core: { docLinks, fatalErrors }, savedQueryService, uiSettings, I18nContext, @@ -455,16 +455,26 @@ function VisualizeAppController( const subscriptions = new Subscription(); subscriptions.add( - subscribeWithScope($scope, timefilter.getRefreshIntervalUpdate$(), { - next: () => { - $scope.refreshInterval = timefilter.getRefreshInterval(); + subscribeWithScope( + $scope, + timefilter.getRefreshIntervalUpdate$(), + { + next: () => { + $scope.refreshInterval = timefilter.getRefreshInterval(); + }, }, - }) + error => addFatalError(fatalErrors, error) + ) ); subscriptions.add( - subscribeWithScope($scope, timefilter.getTimeUpdate$(), { - next: updateTimeRange, - }) + subscribeWithScope( + $scope, + timefilter.getTimeUpdate$(), + { + next: updateTimeRange, + }, + error => addFatalError(fatalErrors, error) + ) ); subscriptions.add( @@ -487,16 +497,26 @@ function VisualizeAppController( // update the searchSource when filters update subscriptions.add( - subscribeWithScope($scope, filterManager.getUpdates$(), { - next: () => { - $scope.filters = filterManager.getFilters(); + subscribeWithScope( + $scope, + filterManager.getUpdates$(), + { + next: () => { + $scope.filters = filterManager.getFilters(); + }, }, - }) + error => addFatalError(fatalErrors, error) + ) ); subscriptions.add( - subscribeWithScope($scope, filterManager.getFetches$(), { - next: $scope.fetch, - }) + subscribeWithScope( + $scope, + filterManager.getFetches$(), + { + next: $scope.fetch, + }, + error => addFatalError(fatalErrors, error) + ) ); $scope.$on('$destroy', () => { diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/types.d.ts b/src/legacy/core_plugins/kibana/public/visualize/np_ready/types.d.ts index ccb3b3ddbb1da1..01ce872aeb679e 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/types.d.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/types.d.ts @@ -24,7 +24,7 @@ import { DataPublicPluginStart, SavedQuery, } from 'src/plugins/data/public'; -import { IEmbeddableStart } from 'src/plugins/embeddable/public'; +import { EmbeddableStart } from 'src/plugins/embeddable/public'; import { PersistedState } from 'src/plugins/visualizations/public'; import { LegacyCoreStart } from 'kibana/public'; import { Vis } from 'src/legacy/core_plugins/visualizations/public'; @@ -61,7 +61,7 @@ export interface EditorRenderProps { appState: { save(): void }; core: LegacyCoreStart; data: DataPublicPluginStart; - embeddable: IEmbeddableStart; + embeddable: EmbeddableStart; filters: Filter[]; uiState: PersistedState; timeRange: TimeRange; diff --git a/src/legacy/core_plugins/kibana/public/visualize/plugin.ts b/src/legacy/core_plugins/kibana/public/visualize/plugin.ts index b9e4487ae84fbc..9d88152c59aa74 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/plugin.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/plugin.ts @@ -36,7 +36,7 @@ import { DataPublicPluginSetup, esFilters, } from '../../../../../plugins/data/public'; -import { IEmbeddableStart } from '../../../../../plugins/embeddable/public'; +import { EmbeddableStart } from '../../../../../plugins/embeddable/public'; import { NavigationPublicPluginStart as NavigationStart } from '../../../../../plugins/navigation/public'; import { SharePluginStart } from '../../../../../plugins/share/public'; import { @@ -55,7 +55,7 @@ import { DefaultEditorController } from '../../../vis_default_editor/public'; export interface VisualizePluginStartDependencies { data: DataPublicPluginStart; - embeddable: IEmbeddableStart; + embeddable: EmbeddableStart; navigation: NavigationStart; share: SharePluginStart; visualizations: VisualizationsStart; @@ -71,7 +71,7 @@ export interface VisualizePluginSetupDependencies { export class VisualizePlugin implements Plugin { private startDependencies: { data: DataPublicPluginStart; - embeddable: IEmbeddableStart; + embeddable: EmbeddableStart; navigation: NavigationStart; savedObjectsClient: SavedObjectsClientContract; share: SharePluginStart; diff --git a/src/legacy/core_plugins/kibana/ui_setting_defaults.js b/src/legacy/core_plugins/kibana/ui_setting_defaults.js index c0628b72c2ce7a..85b1956f453333 100644 --- a/src/legacy/core_plugins/kibana/ui_setting_defaults.js +++ b/src/legacy/core_plugins/kibana/ui_setting_defaults.js @@ -16,11 +16,13 @@ * specific language governing permissions and limitations * under the License. */ - import moment from 'moment-timezone'; import numeralLanguages from '@elastic/numeral/languages'; import { i18n } from '@kbn/i18n'; +import { schema } from '@kbn/config-schema'; + import { DEFAULT_QUERY_LANGUAGE } from '../../../plugins/data/common'; +import { isRelativeUrl } from '../../../core/utils'; export function getUiSettingDefaults() { const weekdays = moment.weekdays().slice(); @@ -67,17 +69,23 @@ export function getUiSettingDefaults() { defaultMessage: 'Default route', }), value: '/app/kibana', - validation: { - regexString: '^/', - message: i18n.translate('kbn.advancedSettings.defaultRoute.defaultRouteValidationMessage', { - defaultMessage: 'The route must start with a slash ("/")', - }), - }, + schema: schema.string({ + validate(value) { + if (!value.startsWith('/') || !isRelativeUrl(value)) { + return i18n.translate( + 'kbn.advancedSettings.defaultRoute.defaultRouteIsRelativeValidationMessage', + { + defaultMessage: 'Must be a relative URL.', + } + ); + } + }, + }), description: i18n.translate('kbn.advancedSettings.defaultRoute.defaultRouteText', { defaultMessage: 'This setting specifies the default route when opening Kibana. ' + 'You can use this setting to modify the landing page when opening Kibana. ' + - 'The route must start with a slash ("/").', + 'The route must be a relative URL.', }), }, 'query:queryString:options': { diff --git a/src/legacy/core_plugins/tests_bundle/tests_entry_template.js b/src/legacy/core_plugins/tests_bundle/tests_entry_template.js index 57adf730f3dd96..3e3dc284671da0 100644 --- a/src/legacy/core_plugins/tests_bundle/tests_entry_template.js +++ b/src/legacy/core_plugins/tests_bundle/tests_entry_template.js @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import { Type } from '@kbn/config-schema'; import pkg from '../../../../package.json'; export const createTestEntryTemplate = defaultUiSettings => bundle => ` @@ -87,7 +87,14 @@ const coreSystem = new CoreSystem({ buildNum: 1234, devMode: true, uiSettings: { - defaults: ${JSON.stringify(defaultUiSettings, null, 2) + defaults: ${JSON.stringify( + defaultUiSettings, + (key, value) => { + if (value instanceof Type) return null; + return value; + }, + 2 + ) .split('\n') .join('\n ')}, user: {} diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_common_props.ts b/src/legacy/core_plugins/vis_default_editor/public/components/agg_common_props.ts index b43894e74689f0..1a97cc5c4d967f 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_common_props.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_common_props.ts @@ -18,7 +18,7 @@ */ import { VisState, VisParams } from 'src/legacy/core_plugins/visualizations/public'; -import { IAggType, IAggConfig, AggGroupNames } from '../legacy_imports'; +import { IAggType, IAggConfig, IAggGroupNames } from '../legacy_imports'; import { Schema } from '../schemas'; type AggId = IAggConfig['id']; @@ -29,7 +29,7 @@ export type ReorderAggs = (sourceAgg: IAggConfig, destinationAgg: IAggConfig) => export interface DefaultEditorCommonProps { formIsTouched: boolean; - groupName: AggGroupNames; + groupName: IAggGroupNames; metricAggs: IAggConfig[]; state: VisState; setAggParamValue: ( diff --git a/src/legacy/core_plugins/vis_default_editor/public/legacy_imports.ts b/src/legacy/core_plugins/vis_default_editor/public/legacy_imports.ts index 33a5c0fe660c4a..50028d8c970f45 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/legacy_imports.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/legacy_imports.ts @@ -18,25 +18,25 @@ */ /* `ui/agg_types` dependencies */ +export { BUCKET_TYPES, METRIC_TYPES } from '../../../../plugins/data/public'; export { - AggType, - IAggType, - IAggConfig, - IAggConfigs, - AggParam, AggGroupNames, aggGroupNamesMap, + AggParam, + AggParamType, + AggType, aggTypes, createAggConfigs, FieldParamType, + IAggConfig, + IAggConfigs, + IAggGroupNames, + IAggType, IFieldParamType, - BUCKET_TYPES, - METRIC_TYPES, termsAggFilter, } from 'ui/agg_types'; export { aggTypeFilters, propFilter } from 'ui/agg_types'; export { aggTypeFieldFilters } from 'ui/agg_types'; -export { AggParamType } from 'ui/agg_types'; export { MetricAggType, IMetricAggType } from 'ui/agg_types'; export { parentPipelineType } from 'ui/agg_types'; export { siblingPipelineType } from 'ui/agg_types'; @@ -45,5 +45,3 @@ export { OptionedValueProp, OptionedParamEditorProps, OptionedParamType } from ' export { isValidInterval } from 'ui/agg_types'; export { AggParamOption } from 'ui/agg_types'; export { CidrMask } from 'ui/agg_types'; - -export * from 'ui/vis/lib'; diff --git a/src/legacy/core_plugins/vis_default_editor/public/schemas.ts b/src/legacy/core_plugins/vis_default_editor/public/schemas.ts index 5849d9d80011e2..94e3ad6023f4e4 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/schemas.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/schemas.ts @@ -22,8 +22,7 @@ import _ from 'lodash'; import { Optional } from '@kbn/utility-types'; import { IndexedArray } from 'ui/indexed_array'; -import { AggGroupNames } from '../../data/public/search/aggs/agg_groups'; -import { AggParam } from '../../data/public/search/aggs/agg_params'; +import { AggGroupNames, AggParam, IAggGroupNames } from '../../../../plugins/data/public'; export interface ISchemas { [AggGroupNames.Buckets]: Schema[]; @@ -34,7 +33,7 @@ export interface ISchemas { export interface Schema { aggFilter: string[]; editor: boolean | string; - group: AggGroupNames; + group: IAggGroupNames; max: number; min: number; name: string; diff --git a/src/legacy/core_plugins/vis_default_editor/public/utils.test.tsx b/src/legacy/core_plugins/vis_default_editor/public/utils.test.ts similarity index 100% rename from src/legacy/core_plugins/vis_default_editor/public/utils.test.tsx rename to src/legacy/core_plugins/vis_default_editor/public/utils.test.ts diff --git a/src/legacy/core_plugins/vis_default_editor/public/utils.tsx b/src/legacy/core_plugins/vis_default_editor/public/utils.ts similarity index 98% rename from src/legacy/core_plugins/vis_default_editor/public/utils.tsx rename to src/legacy/core_plugins/vis_default_editor/public/utils.ts index 4f82298aaca41f..60eeb49e201a06 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/utils.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/utils.ts @@ -39,7 +39,7 @@ export type ComboBoxGroupedOptions = Array>; * * @returns An array of grouped and sorted alphabetically `objects` that are compatible with EuiComboBox options. */ -function groupAndSortBy< +export function groupAndSortBy< T extends Record, TGroupBy extends string = 'type', TLabelName extends string = 'title' @@ -78,5 +78,3 @@ function groupAndSortBy< function sortByLabel(a: GroupOrOption, b: GroupOrOption) { return (a.label || '').toLowerCase().localeCompare((b.label || '').toLowerCase()); } - -export { groupAndSortBy }; diff --git a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_fn.test.ts b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_fn.test.ts index 4094cd4eff0601..3bddc94929cf57 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_fn.test.ts +++ b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_fn.test.ts @@ -23,6 +23,23 @@ import { functionWrapper } from '../../../../plugins/expressions/common/expressi jest.mock('ui/new_platform'); +jest.mock('../../vis_default_editor/public/legacy_imports', () => ({ + propFilter: jest.fn(), + AggGroupNames: { + Buckets: 'buckets', + Metrics: 'metrics', + }, + aggTypeFilters: { + addFilter: jest.fn(), + }, + BUCKET_TYPES: { + DATE_HISTOGRAM: 'date_histogram', + }, + METRIC_TYPES: { + TOP_HITS: 'top_hits', + }, +})); + describe('interpreter/functions#metric', () => { const fn = functionWrapper(createMetricVisFn()); const context = { diff --git a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts index 5dbd59f3f1709f..5813465cc3f00a 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts +++ b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts @@ -36,6 +36,23 @@ import { createMetricVisTypeDefinition } from './metric_vis_type'; jest.mock('ui/new_platform'); +jest.mock('../../vis_default_editor/public/legacy_imports', () => ({ + propFilter: jest.fn(), + AggGroupNames: { + Buckets: 'buckets', + Metrics: 'metrics', + }, + aggTypeFilters: { + addFilter: jest.fn(), + }, + BUCKET_TYPES: { + DATE_HISTOGRAM: 'date_histogram', + }, + METRIC_TYPES: { + TOP_HITS: 'top_hits', + }, +})); + describe('metric_vis - createMetricVisTypeDefinition', () => { let vis: Vis; diff --git a/src/legacy/core_plugins/vis_type_table/public/legacy_imports.ts b/src/legacy/core_plugins/vis_type_table/public/legacy_imports.ts index 90929150de9c39..7b584f8069338e 100644 --- a/src/legacy/core_plugins/vis_type_table/public/legacy_imports.ts +++ b/src/legacy/core_plugins/vis_type_table/public/legacy_imports.ts @@ -24,7 +24,8 @@ export { IAggConfig, AggGroupNames, Schemas } from 'ui/agg_types'; export { PaginateDirectiveProvider } from 'ui/directives/paginate'; // @ts-ignore export { PaginateControlsDirectiveProvider } from 'ui/directives/paginate'; -export { tabifyAggResponse, tabifyGetColumns } from '../../data/public'; +import { search } from '../../../../plugins/data/public'; +export const { tabifyAggResponse, tabifyGetColumns } = search; export { configureAppAngularModule, KbnAccessibleClickProvider, diff --git a/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_options.tsx b/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_options.tsx index ab7c2cd980c424..a9e816f70cf531 100644 --- a/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_options.tsx +++ b/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_options.tsx @@ -20,11 +20,10 @@ import React from 'react'; import { EuiPanel } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; - +import { ValidatedDualRange } from '../../../../../../src/plugins/kibana_react/public'; import { VisOptionsProps } from '../../../vis_default_editor/public'; import { SelectOption, SwitchOption } from '../../../vis_type_vislib/public'; import { TagCloudVisParams } from '../types'; -import { ValidatedDualRange } from '../legacy_imports'; function TagCloudOptions({ stateParams, setValue, vis }: VisOptionsProps) { const handleFontSizeChange = ([minFontSize, maxFontSize]: [string | number, string | number]) => { diff --git a/src/legacy/core_plugins/vis_type_tagcloud/public/legacy_imports.ts b/src/legacy/core_plugins/vis_type_tagcloud/public/legacy_imports.ts index d5b442bc5b3468..0d76bc5d8b68b0 100644 --- a/src/legacy/core_plugins/vis_type_tagcloud/public/legacy_imports.ts +++ b/src/legacy/core_plugins/vis_type_tagcloud/public/legacy_imports.ts @@ -18,5 +18,4 @@ */ export { Schemas } from 'ui/agg_types'; -export { ValidatedDualRange } from 'ui/validated_range'; export { getFormat } from 'ui/visualize/loader/pipeline_helpers/utilities'; diff --git a/src/legacy/core_plugins/vis_type_timelion/public/components/timelion_interval.tsx b/src/legacy/core_plugins/vis_type_timelion/public/components/timelion_interval.tsx index 13a57296bab7ac..6e29b111d422ac 100644 --- a/src/legacy/core_plugins/vis_type_timelion/public/components/timelion_interval.tsx +++ b/src/legacy/core_plugins/vis_type_timelion/public/components/timelion_interval.tsx @@ -21,7 +21,8 @@ import React, { useMemo, useCallback } from 'react'; import { EuiFormRow, EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { isValidEsInterval } from '../../../../core_plugins/data/common'; +import { search } from '../../../../../plugins/data/public'; +const { isValidEsInterval } = search.aggs; import { useValidation } from '../../../vis_default_editor/public'; const intervalOptions = [ diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/get_interval.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/get_interval.js index a6aefe067dd62b..f6ea90a3891d80 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/get_interval.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/lib/get_interval.js @@ -19,7 +19,8 @@ import moment from 'moment'; import { i18n } from '@kbn/i18n'; import { get } from 'lodash'; -import { parseEsInterval } from '../../../../data/public'; +import { search } from '../../../../../../plugins/data/public'; +const { parseEsInterval } = search.aggs; import { GTE_INTERVAL_RE } from '../../../../../../plugins/vis_type_timeseries/common/interval_regexp'; export const AUTO_INTERVAL = 'auto'; diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/lib/validate_interval.js b/src/legacy/core_plugins/vis_type_timeseries/public/lib/validate_interval.js index 2992549d38e308..40fd4d871a96a2 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/lib/validate_interval.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/lib/validate_interval.js @@ -19,7 +19,8 @@ import { GTE_INTERVAL_RE } from '../../../../../plugins/vis_type_timeseries/common/interval_regexp'; import { i18n } from '@kbn/i18n'; -import { parseInterval } from '../../../../../plugins/data/public'; +import { search } from '../../../../../plugins/data/public'; +const { parseInterval } = search.aggs; export function validateInterval(bounds, panel, maxBuckets) { const { interval } = panel; diff --git a/src/legacy/core_plugins/vis_type_vislib/public/legacy_imports.ts b/src/legacy/core_plugins/vis_type_vislib/public/legacy_imports.ts index 1c8e679f7d61f3..343fda44340d11 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/legacy_imports.ts +++ b/src/legacy/core_plugins/vis_type_vislib/public/legacy_imports.ts @@ -17,9 +17,12 @@ * under the License. */ +import { npStart } from 'ui/new_platform'; +export const { createFiltersFromEvent } = npStart.plugins.data.actions; export { AggType, AggGroupNames, IAggConfig, IAggType, Schemas } from 'ui/agg_types'; export { getFormat } from 'ui/visualize/loader/pipeline_helpers/utilities'; -export { tabifyAggResponse, tabifyGetColumns } from '../../data/public'; +import { search } from '../../../../plugins/data/public'; +export const { tabifyAggResponse, tabifyGetColumns } = search; // @ts-ignore export { buildHierarchicalData } from 'ui/agg_response/hierarchical/build_hierarchical_data'; // @ts-ignore diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx index e66dff01b6bf21..7f06bdddb48057 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx +++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.test.tsx @@ -32,10 +32,8 @@ jest.mock('@elastic/eui', () => ({ })); jest.mock('../../../legacy_imports', () => ({ - getTableAggs: jest.fn(), -})); -jest.mock('../../../../../data/public/actions/filters/create_filters_from_event', () => ({ createFiltersFromEvent: jest.fn().mockResolvedValue(['yes']), + getTableAggs: jest.fn(), })); const vis = { diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx index cfe3b0c6571477..d82941b7b8cee6 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx +++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx @@ -22,15 +22,14 @@ import { compact, uniq, map, every, isUndefined } from 'lodash'; import { i18n } from '@kbn/i18n'; import { EuiPopoverProps, EuiIcon, keyCodes, htmlIdGenerator } from '@elastic/eui'; -import { IAggConfig } from '../../../../../data/public'; -import { createFiltersFromEvent } from '../../../../../data/public/actions/filters/create_filters_from_event'; +import { IAggConfig } from '../../../../../../../plugins/data/public'; import { CUSTOM_LEGEND_VIS_TYPES, LegendItem } from './models'; import { VisLegendItem } from './legend_item'; import { getPieNames } from './pie_utils'; import { Vis } from '../../../../../visualizations/public'; -import { tabifyGetColumns } from '../../../legacy_imports'; +import { createFiltersFromEvent, tabifyGetColumns } from '../../../legacy_imports'; const getTableAggs = (vis: Vis): IAggConfig[] => { if (!vis.aggs || !vis.aggs.getResponseAggs) { diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/events.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/events.ts new file mode 100644 index 00000000000000..53d04bf6eb04ac --- /dev/null +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/events.ts @@ -0,0 +1,33 @@ +/* + * 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 { + SELECT_RANGE_TRIGGER, + VALUE_CLICK_TRIGGER, +} from '../../../../../../../plugins/ui_actions/public'; + +export interface VisEventToTrigger { + ['brush']: typeof SELECT_RANGE_TRIGGER; + ['filter']: typeof VALUE_CLICK_TRIGGER; +} + +export const VIS_EVENT_TO_TRIGGER: VisEventToTrigger = { + brush: SELECT_RANGE_TRIGGER, + filter: VALUE_CLICK_TRIGGER, +}; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/visualize_embeddable.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/visualize_embeddable.ts index 7525345ccfe1bd..c45e6832dc8362 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/visualize_embeddable.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/visualize_embeddable.ts @@ -34,8 +34,6 @@ import { EmbeddableOutput, Embeddable, Container, - selectRangeTrigger, - valueClickTrigger, EmbeddableVisTriggerContext, } from '../../../../../../../plugins/embeddable/public'; import { dispatchRenderComplete } from '../../../../../../../plugins/kibana_utils/public'; @@ -48,6 +46,7 @@ import { buildPipeline } from '../legacy/build_pipeline'; import { Vis } from '../vis'; import { getExpressions, getUiActions } from '../services'; import { VisSavedObject } from '../types'; +import { VIS_EVENT_TO_TRIGGER } from './events'; const getKeys = (o: T): Array => Object.keys(o) as Array; @@ -293,8 +292,8 @@ export class VisualizeEmbeddable extends Embeddable { const setup = plugin.setup(coreMock.createSetup(), { data: dataPluginMock.createSetupContract(), expressions: expressionsPluginMock.createSetupContract(), - embeddable: embeddablePluginMock.createStartContract(), + embeddable: embeddablePluginMock.createSetupContract(), usageCollection: usageCollectionPluginMock.createSetupContract(), }); const doStart = () => @@ -57,11 +57,6 @@ const createInstance = async () => { data: dataPluginMock.createStartContract(), expressions: expressionsPluginMock.createStartContract(), uiActions: uiActionsPluginMock.createStartContract(), - __LEGACY: { - aggs: { - createAggConfigs: jest.fn(), - } as any, - }, }); return { diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/plugin.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/plugin.ts index b8db611f30815f..953caecefb9748 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/plugin.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/plugin.ts @@ -42,7 +42,7 @@ import { } from './services'; import { VISUALIZE_EMBEDDABLE_TYPE, VisualizeEmbeddableFactory } from './embeddable'; import { ExpressionsSetup, ExpressionsStart } from '../../../../../../plugins/expressions/public'; -import { IEmbeddableSetup } from '../../../../../../plugins/embeddable/public'; +import { EmbeddableSetup } from '../../../../../../plugins/embeddable/public'; import { visualization as visualizationFunction } from './expressions/visualization_function'; import { visualization as visualizationRenderer } from './expressions/visualization_renderer'; import { @@ -55,7 +55,6 @@ import { createSavedVisLoader, SavedVisualizationsLoader } from './saved_visuali import { VisImpl } from './vis_impl'; import { showNewVisModal } from './wizard'; import { UiActionsStart } from '../../../../../../plugins/ui_actions/public'; -import { DataStart as LegacyDataStart } from '../../../../data/public'; import { VisState } from './types'; /** @@ -74,7 +73,7 @@ export interface VisualizationsStart extends TypesStart { export interface VisualizationsSetupDeps { expressions: ExpressionsSetup; - embeddable: IEmbeddableSetup; + embeddable: EmbeddableSetup; usageCollection: UsageCollectionSetup; data: DataPublicPluginSetup; } @@ -83,9 +82,6 @@ export interface VisualizationsStartDeps { data: DataPublicPluginStart; expressions: ExpressionsStart; uiActions: UiActionsStart; - __LEGACY: { - aggs: LegacyDataStart['search']['aggs']; - }; } /** @@ -128,7 +124,7 @@ export class VisualizationsPlugin public start( core: CoreStart, - { data, expressions, uiActions, __LEGACY: { aggs } }: VisualizationsStartDeps + { data, expressions, uiActions }: VisualizationsStartDeps ): VisualizationsStart { const types = this.types.start(); setI18n(core.i18n); @@ -141,7 +137,7 @@ export class VisualizationsPlugin setExpressions(expressions); setUiActions(uiActions); setTimeFilter(data.query.timefilter.timefilter); - setAggs(aggs); + setAggs(data.search.aggs); const savedVisualizationsLoader = createSavedVisLoader({ savedObjectsClient: core.savedObjects.client, indexPatterns: data.indexPatterns, diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/services.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/services.ts index 05fb106bf99402..b2eebe8b5b57d3 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/services.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/services.ts @@ -27,6 +27,7 @@ import { import { TypesStart } from './vis_types'; import { createGetterSetter } from '../../../../../../plugins/kibana_utils/public'; import { + DataPublicPluginStart, FilterManager, IndexPatternsContract, TimefilterContract, @@ -35,7 +36,6 @@ import { UsageCollectionSetup } from '../../../../../../plugins/usage_collection import { ExpressionsStart } from '../../../../../../plugins/expressions/public'; import { UiActionsStart } from '../../../../../../plugins/ui_actions/public'; import { SavedVisualizationsLoader } from './saved_visualizations'; -import { DataStart as LegacyDataStart } from '../../../../data/public'; export const [getUISettings, setUISettings] = createGetterSetter('UISettings'); @@ -73,6 +73,6 @@ export const [getSavedVisualizationsLoader, setSavedVisualizationsLoader] = crea SavedVisualizationsLoader >('SavedVisualisationsLoader'); -export const [getAggs, setAggs] = createGetterSetter( +export const [getAggs, setAggs] = createGetterSetter( 'AggConfigs' ); diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.ts index ba86125f2e246e..eb262966a4a22e 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.ts @@ -19,7 +19,7 @@ import { VisType } from './vis_types'; import { Status } from './legacy/update_status'; -import { IAggConfigs } from '../../../../data/public'; +import { IAggConfigs } from '../../../../../../plugins/data/public'; export interface Vis { type: VisType; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_impl.d.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_impl.d.ts index 0c4ea1572c4cdc..0e759c3d9872c3 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_impl.d.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_impl.d.ts @@ -19,9 +19,8 @@ import { Vis, VisState, VisParams } from './vis'; import { VisType } from './vis_types'; -import { IIndexPattern } from '../../../../../../plugins/data/common'; +import { IAggConfig, IIndexPattern } from '../../../../../../plugins/data/public'; import { Schema } from '../../../../vis_default_editor/public'; -import { IAggConfig } from '../../../../data/public/search/aggs'; type InitVisStateType = | Partial diff --git a/src/legacy/server/http/index.js b/src/legacy/server/http/index.js index 265d71e95b301f..d616afb533d0a8 100644 --- a/src/legacy/server/http/index.js +++ b/src/legacy/server/http/index.js @@ -24,15 +24,12 @@ import Boom from 'boom'; import { registerHapiPlugins } from './register_hapi_plugins'; import { setupBasePathProvider } from './setup_base_path_provider'; -import { setupDefaultRouteProvider } from './setup_default_route_provider'; export default async function(kbnServer, server, config) { server = kbnServer.server; setupBasePathProvider(kbnServer); - setupDefaultRouteProvider(server); - await registerHapiPlugins(server); // provide a simple way to expose static directories @@ -60,14 +57,6 @@ export default async function(kbnServer, server, config) { }); }); - server.route({ - path: '/', - method: 'GET', - async handler(req, h) { - return h.redirect(await req.getDefaultRoute()); - }, - }); - server.route({ method: 'GET', path: '/{p*}', diff --git a/src/legacy/server/http/integration_tests/default_route_provider.test.ts b/src/legacy/server/http/integration_tests/default_route_provider.test.ts deleted file mode 100644 index d91438d904558b..00000000000000 --- a/src/legacy/server/http/integration_tests/default_route_provider.test.ts +++ /dev/null @@ -1,87 +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. - */ -jest.mock('../../../ui/ui_settings/ui_settings_mixin', () => { - return jest.fn(); -}); - -import * as kbnTestServer from '../../../../test_utils/kbn_server'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { Root } from '../../../../core/server/root'; - -let mockDefaultRouteSetting: any = ''; - -describe('default route provider', () => { - let root: Root; - beforeAll(async () => { - root = kbnTestServer.createRoot({ migrations: { skip: true } }); - - await root.setup(); - await root.start(); - - const kbnServer = kbnTestServer.getKbnServer(root); - - kbnServer.server.decorate('request', 'getUiSettingsService', function() { - return { - get: (key: string) => { - if (key === 'defaultRoute') { - return Promise.resolve(mockDefaultRouteSetting); - } - throw Error(`unsupported ui setting: ${key}`); - }, - getRegistered: () => { - return { - defaultRoute: { - value: '/app/kibana', - }, - }; - }, - }; - }); - }, 30000); - - afterAll(async () => await root.shutdown()); - - it('redirects to the configured default route', async function() { - mockDefaultRouteSetting = '/app/some/default/route'; - - const { status, header } = await kbnTestServer.request.get(root, '/'); - expect(status).toEqual(302); - expect(header).toMatchObject({ - location: '/app/some/default/route', - }); - }); - - const invalidRoutes = [ - 'http://not-your-kibana.com', - '///example.com', - '//example.com', - ' //example.com', - ]; - for (const route of invalidRoutes) { - it(`falls back to /app/kibana when the configured route (${route}) is not a valid relative path`, async function() { - mockDefaultRouteSetting = route; - - const { status, header } = await kbnTestServer.request.get(root, '/'); - expect(status).toEqual(302); - expect(header).toMatchObject({ - location: '/app/kibana', - }); - }); - } -}); diff --git a/src/legacy/server/http/integration_tests/default_route_provider_config.test.ts b/src/legacy/server/http/integration_tests/default_route_provider_config.test.ts deleted file mode 100644 index 8365941cbeb10e..00000000000000 --- a/src/legacy/server/http/integration_tests/default_route_provider_config.test.ts +++ /dev/null @@ -1,54 +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 * as kbnTestServer from '../../../../test_utils/kbn_server'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { Root } from '../../../../core/server/root'; - -describe('default route provider', () => { - let root: Root; - - afterEach(async () => await root.shutdown()); - - it('redirects to the configured default route', async function() { - root = kbnTestServer.createRoot({ - server: { - defaultRoute: '/app/some/default/route', - }, - migrations: { skip: true }, - }); - - await root.setup(); - await root.start(); - - const kbnServer = kbnTestServer.getKbnServer(root); - - kbnServer.server.decorate('request', 'getSavedObjectsClient', function() { - return { - get: (type: string, id: string) => ({ attributes: {} }), - }; - }); - - const { status, header } = await kbnTestServer.request.get(root, '/'); - - expect(status).toEqual(302); - expect(header).toMatchObject({ - location: '/app/some/default/route', - }); - }); -}); diff --git a/src/legacy/server/http/setup_default_route_provider.ts b/src/legacy/server/http/setup_default_route_provider.ts deleted file mode 100644 index 9a580dd1c59bdc..00000000000000 --- a/src/legacy/server/http/setup_default_route_provider.ts +++ /dev/null @@ -1,74 +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 { Legacy } from 'kibana'; -import { parse } from 'url'; - -export function setupDefaultRouteProvider(server: Legacy.Server) { - server.decorate('request', 'getDefaultRoute', async function() { - // @ts-ignore - const request: Legacy.Request = this; - - const serverBasePath: string = server.config().get('server.basePath'); - - const uiSettings = request.getUiSettingsService(); - - const defaultRoute = await uiSettings.get('defaultRoute'); - const qualifiedDefaultRoute = `${request.getBasePath()}${defaultRoute}`; - - if (isRelativePath(qualifiedDefaultRoute, serverBasePath)) { - return qualifiedDefaultRoute; - } else { - server.log( - ['http', 'warn'], - `Ignoring configured default route of '${defaultRoute}', as it is malformed.` - ); - - const fallbackRoute = uiSettings.getRegistered().defaultRoute.value; - - const qualifiedFallbackRoute = `${request.getBasePath()}${fallbackRoute}`; - return qualifiedFallbackRoute; - } - }); - - function isRelativePath(candidatePath: string, basePath = '') { - // validate that `candidatePath` is not attempting a redirect to somewhere - // outside of this Kibana install - const { protocol, hostname, port, pathname } = parse( - candidatePath, - false /* parseQueryString */, - true /* slashesDenoteHost */ - ); - - // We should explicitly compare `protocol`, `port` and `hostname` to null to make sure these are not - // detected in the URL at all. For example `hostname` can be empty string for Node URL parser, but - // browser (because of various bwc reasons) processes URL differently (e.g. `///abc.com` - for browser - // hostname is `abc.com`, but for Node hostname is an empty string i.e. everything between schema (`//`) - // and the first slash that belongs to path. - if (protocol !== null || hostname !== null || port !== null) { - return false; - } - - if (!String(pathname).startsWith(basePath)) { - return false; - } - - return true; - } -} diff --git a/src/legacy/server/kbn_server.d.ts b/src/legacy/server/kbn_server.d.ts index 68b5a63871372b..9952b345fa06ff 100644 --- a/src/legacy/server/kbn_server.d.ts +++ b/src/legacy/server/kbn_server.d.ts @@ -92,7 +92,6 @@ declare module 'hapi' { interface Request { getSavedObjectsClient(options?: SavedObjectsClientProviderOptions): SavedObjectsClientContract; getBasePath(): string; - getDefaultRoute(): Promise; getUiSettingsService(): IUiSettingsClient; } diff --git a/src/legacy/ui/public/agg_response/index.js b/src/legacy/ui/public/agg_response/index.js index 139a124356de21..982c1c25a81010 100644 --- a/src/legacy/ui/public/agg_response/index.js +++ b/src/legacy/ui/public/agg_response/index.js @@ -19,10 +19,10 @@ import { buildHierarchicalData } from './hierarchical/build_hierarchical_data'; import { buildPointSeriesData } from './point_series/point_series'; -import { tabifyAggResponse } from '../../../core_plugins/data/public'; +import { search } from '../../../../plugins/data/public'; export const aggResponseIndex = { hierarchical: buildHierarchicalData, pointSeries: buildPointSeriesData, - tabify: tabifyAggResponse, + tabify: search.tabifyAggResponse, }; diff --git a/src/legacy/ui/public/agg_types/index.ts b/src/legacy/ui/public/agg_types/index.ts index d066e61df18e90..75c2cd43178726 100644 --- a/src/legacy/ui/public/agg_types/index.ts +++ b/src/legacy/ui/public/agg_types/index.ts @@ -20,16 +20,16 @@ /** * Nothing to see here! * - * Agg Types have moved to the data plugin, and are being + * Agg Types have moved to the new platform, and are being * re-exported from ui/agg_types for backwards compatibility. */ -import { start as dataStart } from '../../../core_plugins/data/public/legacy'; +import { npStart } from 'ui/new_platform'; // runtime contracts -const { types } = dataStart.search.aggs; +const { types } = npStart.plugins.data.search.aggs; export const aggTypes = types.getAll(); -export const { createAggConfigs } = dataStart.search.aggs; +export const { createAggConfigs } = npStart.plugins.data.search.aggs; export const { AggConfig, AggType, @@ -38,33 +38,36 @@ export const { MetricAggType, parentPipelineAggHelper, siblingPipelineAggHelper, -} = dataStart.search.aggs.__LEGACY; +} = npStart.plugins.data.search.__LEGACY; // types export { + AggGroupNames, + AggParam, + AggParamOption, + AggParamType, + AggTypeFieldFilters, + AggTypeFilters, + BUCKET_TYPES, + DateRangeKey, IAggConfig, IAggConfigs, + IAggGroupNames, IAggType, IFieldParamType, IMetricAggType, - AggParam, - AggParamOption, - BUCKET_TYPES, - DateRangeKey, IpRangeKey, METRIC_TYPES, OptionedParamEditorProps, + OptionedParamType, OptionedValueProp, -} from '../../../core_plugins/data/public'; +} from '../../../../plugins/data/public'; // static code -export { - AggParamType, - AggTypeFilters, - aggTypeFilters, - AggTypeFieldFilters, - AggGroupNames, +import { search } from '../../../../plugins/data/public'; +export const { aggGroupNamesMap, + aggTypeFilters, CidrMask, convertDateRangeToString, convertIPRangeToString, @@ -73,11 +76,10 @@ export { isStringType, isType, isValidInterval, - OptionedParamType, parentPipelineType, propFilter, siblingPipelineType, termsAggFilter, -} from '../../../core_plugins/data/public'; +} = search.aggs; export { ISchemas, Schemas, Schema } from '../../../core_plugins/vis_default_editor/public/schemas'; diff --git a/src/legacy/ui/public/chrome/directives/kbn_chrome.js b/src/legacy/ui/public/chrome/directives/kbn_chrome.js index 4c5d7981e962ac..45da4ab6b7472e 100644 --- a/src/legacy/ui/public/chrome/directives/kbn_chrome.js +++ b/src/legacy/ui/public/chrome/directives/kbn_chrome.js @@ -20,6 +20,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import $ from 'jquery'; +import { fatalError } from 'ui/notify/fatal_error'; import { uiModules } from '../../modules'; import template from './kbn_chrome.html'; @@ -30,7 +31,7 @@ import { chromeHeaderNavControlsRegistry, NavControlSide, } from '../../registry/chrome_header_nav_controls'; -import { subscribeWithScope } from '../../utils/subscribe_with_scope'; +import { subscribeWithScope } from '../../../../../plugins/kibana_legacy/public'; export function kbnChromeProvider(chrome, internals) { uiModules.get('kibana').directive('kbnChrome', () => { @@ -84,11 +85,16 @@ export function kbnChromeProvider(chrome, internals) { ); } - const chromeVisibility = subscribeWithScope($scope, chrome.visible$, { - next: () => { - // just makes sure change detection is triggered when chrome visibility changes + const chromeVisibility = subscribeWithScope( + $scope, + chrome.visible$, + { + next: () => { + // just makes sure change detection is triggered when chrome visibility changes + }, }, - }); + fatalError + ); $scope.$on('$destroy', () => { chromeVisibility.unsubscribe(); }); diff --git a/src/legacy/ui/public/config/config.js b/src/legacy/ui/public/config/config.js index 28379c4feb94d4..80a9d39221b2c2 100644 --- a/src/legacy/ui/public/config/config.js +++ b/src/legacy/ui/public/config/config.js @@ -18,10 +18,11 @@ */ import angular from 'angular'; +import { fatalError } from 'ui/notify/fatal_error'; import chrome from '../chrome'; import { isPlainObject } from 'lodash'; import { uiModules } from '../modules'; -import { subscribeWithScope } from '../utils/subscribe_with_scope'; +import { subscribeWithScope } from '../../../../plugins/kibana_legacy/public'; const module = uiModules.get('kibana/config'); @@ -52,12 +53,17 @@ module.service(`config`, function($rootScope, Promise) { //* angular specific methods * ////////////////////////////// - const subscription = subscribeWithScope($rootScope, uiSettings.getUpdate$(), { - next: ({ key, newValue, oldValue }) => { - $rootScope.$broadcast('change:config', newValue, oldValue, key, this); - $rootScope.$broadcast(`change:config.${key}`, newValue, oldValue, key, this); + const subscription = subscribeWithScope( + $rootScope, + uiSettings.getUpdate$(), + { + next: ({ key, newValue, oldValue }) => { + $rootScope.$broadcast('change:config', newValue, oldValue, key, this); + $rootScope.$broadcast(`change:config.${key}`, newValue, oldValue, key, this); + }, }, - }); + fatalError + ); $rootScope.$on('$destroy', () => subscription.unsubscribe()); this.watchAll = function(handler, scope = $rootScope) { 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 89617c20a31b7f..ea84ba1ad28387 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 @@ -20,6 +20,24 @@ import sinon from 'sinon'; import { getFieldFormatsRegistry } from '../../../../test_utils/public/stub_field_formats'; import { METRIC_TYPE } from '@kbn/analytics'; +import { + setIndexPatterns, + setQueryService, + setUiSettings, + setInjectedMetadata, + setFieldFormats, + setSearchService, + setOverlays, + // eslint-disable-next-line @kbn/eslint/no-restricted-paths +} from '../../../../plugins/data/public/services'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { setAggs } from '../../../../../src/legacy/core_plugins/visualizations/public/np_ready/public/services'; +import { + AggTypesRegistry, + getAggTypes, + AggConfigs, + // eslint-disable-next-line @kbn/eslint/no-restricted-paths +} from '../../../../../src/plugins/data/public/search/aggs'; import { ComponentRegistry } from '../../../../../src/plugins/advanced_settings/public/'; const mockObservable = () => { @@ -61,6 +79,18 @@ const mockCore = { }, }; +const mockAggTypesRegistry = () => { + const registry = new AggTypesRegistry(); + const registrySetup = registry.setup(); + const aggTypes = getAggTypes({ uiSettings: mockCore.uiSettings }); + aggTypes.buckets.forEach(type => registrySetup.registerBucket(type)); + aggTypes.metrics.forEach(type => registrySetup.registerMetric(type)); + + return registry; +}; + +const aggTypesRegistry = mockAggTypesRegistry(); + let refreshInterval = undefined; let isTimeRangeSelectorEnabled = true; let isAutoRefreshSelectorEnabled = true; @@ -169,10 +199,16 @@ export const npSetup = { getSavedQueryCount: sinon.fake(), }, }, - __LEGACY: { - esClient: { - search: sinon.fake(), - msearch: sinon.fake(), + search: { + aggs: { + calculateAutoTimeExpression: sinon.fake(), + types: aggTypesRegistry.setup(), + }, + __LEGACY: { + esClient: { + search: sinon.fake(), + msearch: sinon.fake(), + }, }, }, fieldFormats: getFieldFormatsRegistry(mockCore), @@ -233,6 +269,9 @@ export const npSetup = { }), }, }, + visTypeVega: { + config: sinon.fake(), + }, }, }; @@ -284,6 +323,9 @@ export const npStart = { }, }, data: { + actions: { + createFiltersFromEvent: Promise.resolve(['yes']), + }, autocomplete: { getProvider: sinon.fake(), }, @@ -355,7 +397,27 @@ export const npStart = { }, }, search: { + aggs: { + calculateAutoTimeExpression: sinon.fake(), + createAggConfigs: sinon.fake(), + createAggConfigs: (indexPattern, configStates = []) => { + return new AggConfigs(indexPattern, configStates, { + typesRegistry: aggTypesRegistry.start(), + }); + }, + types: aggTypesRegistry.start(), + }, __LEGACY: { + AggConfig: sinon.fake(), + AggType: sinon.fake(), + aggTypeFieldFilters: { + addFilter: sinon.fake(), + filter: sinon.fake(), + }, + FieldParamType: sinon.fake(), + MetricAggType: sinon.fake(), + parentPipelineAggHelper: sinon.fake(), + siblingPipelineAggHelper: sinon.fake(), esClient: { search: sinon.fake(), msearch: sinon.fake(), @@ -404,8 +466,22 @@ export function __setup__(coreSetup) { // no-op application register calls (this is overwritten to // bootstrap an LP plugin outside of tests) npSetup.core.application.register = () => {}; + + // Services that need to be set in the legacy platform since the legacy data plugin + // which previously provided them has been removed. + setInjectedMetadata(npSetup.core.injectedMetadata); } export function __start__(coreStart) { npStart.core = coreStart; + + // Services that need to be set in the legacy platform since the legacy data plugin + // which previously provided them has been removed. + setUiSettings(npStart.core.uiSettings); + setQueryService(npStart.plugins.data.query); + setIndexPatterns(npStart.plugins.data.indexPatterns); + setFieldFormats(npStart.plugins.data.fieldFormats); + setSearchService(npStart.plugins.data.search); + setAggs(npStart.plugins.data.search.aggs); + setOverlays(npStart.core.overlays); } diff --git a/src/legacy/ui/public/new_platform/new_platform.ts b/src/legacy/ui/public/new_platform/new_platform.ts index c5369b00f9f762..07e17ad5622918 100644 --- a/src/legacy/ui/public/new_platform/new_platform.ts +++ b/src/legacy/ui/public/new_platform/new_platform.ts @@ -16,10 +16,11 @@ * specific language governing permissions and limitations * under the License. */ + import { IScope } from 'angular'; import { UiActionsStart, UiActionsSetup } from 'src/plugins/ui_actions/public'; -import { IEmbeddableStart, IEmbeddableSetup } from 'src/plugins/embeddable/public'; +import { EmbeddableStart, EmbeddableSetup } from 'src/plugins/embeddable/public'; import { createBrowserHistory } from 'history'; import { LegacyCoreSetup, @@ -29,6 +30,16 @@ import { ScopedHistory, } from '../../../../core/public'; import { Plugin as DataPlugin } from '../../../../plugins/data/public'; +import { + setIndexPatterns, + setQueryService, + setUiSettings, + setInjectedMetadata, + setFieldFormats, + setSearchService, + setOverlays, + // eslint-disable-next-line @kbn/eslint/no-restricted-paths +} from '../../../../plugins/data/public/services'; import { Plugin as ExpressionsPlugin } from '../../../../plugins/expressions/public'; import { Setup as InspectorSetup, @@ -57,7 +68,7 @@ export interface PluginsSetup { bfetch: BfetchPublicSetup; charts: ChartsPluginSetup; data: ReturnType; - embeddable: IEmbeddableSetup; + embeddable: EmbeddableSetup; expressions: ReturnType; home: HomePublicPluginSetup; inspector: InspectorSetup; @@ -77,7 +88,7 @@ export interface PluginsStart { bfetch: BfetchPublicStart; charts: ChartsPluginStart; data: ReturnType; - embeddable: IEmbeddableStart; + embeddable: EmbeddableStart; expressions: ReturnType; inspector: InspectorStart; uiActions: UiActionsStart; @@ -118,11 +129,24 @@ export function __setup__(coreSetup: LegacyCoreSetup, plugins: PluginsSetup) { // Setup compatibility layer for AppService in legacy platform npSetup.core.application.register = legacyAppRegister; + + // Services that need to be set in the legacy platform since the legacy data plugin + // which previously provided them has been removed. + setInjectedMetadata(npSetup.core.injectedMetadata); } export function __start__(coreStart: LegacyCoreStart, plugins: PluginsStart) { npStart.core = coreStart; npStart.plugins = plugins; + + // Services that need to be set in the legacy platform since the legacy data plugin + // which previously provided them has been removed. + setUiSettings(npStart.core.uiSettings); + setQueryService(npStart.plugins.data.query); + setIndexPatterns(npStart.plugins.data.indexPatterns); + setFieldFormats(npStart.plugins.data.fieldFormats); + setSearchService(npStart.plugins.data.search); + setOverlays(npStart.core.overlays); } /** Flag used to ensure `legacyAppRegister` is only called once. */ diff --git a/src/legacy/ui/public/notify/fatal_error.ts b/src/legacy/ui/public/notify/fatal_error.ts index 7fa2ae7ac6fe6a..5614ffea7913e7 100644 --- a/src/legacy/ui/public/notify/fatal_error.ts +++ b/src/legacy/ui/public/notify/fatal_error.ts @@ -18,23 +18,8 @@ */ import { npSetup } from 'ui/new_platform'; -import { - AngularHttpError, - formatAngularHttpError, - isAngularHttpError, -} from '../../../../plugins/kibana_legacy/public'; - -export function addFatalErrorCallback(callback: () => void) { - npSetup.core.fatalErrors.get$().subscribe(() => { - callback(); - }); -} +import { AngularHttpError, addFatalError } from '../../../../plugins/kibana_legacy/public'; export function fatalError(error: AngularHttpError | Error | string, location?: string) { - // add support for angular http errors to newPlatformFatalErrors - if (isAngularHttpError(error)) { - error = formatAngularHttpError(error); - } - - npSetup.core.fatalErrors.add(error, location); + addFatalError(npSetup.core.fatalErrors, error, location); } diff --git a/src/legacy/ui/public/notify/index.js b/src/legacy/ui/public/notify/index.js index 7ec6a394d7e885..51394033e4d2e0 100644 --- a/src/legacy/ui/public/notify/index.js +++ b/src/legacy/ui/public/notify/index.js @@ -17,6 +17,6 @@ * under the License. */ -export { fatalError, addFatalErrorCallback } from './fatal_error'; +export { fatalError } from './fatal_error'; export { toastNotifications } from './toasts'; export { banners } from './banners'; diff --git a/src/legacy/ui/public/timefilter/setup_router.test.js b/src/legacy/ui/public/timefilter/setup_router.test.js index 46465f3a89ef08..2ae9a053ae2db1 100644 --- a/src/legacy/ui/public/timefilter/setup_router.test.js +++ b/src/legacy/ui/public/timefilter/setup_router.test.js @@ -18,7 +18,7 @@ */ import { registerTimefilterWithGlobalState } from './setup_router'; -jest.mock('ui/utils/subscribe_with_scope', () => ({ +jest.mock('../../../../plugins/kibana_legacy/public', () => ({ subscribeWithScope: jest.fn(), })); diff --git a/src/legacy/ui/public/timefilter/setup_router.ts b/src/legacy/ui/public/timefilter/setup_router.ts index 64105b016fb44c..a7492e538b3af1 100644 --- a/src/legacy/ui/public/timefilter/setup_router.ts +++ b/src/legacy/ui/public/timefilter/setup_router.ts @@ -20,10 +20,11 @@ import _ from 'lodash'; import { IScope } from 'angular'; import moment from 'moment'; -import { subscribeWithScope } from 'ui/utils/subscribe_with_scope'; import chrome from 'ui/chrome'; import { RefreshInterval, TimeRange, TimefilterContract } from 'src/plugins/data/public'; import { Subscription } from 'rxjs'; +import { fatalError } from 'ui/notify/fatal_error'; +import { subscribeWithScope } from '../../../../plugins/kibana_legacy/public'; // TODO // remove everything underneath once globalState is no longer an angular service @@ -79,15 +80,25 @@ export const registerTimefilterWithGlobalStateFactory = ( const subscriptions = new Subscription(); subscriptions.add( - subscribeWithScope($rootScope, timefilter.getRefreshIntervalUpdate$(), { - next: updateGlobalStateWithTime, - }) + subscribeWithScope( + $rootScope, + timefilter.getRefreshIntervalUpdate$(), + { + next: updateGlobalStateWithTime, + }, + fatalError + ) ); subscriptions.add( - subscribeWithScope($rootScope, timefilter.getTimeUpdate$(), { - next: updateGlobalStateWithTime, - }) + subscribeWithScope( + $rootScope, + timefilter.getTimeUpdate$(), + { + next: updateGlobalStateWithTime, + }, + fatalError + ) ); $rootScope.$on('$destroy', () => { diff --git a/src/legacy/ui/public/utils/subscribe_with_scope.test.mocks.ts b/src/legacy/ui/public/utils/subscribe_with_scope.test.mocks.ts deleted file mode 100644 index 815d2f09150c7a..00000000000000 --- a/src/legacy/ui/public/utils/subscribe_with_scope.test.mocks.ts +++ /dev/null @@ -1,23 +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. - */ - -export const mockFatalError = jest.fn(); -jest.mock('ui/notify/fatal_error', () => ({ - fatalError: mockFatalError, -})); diff --git a/src/legacy/ui/public/vis/lib/index.ts b/src/legacy/ui/public/vis/lib/index.ts deleted file mode 100644 index ce44ad71e4bd87..00000000000000 --- a/src/legacy/ui/public/vis/lib/index.ts +++ /dev/null @@ -1,21 +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. - */ - -export { leastCommonInterval } from './least_common_interval'; -export { leastCommonMultiple } from './least_common_multiple'; diff --git a/src/plugins/advanced_settings/public/management_app/advanced_settings.test.tsx b/src/plugins/advanced_settings/public/management_app/advanced_settings.test.tsx index 7a2ab648ec2586..6103041cf0a4c8 100644 --- a/src/plugins/advanced_settings/public/management_app/advanced_settings.test.tsx +++ b/src/plugins/advanced_settings/public/management_app/advanced_settings.test.tsx @@ -22,7 +22,11 @@ import { Observable } from 'rxjs'; import { ReactWrapper } from 'enzyme'; import { mountWithI18nProvider } from 'test_utils/enzyme_helpers'; import dedent from 'dedent'; -import { UiSettingsParams, UserProvidedValues, UiSettingsType } from '../../../../core/public'; +import { + PublicUiSettingsParams, + UserProvidedValues, + UiSettingsType, +} from '../../../../core/public'; import { FieldSetting } from './types'; import { AdvancedSettingsComponent } from './advanced_settings'; import { notificationServiceMock, docLinksServiceMock } from '../../../../core/public/mocks'; @@ -68,7 +72,7 @@ function mockConfig() { remove: (key: string) => Promise.resolve(true), isCustom: (key: string) => false, isOverridden: (key: string) => Boolean(config.getAll()[key].isOverridden), - getRegistered: () => ({} as Readonly>), + getRegistered: () => ({} as Readonly>), overrideLocalDefault: (key: string, value: any) => {}, getUpdate$: () => new Observable<{ @@ -89,7 +93,7 @@ function mockConfig() { getUpdateErrors$: () => new Observable(), get: (key: string, defaultOverride?: any): any => config.getAll()[key] || defaultOverride, get$: (key: string) => new Observable(config.get(key)), - getAll: (): Readonly> => { + getAll: (): Readonly> => { return { 'test:array:setting': { ...defaultConfig, diff --git a/src/plugins/advanced_settings/public/management_app/lib/to_editable_config.test.ts b/src/plugins/advanced_settings/public/management_app/lib/to_editable_config.test.ts index 881a2eb003cc81..7ac9b281eb99aa 100644 --- a/src/plugins/advanced_settings/public/management_app/lib/to_editable_config.test.ts +++ b/src/plugins/advanced_settings/public/management_app/lib/to_editable_config.test.ts @@ -17,7 +17,7 @@ * under the License. */ -import { UiSettingsParams, StringValidationRegex } from 'src/core/public'; +import { PublicUiSettingsParams, StringValidationRegex } from 'src/core/public'; import expect from '@kbn/expect'; import { toEditableConfig } from './to_editable_config'; @@ -30,7 +30,7 @@ function invoke({ name = 'woah', value = 'forreal', }: { - def?: UiSettingsParams & { isOverridden?: boolean }; + def?: PublicUiSettingsParams & { isOverridden?: boolean }; name?: string; value?: any; }) { @@ -55,7 +55,7 @@ describe('Settings', function() { }); describe('when given a setting definition object', function() { - let def: UiSettingsParams & { isOverridden?: boolean }; + let def: PublicUiSettingsParams & { isOverridden?: boolean }; beforeEach(function() { def = { value: 'the original', diff --git a/src/plugins/advanced_settings/public/management_app/lib/to_editable_config.ts b/src/plugins/advanced_settings/public/management_app/lib/to_editable_config.ts index 2c27d72f7f645a..406bc35f826e84 100644 --- a/src/plugins/advanced_settings/public/management_app/lib/to_editable_config.ts +++ b/src/plugins/advanced_settings/public/management_app/lib/to_editable_config.ts @@ -18,7 +18,7 @@ */ import { - UiSettingsParams, + PublicUiSettingsParams, UserProvidedValues, StringValidationRegexString, SavedObjectAttribute, @@ -40,7 +40,7 @@ export function toEditableConfig({ isCustom, isOverridden, }: { - def: UiSettingsParams & UserProvidedValues; + def: PublicUiSettingsParams & UserProvidedValues; name: string; value: SavedObjectAttribute; isCustom: boolean; diff --git a/src/plugins/advanced_settings/public/management_app/types.ts b/src/plugins/advanced_settings/public/management_app/types.ts index d44a05ce36f5d2..ee9b9b0535b794 100644 --- a/src/plugins/advanced_settings/public/management_app/types.ts +++ b/src/plugins/advanced_settings/public/management_app/types.ts @@ -17,17 +17,12 @@ * under the License. */ -import { - UiSettingsType, - StringValidation, - ImageValidation, - SavedObjectAttribute, -} from '../../../../core/public'; +import { UiSettingsType, StringValidation, ImageValidation } from '../../../../core/public'; export interface FieldSetting { displayName: string; name: string; - value: SavedObjectAttribute; + value: unknown; description?: string; options?: string[]; optionLabels?: Record; @@ -36,7 +31,7 @@ export interface FieldSetting { category: string[]; ariaName: string; isOverridden: boolean; - defVal: SavedObjectAttribute; + defVal: unknown; isCustom: boolean; validation?: StringValidation | ImageValidation; readOnly?: boolean; diff --git a/src/plugins/dashboard_embeddable_container/kibana.json b/src/plugins/dashboard/kibana.json similarity index 81% rename from src/plugins/dashboard_embeddable_container/kibana.json rename to src/plugins/dashboard/kibana.json index 70e37ea6a6d7dc..e5a657555819a4 100644 --- a/src/plugins/dashboard_embeddable_container/kibana.json +++ b/src/plugins/dashboard/kibana.json @@ -1,5 +1,5 @@ { - "id": "dashboard_embeddable_container", + "id": "dashboard", "version": "kibana", "requiredPlugins": [ "data", diff --git a/src/plugins/dashboard_embeddable_container/public/actions/expand_panel_action.test.tsx b/src/plugins/dashboard/public/actions/expand_panel_action.test.tsx similarity index 97% rename from src/plugins/dashboard_embeddable_container/public/actions/expand_panel_action.test.tsx rename to src/plugins/dashboard/public/actions/expand_panel_action.test.tsx index f8c05170e8f672..22cf854a46623e 100644 --- a/src/plugins/dashboard_embeddable_container/public/actions/expand_panel_action.test.tsx +++ b/src/plugins/dashboard/public/actions/expand_panel_action.test.tsx @@ -28,7 +28,6 @@ import { ContactCardEmbeddableInput, ContactCardEmbeddableOutput, } from '../embeddable_plugin_test_samples'; -import { DashboardOptions } from '../embeddable/dashboard_container_factory'; const embeddableFactories = new Map(); embeddableFactories.set( @@ -40,7 +39,7 @@ let container: DashboardContainer; let embeddable: ContactCardEmbeddable; beforeEach(async () => { - const options: DashboardOptions = { + const options = { ExitFullScreenButton: () => null, SavedObjectFinder: () => null, application: {} as any, diff --git a/src/plugins/dashboard_embeddable_container/public/actions/expand_panel_action.tsx b/src/plugins/dashboard/public/actions/expand_panel_action.tsx similarity index 87% rename from src/plugins/dashboard_embeddable_container/public/actions/expand_panel_action.tsx rename to src/plugins/dashboard/public/actions/expand_panel_action.tsx index cf245178306d50..27d4078411564e 100644 --- a/src/plugins/dashboard_embeddable_container/public/actions/expand_panel_action.tsx +++ b/src/plugins/dashboard/public/actions/expand_panel_action.tsx @@ -53,18 +53,12 @@ export class ExpandPanelAction implements ActionByType; notifications: CoreStart['notifications']; panelToRemove: IEmbeddable; - getEmbeddableFactories: IEmbeddableStart['getEmbeddableFactories']; + getEmbeddableFactories: EmbeddableStart['getEmbeddableFactories']; }) { const { embeddable, diff --git a/src/plugins/dashboard_embeddable_container/public/actions/replace_panel_action.test.tsx b/src/plugins/dashboard/public/actions/replace_panel_action.test.tsx similarity index 97% rename from src/plugins/dashboard_embeddable_container/public/actions/replace_panel_action.test.tsx rename to src/plugins/dashboard/public/actions/replace_panel_action.test.tsx index 4438a6c9971261..69346dc8c118a6 100644 --- a/src/plugins/dashboard_embeddable_container/public/actions/replace_panel_action.test.tsx +++ b/src/plugins/dashboard/public/actions/replace_panel_action.test.tsx @@ -27,7 +27,6 @@ import { ContactCardEmbeddableInput, ContactCardEmbeddableOutput, } from '../embeddable_plugin_test_samples'; -import { DashboardOptions } from '../embeddable/dashboard_container_factory'; import { coreMock } from '../../../../core/public/mocks'; import { CoreStart } from 'kibana/public'; @@ -43,7 +42,7 @@ let embeddable: ContactCardEmbeddable; let coreStart: CoreStart; beforeEach(async () => { coreStart = coreMock.createStart(); - const options: DashboardOptions = { + const options = { ExitFullScreenButton: () => null, SavedObjectFinder: () => null, application: {} as any, diff --git a/src/plugins/dashboard_embeddable_container/public/actions/replace_panel_action.tsx b/src/plugins/dashboard/public/actions/replace_panel_action.tsx similarity index 92% rename from src/plugins/dashboard_embeddable_container/public/actions/replace_panel_action.tsx rename to src/plugins/dashboard/public/actions/replace_panel_action.tsx index 1d59fe6bcb30ff..21ec961917d170 100644 --- a/src/plugins/dashboard_embeddable_container/public/actions/replace_panel_action.tsx +++ b/src/plugins/dashboard/public/actions/replace_panel_action.tsx @@ -19,7 +19,7 @@ import { i18n } from '@kbn/i18n'; import { CoreStart } from '../../../../core/public'; -import { IEmbeddable, ViewMode, IEmbeddableStart } from '../embeddable_plugin'; +import { IEmbeddable, ViewMode, EmbeddableStart } from '../embeddable_plugin'; import { DASHBOARD_CONTAINER_TYPE, DashboardContainer } from '../embeddable'; import { ActionByType, IncompatibleActionError } from '../ui_actions_plugin'; import { openReplacePanelFlyout } from './open_replace_panel_flyout'; @@ -43,14 +43,14 @@ export class ReplacePanelAction implements ActionByType, private notifications: CoreStart['notifications'], - private getEmbeddableFactories: IEmbeddableStart['getEmbeddableFactories'] + private getEmbeddableFactories: EmbeddableStart['getEmbeddableFactories'] ) {} public getDisplayName({ embeddable }: ReplacePanelActionContext) { if (!embeddable.parent || !isDashboard(embeddable.parent)) { throw new IncompatibleActionError(); } - return i18n.translate('dashboardEmbeddableContainer.panel.removePanel.replacePanel', { + return i18n.translate('dashboard.panel.removePanel.replacePanel', { defaultMessage: 'Replace panel', }); } diff --git a/src/plugins/dashboard_embeddable_container/public/actions/replace_panel_flyout.tsx b/src/plugins/dashboard/public/actions/replace_panel_flyout.tsx similarity index 87% rename from src/plugins/dashboard_embeddable_container/public/actions/replace_panel_flyout.tsx rename to src/plugins/dashboard/public/actions/replace_panel_flyout.tsx index 7b3842bd33dbd0..a1cd865f771d45 100644 --- a/src/plugins/dashboard_embeddable_container/public/actions/replace_panel_flyout.tsx +++ b/src/plugins/dashboard/public/actions/replace_panel_flyout.tsx @@ -20,7 +20,7 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; import { EuiFlyout, EuiFlyoutBody, EuiFlyoutHeader, EuiTitle } from '@elastic/eui'; -import { GetEmbeddableFactories } from 'src/plugins/embeddable/public'; +import { EmbeddableStart } from '../../../../../src/plugins/embeddable/public'; import { DashboardPanelState } from '../embeddable'; import { NotificationsStart, Toast } from '../../../../core/public'; import { IContainer, IEmbeddable, EmbeddableInput, EmbeddableOutput } from '../embeddable_plugin'; @@ -31,7 +31,7 @@ interface Props { onClose: () => void; notifications: NotificationsStart; panelToRemove: IEmbeddable; - getEmbeddableFactories: GetEmbeddableFactories; + getEmbeddableFactories: EmbeddableStart['getEmbeddableFactories']; } export class ReplacePanelFlyout extends React.Component { @@ -51,15 +51,12 @@ export class ReplacePanelFlyout extends React.Component { } this.lastToast = this.props.notifications.toasts.addSuccess({ - title: i18n.translate( - 'dashboardEmbeddableContainer.addPanel.savedObjectAddedToContainerSuccessMessageTitle', - { - defaultMessage: '{savedObjectName} was added', - values: { - savedObjectName: name, - }, - } - ), + title: i18n.translate('dashboard.addPanel.savedObjectAddedToContainerSuccessMessageTitle', { + defaultMessage: '{savedObjectName} was added', + values: { + savedObjectName: name, + }, + }), 'data-test-subj': 'addObjectToContainerSuccess', }); }; @@ -97,12 +94,9 @@ export class ReplacePanelFlyout extends React.Component { const SavedObjectFinder = this.props.savedObjectsFinder; const savedObjectsFinder = ( diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/dashboard_constants.ts b/src/plugins/dashboard/public/embeddable/dashboard_constants.ts similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/embeddable/dashboard_constants.ts rename to src/plugins/dashboard/public/embeddable/dashboard_constants.ts diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/dashboard_container.test.tsx b/src/plugins/dashboard/public/embeddable/dashboard_container.test.tsx similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/embeddable/dashboard_container.test.tsx rename to src/plugins/dashboard/public/embeddable/dashboard_container.test.tsx diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/dashboard_container.tsx b/src/plugins/dashboard/public/embeddable/dashboard_container.tsx similarity index 98% rename from src/plugins/dashboard_embeddable_container/public/embeddable/dashboard_container.tsx rename to src/plugins/dashboard/public/embeddable/dashboard_container.tsx index f9443ab97416da..86a6e374d3e255 100644 --- a/src/plugins/dashboard_embeddable_container/public/embeddable/dashboard_container.tsx +++ b/src/plugins/dashboard/public/embeddable/dashboard_container.tsx @@ -30,7 +30,7 @@ import { ViewMode, EmbeddableFactory, IEmbeddable, - IEmbeddableStart, + EmbeddableStart, } from '../embeddable_plugin'; import { DASHBOARD_CONTAINER_TYPE } from './dashboard_constants'; import { createPanelState } from './panel'; @@ -77,7 +77,7 @@ export interface DashboardContainerOptions { application: CoreStart['application']; overlays: CoreStart['overlays']; notifications: CoreStart['notifications']; - embeddable: IEmbeddableStart; + embeddable: EmbeddableStart; inspector: InspectorStartContract; SavedObjectFinder: React.ComponentType; ExitFullScreenButton: React.ComponentType; diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/dashboard_container_factory.tsx b/src/plugins/dashboard/public/embeddable/dashboard_container_factory.tsx similarity index 57% rename from src/plugins/dashboard_embeddable_container/public/embeddable/dashboard_container_factory.tsx rename to src/plugins/dashboard/public/embeddable/dashboard_container_factory.tsx index d08fcfef3529ee..0fa62fc8756037 100644 --- a/src/plugins/dashboard_embeddable_container/public/embeddable/dashboard_container_factory.tsx +++ b/src/plugins/dashboard/public/embeddable/dashboard_container_factory.tsx @@ -18,24 +18,29 @@ */ import { i18n } from '@kbn/i18n'; -import { SavedObjectMetaData } from '../../../saved_objects/public'; -import { SavedObjectAttributes } from '../../../../core/public'; +import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public'; +import { EmbeddableStart } from '../../../../../src/plugins/embeddable/public'; +import { CoreStart } from '../../../../core/public'; import { ContainerOutput, EmbeddableFactory, ErrorEmbeddable, Container, } from '../embeddable_plugin'; -import { - DashboardContainer, - DashboardContainerInput, - DashboardContainerOptions, -} from './dashboard_container'; -import { DashboardCapabilities } from '../types'; +import { DashboardContainer, DashboardContainerInput } from './dashboard_container'; import { DASHBOARD_CONTAINER_TYPE } from './dashboard_constants'; +import { Start as InspectorStartContract } from '../../../inspector/public'; -export interface DashboardOptions extends DashboardContainerOptions { - savedObjectMetaData?: SavedObjectMetaData; +interface StartServices { + capabilities: CoreStart['application']['capabilities']; + application: CoreStart['application']; + overlays: CoreStart['overlays']; + notifications: CoreStart['notifications']; + embeddable: EmbeddableStart; + inspector: InspectorStartContract; + SavedObjectFinder: React.ComponentType; + ExitFullScreenButton: React.ComponentType; + uiActions: UiActionsStart; } export class DashboardContainerFactory extends EmbeddableFactory< @@ -45,27 +50,17 @@ export class DashboardContainerFactory extends EmbeddableFactory< public readonly isContainerType = true; public readonly type = DASHBOARD_CONTAINER_TYPE; - private readonly allowEditing: boolean; - - constructor(private readonly options: DashboardOptions) { - super({ savedObjectMetaData: options.savedObjectMetaData }); - - const capabilities = (options.application.capabilities - .dashboard as unknown) as DashboardCapabilities; - - if (!capabilities || typeof capabilities !== 'object') { - throw new TypeError('Dashboard capabilities not found.'); - } - - this.allowEditing = !!capabilities.createNew && !!capabilities.showWriteControls; + constructor(private readonly getStartServices: () => Promise) { + super(); } - public isEditable() { - return this.allowEditing; + public async isEditable() { + const { capabilities } = await this.getStartServices(); + return !!capabilities.createNew && !!capabilities.showWriteControls; } public getDisplayName() { - return i18n.translate('dashboardEmbeddableContainer.factory.displayName', { + return i18n.translate('dashboard.factory.displayName', { defaultMessage: 'dashboard', }); } @@ -82,6 +77,7 @@ export class DashboardContainerFactory extends EmbeddableFactory< initialInput: DashboardContainerInput, parent?: Container ): Promise { - return new DashboardContainer(initialInput, this.options, parent); + const services = await this.getStartServices(); + return new DashboardContainer(initialInput, services, parent); } } diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/grid/_dashboard_grid.scss b/src/plugins/dashboard/public/embeddable/grid/_dashboard_grid.scss similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/embeddable/grid/_dashboard_grid.scss rename to src/plugins/dashboard/public/embeddable/grid/_dashboard_grid.scss diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/grid/_index.scss b/src/plugins/dashboard/public/embeddable/grid/_index.scss similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/embeddable/grid/_index.scss rename to src/plugins/dashboard/public/embeddable/grid/_index.scss diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/grid/dashboard_grid.test.tsx b/src/plugins/dashboard/public/embeddable/grid/dashboard_grid.test.tsx similarity index 96% rename from src/plugins/dashboard_embeddable_container/public/embeddable/grid/dashboard_grid.test.tsx rename to src/plugins/dashboard/public/embeddable/grid/dashboard_grid.test.tsx index c1a3d88979f490..0f1b9c6dc93072 100644 --- a/src/plugins/dashboard_embeddable_container/public/embeddable/grid/dashboard_grid.test.tsx +++ b/src/plugins/dashboard/public/embeddable/grid/dashboard_grid.test.tsx @@ -23,7 +23,7 @@ import sizeMe from 'react-sizeme'; import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { skip } from 'rxjs/operators'; -import { EmbeddableFactory, GetEmbeddableFactory } from '../../embeddable_plugin'; +import { EmbeddableFactory } from '../../embeddable_plugin'; import { DashboardGrid, DashboardGridProps } from './dashboard_grid'; import { DashboardContainer, DashboardContainerOptions } from '../dashboard_container'; import { getSampleDashboardInput } from '../../test_helpers'; @@ -41,7 +41,7 @@ function prepare(props?: Partial) { CONTACT_CARD_EMBEDDABLE, new ContactCardEmbeddableFactory({} as any, (() => {}) as any, {} as any) ); - const getEmbeddableFactory: GetEmbeddableFactory = (id: string) => embeddableFactories.get(id); + const getEmbeddableFactory = (id: string) => embeddableFactories.get(id); const initialInput = getSampleDashboardInput({ panels: { '1': { diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/grid/dashboard_grid.tsx b/src/plugins/dashboard/public/embeddable/grid/dashboard_grid.tsx similarity index 99% rename from src/plugins/dashboard_embeddable_container/public/embeddable/grid/dashboard_grid.tsx rename to src/plugins/dashboard/public/embeddable/grid/dashboard_grid.tsx index 40db43427339d9..3f1f1056cf1b48 100644 --- a/src/plugins/dashboard_embeddable_container/public/embeddable/grid/dashboard_grid.tsx +++ b/src/plugins/dashboard/public/embeddable/grid/dashboard_grid.tsx @@ -164,7 +164,7 @@ class DashboardGridUi extends React.Component { isLayoutInvalid = true; this.props.kibana.notifications.toasts.danger({ title: this.props.intl.formatMessage({ - id: 'dashboardEmbeddableContainer.dashboardGrid.toast.unableToLoadDashboardDangerMessage', + id: 'dashboard.dashboardGrid.toast.unableToLoadDashboardDangerMessage', defaultMessage: 'Unable to load dashboard.', }), body: error.message, diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/grid/index.ts b/src/plugins/dashboard/public/embeddable/grid/index.ts similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/embeddable/grid/index.ts rename to src/plugins/dashboard/public/embeddable/grid/index.ts diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/index.ts b/src/plugins/dashboard/public/embeddable/index.ts similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/embeddable/index.ts rename to src/plugins/dashboard/public/embeddable/index.ts diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/panel/_dashboard_panel.scss b/src/plugins/dashboard/public/embeddable/panel/_dashboard_panel.scss similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/embeddable/panel/_dashboard_panel.scss rename to src/plugins/dashboard/public/embeddable/panel/_dashboard_panel.scss diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/panel/_index.scss b/src/plugins/dashboard/public/embeddable/panel/_index.scss similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/embeddable/panel/_index.scss rename to src/plugins/dashboard/public/embeddable/panel/_index.scss diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/panel/create_panel_state.test.ts b/src/plugins/dashboard/public/embeddable/panel/create_panel_state.test.ts similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/embeddable/panel/create_panel_state.test.ts rename to src/plugins/dashboard/public/embeddable/panel/create_panel_state.test.ts diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/panel/create_panel_state.ts b/src/plugins/dashboard/public/embeddable/panel/create_panel_state.ts similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/embeddable/panel/create_panel_state.ts rename to src/plugins/dashboard/public/embeddable/panel/create_panel_state.ts diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/panel/index.ts b/src/plugins/dashboard/public/embeddable/panel/index.ts similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/embeddable/panel/index.ts rename to src/plugins/dashboard/public/embeddable/panel/index.ts diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/types.ts b/src/plugins/dashboard/public/embeddable/types.ts similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/embeddable/types.ts rename to src/plugins/dashboard/public/embeddable/types.ts diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/viewport/_dashboard_viewport.scss b/src/plugins/dashboard/public/embeddable/viewport/_dashboard_viewport.scss similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/embeddable/viewport/_dashboard_viewport.scss rename to src/plugins/dashboard/public/embeddable/viewport/_dashboard_viewport.scss diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/viewport/_index.scss b/src/plugins/dashboard/public/embeddable/viewport/_index.scss similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/embeddable/viewport/_index.scss rename to src/plugins/dashboard/public/embeddable/viewport/_index.scss diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/viewport/dashboard_viewport.test.tsx b/src/plugins/dashboard/public/embeddable/viewport/dashboard_viewport.test.tsx similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/embeddable/viewport/dashboard_viewport.test.tsx rename to src/plugins/dashboard/public/embeddable/viewport/dashboard_viewport.test.tsx diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/viewport/dashboard_viewport.tsx b/src/plugins/dashboard/public/embeddable/viewport/dashboard_viewport.tsx similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/embeddable/viewport/dashboard_viewport.tsx rename to src/plugins/dashboard/public/embeddable/viewport/dashboard_viewport.tsx diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable_plugin.ts b/src/plugins/dashboard/public/embeddable_plugin.ts similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/embeddable_plugin.ts rename to src/plugins/dashboard/public/embeddable_plugin.ts diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable_plugin_test_samples.ts b/src/plugins/dashboard/public/embeddable_plugin_test_samples.ts similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/embeddable_plugin_test_samples.ts rename to src/plugins/dashboard/public/embeddable_plugin_test_samples.ts diff --git a/src/plugins/dashboard_embeddable_container/public/index.scss b/src/plugins/dashboard/public/index.scss similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/index.scss rename to src/plugins/dashboard/public/index.scss diff --git a/src/plugins/dashboard_embeddable_container/public/index.ts b/src/plugins/dashboard/public/index.ts similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/index.ts rename to src/plugins/dashboard/public/index.ts diff --git a/src/plugins/dashboard_embeddable_container/public/plugin.tsx b/src/plugins/dashboard/public/plugin.tsx similarity index 73% rename from src/plugins/dashboard_embeddable_container/public/plugin.tsx rename to src/plugins/dashboard/public/plugin.tsx index 6f78829af19f1c..8a6e747aac1705 100644 --- a/src/plugins/dashboard_embeddable_container/public/plugin.tsx +++ b/src/plugins/dashboard/public/plugin.tsx @@ -23,7 +23,7 @@ import * as React from 'react'; import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'src/core/public'; import { SharePluginSetup } from 'src/plugins/share/public'; import { UiActionsSetup, UiActionsStart } from '../../../plugins/ui_actions/public'; -import { CONTEXT_MENU_TRIGGER, IEmbeddableSetup, IEmbeddableStart } from './embeddable_plugin'; +import { CONTEXT_MENU_TRIGGER, EmbeddableSetup, EmbeddableStart } from './embeddable_plugin'; import { ExpandPanelAction, ReplacePanelAction } from '.'; import { DashboardContainerFactory } from './embeddable/dashboard_container_factory'; import { Start as InspectorStartContract } from '../../../plugins/inspector/public'; @@ -47,13 +47,13 @@ declare module '../../share/public' { } interface SetupDependencies { - embeddable: IEmbeddableSetup; + embeddable: EmbeddableSetup; uiActions: UiActionsSetup; share?: SharePluginSetup; } interface StartDependencies { - embeddable: IEmbeddableStart; + embeddable: EmbeddableStart; inspector: InspectorStartContract; uiActions: UiActionsStart; } @@ -72,7 +72,10 @@ export class DashboardEmbeddableContainerPublicPlugin implements Plugin { constructor(initializerContext: PluginInitializerContext) {} - public setup(core: CoreSetup, { share, uiActions }: SetupDependencies): Setup { + public setup( + core: CoreSetup, + { share, uiActions, embeddable }: SetupDependencies + ): Setup { const expandPanelAction = new ExpandPanelAction(); uiActions.registerAction(expandPanelAction); uiActions.attachAction(CONTEXT_MENU_TRIGGER, expandPanelAction); @@ -86,26 +89,44 @@ export class DashboardEmbeddableContainerPublicPlugin })) ); } + + const getStartServices = async () => { + const [coreStart, deps] = await core.getStartServices(); + + const useHideChrome = () => { + React.useEffect(() => { + coreStart.chrome.setIsVisible(false); + return () => coreStart.chrome.setIsVisible(true); + }, []); + }; + + const ExitFullScreenButton: React.FC = props => { + useHideChrome(); + return ; + }; + return { + capabilities: coreStart.application.capabilities, + application: coreStart.application, + notifications: coreStart.notifications, + overlays: coreStart.overlays, + embeddable: deps.embeddable, + inspector: deps.inspector, + SavedObjectFinder: getSavedObjectFinder(coreStart.savedObjects, coreStart.uiSettings), + ExitFullScreenButton, + uiActions: deps.uiActions, + }; + }; + + const factory = new DashboardContainerFactory(getStartServices); + embeddable.registerEmbeddableFactory(factory.type, factory); } public start(core: CoreStart, plugins: StartDependencies): Start { - const { application, notifications, overlays } = core; - const { embeddable, inspector, uiActions } = plugins; + const { notifications } = core; + const { uiActions } = plugins; const SavedObjectFinder = getSavedObjectFinder(core.savedObjects, core.uiSettings); - const useHideChrome = () => { - React.useEffect(() => { - core.chrome.setIsVisible(false); - return () => core.chrome.setIsVisible(true); - }, []); - }; - - const ExitFullScreenButton: React.FC = props => { - useHideChrome(); - return ; - }; - const changeViewAction = new ReplacePanelAction( core, SavedObjectFinder, @@ -114,19 +135,6 @@ export class DashboardEmbeddableContainerPublicPlugin ); uiActions.registerAction(changeViewAction); uiActions.attachAction(CONTEXT_MENU_TRIGGER, changeViewAction); - - const factory = new DashboardContainerFactory({ - application, - notifications, - overlays, - embeddable, - inspector, - SavedObjectFinder, - ExitFullScreenButton, - uiActions, - }); - - embeddable.registerEmbeddableFactory(factory.type, factory); } public stop() {} diff --git a/src/plugins/dashboard_embeddable_container/public/test_helpers/get_sample_dashboard_input.ts b/src/plugins/dashboard/public/test_helpers/get_sample_dashboard_input.ts similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/test_helpers/get_sample_dashboard_input.ts rename to src/plugins/dashboard/public/test_helpers/get_sample_dashboard_input.ts diff --git a/src/plugins/dashboard_embeddable_container/public/test_helpers/index.ts b/src/plugins/dashboard/public/test_helpers/index.ts similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/test_helpers/index.ts rename to src/plugins/dashboard/public/test_helpers/index.ts diff --git a/src/plugins/dashboard_embeddable_container/public/tests/dashboard_container.test.tsx b/src/plugins/dashboard/public/tests/dashboard_container.test.tsx similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/tests/dashboard_container.test.tsx rename to src/plugins/dashboard/public/tests/dashboard_container.test.tsx diff --git a/src/plugins/dashboard_embeddable_container/public/types.ts b/src/plugins/dashboard/public/types.ts similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/types.ts rename to src/plugins/dashboard/public/types.ts diff --git a/src/plugins/dashboard_embeddable_container/public/ui_actions_plugin.ts b/src/plugins/dashboard/public/ui_actions_plugin.ts similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/ui_actions_plugin.ts rename to src/plugins/dashboard/public/ui_actions_plugin.ts diff --git a/src/plugins/dashboard_embeddable_container/public/url_generator.test.ts b/src/plugins/dashboard/public/url_generator.test.ts similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/url_generator.test.ts rename to src/plugins/dashboard/public/url_generator.test.ts diff --git a/src/plugins/dashboard_embeddable_container/public/url_generator.ts b/src/plugins/dashboard/public/url_generator.ts similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/url_generator.ts rename to src/plugins/dashboard/public/url_generator.ts diff --git a/src/plugins/data/common/field_formats/converters/source.ts b/src/plugins/data/common/field_formats/converters/source.ts index 702e1579e945f2..7f13d5526cc157 100644 --- a/src/plugins/data/common/field_formats/converters/source.ts +++ b/src/plugins/data/common/field_formats/converters/source.ts @@ -18,13 +18,29 @@ */ import { template, escape, keys } from 'lodash'; -// @ts-ignore -import { noWhiteSpace } from '../../../../../legacy/core_plugins/kibana/common/utils/no_white_space'; import { shortenDottedString } from '../../utils'; import { KBN_FIELD_TYPES } from '../../kbn_field_types/types'; import { FieldFormat } from '../field_format'; import { TextContextTypeConvert, HtmlContextTypeConvert, FIELD_FORMAT_IDS } from '../types'; +/** + * Remove all of the whitespace between html tags + * so that inline elements don't have extra spaces. + * + * If you have inline elements (span, a, em, etc.) and any + * amount of whitespace around them in your markup, then the + * browser will push them apart. This is ugly in certain + * scenarios and is only fixed by removing the whitespace + * from the html in the first place (or ugly css hacks). + * + * @param {string} html - the html to modify + * @return {string} - modified html + */ +function noWhiteSpace(html: string) { + const TAGS_WITH_WS = />\s+<'); +} + const templateHtml = `
<% defPairs.forEach(function (def) { %> diff --git a/src/plugins/data/common/index.ts b/src/plugins/data/common/index.ts index 7fa6e88b427a95..cf8c0bfe3d4345 100644 --- a/src/plugins/data/common/index.ts +++ b/src/plugins/data/common/index.ts @@ -17,12 +17,12 @@ * under the License. */ -export * from './query'; +export * from './constants'; +export * from './es_query'; export * from './field_formats'; -export * from './kbn_field_types'; export * from './index_patterns'; -export * from './es_query'; -export * from './utils'; -export * from './types'; +export * from './kbn_field_types'; +export * from './query'; export * from './search'; -export * from './constants'; +export * from './search/aggs'; +export * from './types'; diff --git a/src/plugins/data/common/index_patterns/fields/utils.ts b/src/plugins/data/common/index_patterns/fields/utils.ts index e587c0fe632f11..58f348b24d92e1 100644 --- a/src/plugins/data/common/index_patterns/fields/utils.ts +++ b/src/plugins/data/common/index_patterns/fields/utils.ts @@ -17,7 +17,8 @@ * under the License. */ -import { getFilterableKbnTypeNames, IFieldType } from '../..'; +import { getFilterableKbnTypeNames } from '../../kbn_field_types'; +import { IFieldType } from './types'; const filterableTypes = getFilterableKbnTypeNames(); diff --git a/src/legacy/core_plugins/data/common/date_histogram_interval.test.ts b/src/plugins/data/common/search/aggs/date_interval_utils/date_histogram_interval.test.ts similarity index 100% rename from src/legacy/core_plugins/data/common/date_histogram_interval.test.ts rename to src/plugins/data/common/search/aggs/date_interval_utils/date_histogram_interval.test.ts diff --git a/src/legacy/core_plugins/data/common/date_histogram_interval.ts b/src/plugins/data/common/search/aggs/date_interval_utils/date_histogram_interval.ts similarity index 100% rename from src/legacy/core_plugins/data/common/date_histogram_interval.ts rename to src/plugins/data/common/search/aggs/date_interval_utils/date_histogram_interval.ts diff --git a/src/legacy/core_plugins/data/common/index.ts b/src/plugins/data/common/search/aggs/date_interval_utils/index.ts similarity index 70% rename from src/legacy/core_plugins/data/common/index.ts rename to src/plugins/data/common/search/aggs/date_interval_utils/index.ts index 403ea4821ffbc3..67b9cfecba00fb 100644 --- a/src/legacy/core_plugins/data/common/index.ts +++ b/src/plugins/data/common/search/aggs/date_interval_utils/index.ts @@ -17,13 +17,11 @@ * under the License. */ -/** @public static code */ -export { dateHistogramInterval } from './date_histogram_interval'; -/** @public static code */ -export { - isValidEsInterval, - InvalidEsCalendarIntervalError, - InvalidEsIntervalFormatError, - parseEsInterval, - ParsedInterval, -} from './parse_es_interval'; +export * from './date_histogram_interval'; +export * from './invalid_es_calendar_interval_error'; +export * from './invalid_es_interval_format_error'; +export * from './is_valid_es_interval'; +export * from './is_valid_interval'; +export * from './parse_interval'; +export * from './parse_es_interval'; +export * from './to_absolute_dates'; diff --git a/src/legacy/core_plugins/data/common/parse_es_interval/invalid_es_calendar_interval_error.ts b/src/plugins/data/common/search/aggs/date_interval_utils/invalid_es_calendar_interval_error.ts similarity index 100% rename from src/legacy/core_plugins/data/common/parse_es_interval/invalid_es_calendar_interval_error.ts rename to src/plugins/data/common/search/aggs/date_interval_utils/invalid_es_calendar_interval_error.ts diff --git a/src/legacy/core_plugins/data/common/parse_es_interval/invalid_es_interval_format_error.ts b/src/plugins/data/common/search/aggs/date_interval_utils/invalid_es_interval_format_error.ts similarity index 100% rename from src/legacy/core_plugins/data/common/parse_es_interval/invalid_es_interval_format_error.ts rename to src/plugins/data/common/search/aggs/date_interval_utils/invalid_es_interval_format_error.ts diff --git a/src/legacy/core_plugins/data/common/parse_es_interval/is_valid_es_interval.ts b/src/plugins/data/common/search/aggs/date_interval_utils/is_valid_es_interval.ts similarity index 100% rename from src/legacy/core_plugins/data/common/parse_es_interval/is_valid_es_interval.ts rename to src/plugins/data/common/search/aggs/date_interval_utils/is_valid_es_interval.ts diff --git a/src/plugins/data/common/search/aggs/date_interval_utils/is_valid_interval.ts b/src/plugins/data/common/search/aggs/date_interval_utils/is_valid_interval.ts new file mode 100644 index 00000000000000..03d84c5e2c97b7 --- /dev/null +++ b/src/plugins/data/common/search/aggs/date_interval_utils/is_valid_interval.ts @@ -0,0 +1,41 @@ +/* + * 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 { isValidEsInterval } from './is_valid_es_interval'; +import { leastCommonInterval } from './least_common_interval'; + +// When base interval is set, check for least common interval and allow +// input the value is the same. This means that the input interval is a +// multiple of the base interval. +function _parseWithBase(value: string, baseInterval: string) { + try { + const interval = leastCommonInterval(baseInterval, value); + return interval === value.replace(/\s/g, ''); + } catch (e) { + return false; + } +} + +export function isValidInterval(value: string, baseInterval?: string) { + if (baseInterval) { + return _parseWithBase(value, baseInterval); + } else { + return isValidEsInterval(value); + } +} diff --git a/src/legacy/ui/public/vis/lib/least_common_interval.test.ts b/src/plugins/data/common/search/aggs/date_interval_utils/least_common_interval.test.ts similarity index 99% rename from src/legacy/ui/public/vis/lib/least_common_interval.test.ts rename to src/plugins/data/common/search/aggs/date_interval_utils/least_common_interval.test.ts index 3f780665a949f6..f9ff4bfea222b0 100644 --- a/src/legacy/ui/public/vis/lib/least_common_interval.test.ts +++ b/src/plugins/data/common/search/aggs/date_interval_utils/least_common_interval.test.ts @@ -19,8 +19,6 @@ import { leastCommonInterval } from './least_common_interval'; -jest.mock('ui/new_platform'); - describe('leastCommonInterval', () => { it('should correctly return lowest common interval for fixed units', () => { expect(leastCommonInterval('1ms', '1s')).toBe('1s'); diff --git a/src/legacy/ui/public/vis/lib/least_common_interval.ts b/src/plugins/data/common/search/aggs/date_interval_utils/least_common_interval.ts similarity index 96% rename from src/legacy/ui/public/vis/lib/least_common_interval.ts rename to src/plugins/data/common/search/aggs/date_interval_utils/least_common_interval.ts index 72426855f70af5..9df17b4c24a982 100644 --- a/src/legacy/ui/public/vis/lib/least_common_interval.ts +++ b/src/plugins/data/common/search/aggs/date_interval_utils/least_common_interval.ts @@ -19,7 +19,7 @@ import dateMath from '@elastic/datemath'; import { leastCommonMultiple } from './least_common_multiple'; -import { parseEsInterval } from '../../../../core_plugins/data/common/parse_es_interval/parse_es_interval'; +import { parseEsInterval } from './parse_es_interval'; /** * Finds the lowest common interval between two given ES date histogram intervals diff --git a/src/legacy/ui/public/vis/lib/least_common_multiple.test.ts b/src/plugins/data/common/search/aggs/date_interval_utils/least_common_multiple.test.ts similarity index 100% rename from src/legacy/ui/public/vis/lib/least_common_multiple.test.ts rename to src/plugins/data/common/search/aggs/date_interval_utils/least_common_multiple.test.ts diff --git a/src/legacy/ui/public/vis/lib/least_common_multiple.ts b/src/plugins/data/common/search/aggs/date_interval_utils/least_common_multiple.ts similarity index 100% rename from src/legacy/ui/public/vis/lib/least_common_multiple.ts rename to src/plugins/data/common/search/aggs/date_interval_utils/least_common_multiple.ts diff --git a/src/legacy/core_plugins/data/common/parse_es_interval/parse_es_interval.test.ts b/src/plugins/data/common/search/aggs/date_interval_utils/parse_es_interval.test.ts similarity index 100% rename from src/legacy/core_plugins/data/common/parse_es_interval/parse_es_interval.test.ts rename to src/plugins/data/common/search/aggs/date_interval_utils/parse_es_interval.test.ts diff --git a/src/legacy/core_plugins/data/common/parse_es_interval/parse_es_interval.ts b/src/plugins/data/common/search/aggs/date_interval_utils/parse_es_interval.ts similarity index 100% rename from src/legacy/core_plugins/data/common/parse_es_interval/parse_es_interval.ts rename to src/plugins/data/common/search/aggs/date_interval_utils/parse_es_interval.ts diff --git a/src/plugins/data/common/utils/parse_interval.test.ts b/src/plugins/data/common/search/aggs/date_interval_utils/parse_interval.test.ts similarity index 100% rename from src/plugins/data/common/utils/parse_interval.test.ts rename to src/plugins/data/common/search/aggs/date_interval_utils/parse_interval.test.ts diff --git a/src/plugins/data/common/utils/parse_interval.ts b/src/plugins/data/common/search/aggs/date_interval_utils/parse_interval.ts similarity index 100% rename from src/plugins/data/common/utils/parse_interval.ts rename to src/plugins/data/common/search/aggs/date_interval_utils/parse_interval.ts diff --git a/src/plugins/data/common/search/aggs/date_interval_utils/to_absolute_dates.ts b/src/plugins/data/common/search/aggs/date_interval_utils/to_absolute_dates.ts new file mode 100644 index 00000000000000..98d752a72e28ae --- /dev/null +++ b/src/plugins/data/common/search/aggs/date_interval_utils/to_absolute_dates.ts @@ -0,0 +1,35 @@ +/* + * 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 dateMath from '@elastic/datemath'; +import { TimeRange } from '../../../../common'; + +export function toAbsoluteDates(range: TimeRange) { + const fromDate = dateMath.parse(range.from); + const toDate = dateMath.parse(range.to, { roundUp: true }); + + if (!fromDate || !toDate) { + return; + } + + return { + from: fromDate.toDate(), + to: toDate.toDate(), + }; +} diff --git a/src/legacy/core_plugins/dashboard_embeddable_container/public/initialize.ts b/src/plugins/data/common/search/aggs/index.ts similarity index 95% rename from src/legacy/core_plugins/dashboard_embeddable_container/public/initialize.ts rename to src/plugins/data/common/search/aggs/index.ts index 9880b336e76e5c..09ea958ccaa85e 100644 --- a/src/legacy/core_plugins/dashboard_embeddable_container/public/initialize.ts +++ b/src/plugins/data/common/search/aggs/index.ts @@ -16,3 +16,5 @@ * specific language governing permissions and limitations * under the License. */ + +export * from './date_interval_utils'; diff --git a/src/plugins/data/common/utils/index.ts b/src/plugins/data/common/utils/index.ts index c5f1276feb81dd..8b8686c51b9c19 100644 --- a/src/plugins/data/common/utils/index.ts +++ b/src/plugins/data/common/utils/index.ts @@ -17,5 +17,5 @@ * under the License. */ +/** @internal */ export { shortenDottedString } from './shorten_dotted_string'; -export { parseInterval } from './parse_interval'; diff --git a/src/plugins/data/kibana.json b/src/plugins/data/kibana.json index 6553ce8ce4d915..f5df747f17e1ea 100644 --- a/src/plugins/data/kibana.json +++ b/src/plugins/data/kibana.json @@ -3,6 +3,9 @@ "version": "kibana", "server": true, "ui": true, - "requiredPlugins": ["uiActions"], + "requiredPlugins": [ + "expressions", + "uiActions" + ], "optionalPlugins": ["usageCollection"] } diff --git a/src/legacy/core_plugins/data/public/actions/filters/brush_event.test.ts b/src/plugins/data/public/actions/filters/brush_event.test.ts similarity index 93% rename from src/legacy/core_plugins/data/public/actions/filters/brush_event.test.ts rename to src/plugins/data/public/actions/filters/brush_event.test.ts index eb29530f92fee7..60244354f06e4b 100644 --- a/src/legacy/core_plugins/data/public/actions/filters/brush_event.test.ts +++ b/src/plugins/data/public/actions/filters/brush_event.test.ts @@ -21,11 +21,10 @@ import moment from 'moment'; import { onBrushEvent, BrushEvent } from './brush_event'; -import { mockDataServices } from '../../search/aggs/test_helpers'; -import { IndexPatternsContract } from '../../../../../../plugins/data/public'; -import { dataPluginMock } from '../../../../../../plugins/data/public/mocks'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { setIndexPatterns } from '../../../../../../plugins/data/public/services'; +import { IndexPatternsContract } from '../../../public'; +import { dataPluginMock } from '../../../public/mocks'; +import { setIndexPatterns } from '../../../public/services'; +import { mockDataServices } from '../../../public/search/aggs/test_helpers'; describe('brushEvent', () => { const DAY_IN_MS = 24 * 60 * 60 * 1000; diff --git a/src/legacy/core_plugins/data/public/actions/filters/brush_event.ts b/src/plugins/data/public/actions/filters/brush_event.ts similarity index 89% rename from src/legacy/core_plugins/data/public/actions/filters/brush_event.ts rename to src/plugins/data/public/actions/filters/brush_event.ts index 00990d21ccf378..714f005fbeb6dd 100644 --- a/src/legacy/core_plugins/data/public/actions/filters/brush_event.ts +++ b/src/plugins/data/public/actions/filters/brush_event.ts @@ -19,11 +19,9 @@ import { get, last } from 'lodash'; import moment from 'moment'; -import { esFilters, IFieldType, RangeFilterParams } from '../../../../../../plugins/data/public'; +import { esFilters, IFieldType, RangeFilterParams } from '../../../public'; +import { getIndexPatterns } from '../../../public/services'; import { deserializeAggConfig } from '../../search/expressions/utils'; -// should be removed after moving into new platform plugins data folder -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getIndexPatterns } from '../../../../../../plugins/data/public/services'; export interface BrushEvent { data: { diff --git a/src/legacy/core_plugins/data/public/actions/filters/create_filters_from_event.test.ts b/src/plugins/data/public/actions/filters/create_filters_from_event.test.ts similarity index 89% rename from src/legacy/core_plugins/data/public/actions/filters/create_filters_from_event.test.ts rename to src/plugins/data/public/actions/filters/create_filters_from_event.test.ts index bfba4d7f4c8dad..1ed09002816d1f 100644 --- a/src/legacy/core_plugins/data/public/actions/filters/create_filters_from_event.test.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_event.test.ts @@ -22,14 +22,11 @@ import { FieldFormatsGetConfigFn, esFilters, IndexPatternsContract, -} from '../../../../../../plugins/data/public'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { setIndexPatterns } from '../../../../../../plugins/data/public/services'; -import { dataPluginMock } from '../../../../../../plugins/data/public/mocks'; +} from '../../../public'; +import { dataPluginMock } from '../../../public/mocks'; +import { setIndexPatterns } from '../../../public/services'; +import { mockDataServices } from '../../../public/search/aggs/test_helpers'; import { createFiltersFromEvent, EventData } from './create_filters_from_event'; -import { mockDataServices } from '../../search/aggs/test_helpers'; - -jest.mock('ui/new_platform'); const mockField = { name: 'bytes', diff --git a/src/legacy/core_plugins/data/public/actions/filters/create_filters_from_event.ts b/src/plugins/data/public/actions/filters/create_filters_from_event.ts similarity index 89% rename from src/legacy/core_plugins/data/public/actions/filters/create_filters_from_event.ts rename to src/plugins/data/public/actions/filters/create_filters_from_event.ts index 3713c781b0958d..e62945a5920728 100644 --- a/src/legacy/core_plugins/data/public/actions/filters/create_filters_from_event.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_event.ts @@ -17,11 +17,10 @@ * under the License. */ -import { KibanaDatatable } from '../../../../../../plugins/expressions/public'; -import { esFilters, Filter } from '../../../../../../plugins/data/public'; -import { deserializeAggConfig } from '../../search/expressions/utils'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getIndexPatterns } from '../../../../../../plugins/data/public/services'; +import { KibanaDatatable } from '../../../../../plugins/expressions/public'; +import { deserializeAggConfig } from '../../search/expressions'; +import { esFilters, Filter } from '../../../public'; +import { getIndexPatterns } from '../../../public/services'; export interface EventData { table: Pick; @@ -113,7 +112,8 @@ const createFilter = async (table: EventData['table'], columnIndex: number, rowI return filter; }; -const createFiltersFromEvent = async (dataPoints: EventData[], negate?: boolean) => { +/** @public */ +export const createFiltersFromEvent = async (dataPoints: EventData[], negate?: boolean) => { const filters: Filter[] = []; await Promise.all( @@ -135,5 +135,3 @@ const createFiltersFromEvent = async (dataPoints: EventData[], negate?: boolean) return filters; }; - -export { createFilter, createFiltersFromEvent }; diff --git a/src/plugins/data/public/actions/index.ts b/src/plugins/data/public/actions/index.ts index e3dc9760aa8b83..cdb84ff13f25ef 100644 --- a/src/plugins/data/public/actions/index.ts +++ b/src/plugins/data/public/actions/index.ts @@ -18,3 +18,6 @@ */ export { ACTION_GLOBAL_APPLY_FILTER, createFilterAction } from './apply_filter_action'; +export { createFiltersFromEvent } from './filters/create_filters_from_event'; +export { selectRangeAction } from './select_range_action'; +export { valueClickAction } from './value_click_action'; diff --git a/src/legacy/core_plugins/data/public/actions/select_range_action.ts b/src/plugins/data/public/actions/select_range_action.ts similarity index 96% rename from src/legacy/core_plugins/data/public/actions/select_range_action.ts rename to src/plugins/data/public/actions/select_range_action.ts index 21046f8bb834fb..6e1f16a09e803f 100644 --- a/src/legacy/core_plugins/data/public/actions/select_range_action.ts +++ b/src/plugins/data/public/actions/select_range_action.ts @@ -22,9 +22,9 @@ import { createAction, IncompatibleActionError, ActionByType, -} from '../../../../../plugins/ui_actions/public'; +} from '../../../../plugins/ui_actions/public'; import { onBrushEvent } from './filters/brush_event'; -import { FilterManager, TimefilterContract, esFilters } from '../../../../../plugins/data/public'; +import { FilterManager, TimefilterContract, esFilters } from '..'; export const ACTION_SELECT_RANGE = 'ACTION_SELECT_RANGE'; diff --git a/src/legacy/core_plugins/data/public/actions/value_click_action.ts b/src/plugins/data/public/actions/value_click_action.ts similarity index 86% rename from src/legacy/core_plugins/data/public/actions/value_click_action.ts rename to src/plugins/data/public/actions/value_click_action.ts index 4c69bc82629227..01c32e27da07d0 100644 --- a/src/legacy/core_plugins/data/public/actions/value_click_action.ts +++ b/src/plugins/data/public/actions/value_click_action.ts @@ -18,24 +18,16 @@ */ import { i18n } from '@kbn/i18n'; -import { toMountPoint } from '../../../../../plugins/kibana_react/public'; +import { toMountPoint } from '../../../../plugins/kibana_react/public'; import { ActionByType, createAction, IncompatibleActionError, -} from '../../../../../plugins/ui_actions/public'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getOverlays, getIndexPatterns } from '../../../../../plugins/data/public/services'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { applyFiltersPopover } from '../../../../../plugins/data/public/ui/apply_filters'; -// @ts-ignore +} from '../../../../plugins/ui_actions/public'; +import { getOverlays, getIndexPatterns } from '../services'; +import { applyFiltersPopover } from '../ui/apply_filters'; import { createFiltersFromEvent } from './filters/create_filters_from_event'; -import { - Filter, - FilterManager, - TimefilterContract, - esFilters, -} from '../../../../../plugins/data/public'; +import { Filter, FilterManager, TimefilterContract, esFilters } from '..'; export const ACTION_VALUE_CLICK = 'ACTION_VALUE_CLICK'; diff --git a/src/plugins/data/public/field_formats/utils/deserialize.ts b/src/plugins/data/public/field_formats/utils/deserialize.ts index c10ebfbe3eb1ed..c735ad196fbee7 100644 --- a/src/plugins/data/public/field_formats/utils/deserialize.ts +++ b/src/plugins/data/public/field_formats/utils/deserialize.ts @@ -19,14 +19,8 @@ import { identity } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { - convertDateRangeToString, - DateRangeKey, -} from '../../../../../legacy/core_plugins/data/public/search/aggs/buckets/lib/date_range'; -import { - convertIPRangeToString, - IpRangeKey, -} from '../../../../../legacy/core_plugins/data/public/search/aggs/buckets/lib/ip_range'; +import { convertDateRangeToString, DateRangeKey } from '../../search/aggs/buckets/lib/date_range'; +import { convertIPRangeToString, IpRangeKey } from '../../search/aggs/buckets/lib/ip_range'; import { SerializedFieldFormat } from '../../../../expressions/common/types'; import { FieldFormatId, FieldFormatsContentType, IFieldFormat } from '../..'; import { FieldFormat } from '../../../common'; diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index 7d739103eb2bbb..58bd9a5ab05d73 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -26,27 +26,27 @@ import { PluginInitializerContext } from '../../../core/public'; */ import { - FILTERS, buildEmptyFilter, - buildPhrasesFilter, buildExistsFilter, buildPhraseFilter, + buildPhrasesFilter, buildQueryFilter, buildRangeFilter, - toggleFilterNegated, disableFilter, + FILTERS, FilterStateStore, + getDisplayValueFromFilter, getPhraseFilterField, getPhraseFilterValue, - isPhraseFilter, isExistsFilter, - isPhrasesFilter, - isRangeFilter, + isFilterPinned, isMatchAllFilter, isMissingFilter, + isPhraseFilter, + isPhrasesFilter, isQueryStringFilter, - getDisplayValueFromFilter, - isFilterPinned, + isRangeFilter, + toggleFilterNegated, } from '../common'; import { FilterLabel } from './ui/filter_bar'; @@ -283,7 +283,65 @@ export { * Search: */ +import { + // aggs + AggConfigs, + aggTypeFilters, + aggGroupNamesMap, + CidrMask, + convertDateRangeToString, + convertIPRangeToString, + intervalOptions, // only used in Discover + isDateHistogramBucketAggConfig, + isStringType, + isType, + parentPipelineType, + propFilter, + siblingPipelineType, + termsAggFilter, + // expressions utils + getRequestInspectorStats, + getResponseInspectorStats, + // tabify + tabifyAggResponse, + tabifyGetColumns, +} from './search'; + +import { + dateHistogramInterval, + InvalidEsCalendarIntervalError, + InvalidEsIntervalFormatError, + isValidEsInterval, + isValidInterval, + parseEsInterval, + parseInterval, + toAbsoluteDates, +} from '../common'; + +export { ParsedInterval } from '../common'; + export { + // aggs + AggGroupNames, + AggParam, // only the type is used externally, only in vis editor + AggParamOption, // only the type is used externally + AggParamType, + AggTypeFieldFilters, // TODO convert to interface + AggTypeFilters, // TODO convert to interface + BUCKET_TYPES, + DateRangeKey, // only used in field formatter deserialization, which will live in data + IAggConfig, + IAggConfigs, + IAggGroupNames, + IAggType, + IFieldParamType, + IMetricAggType, + IpRangeKey, // only used in field formatter deserialization, which will live in data + METRIC_TYPES, + OptionedParamEditorProps, // only type is used externally + OptionedParamType, + OptionedValueProp, // only type is used externally + // search ES_SEARCH_STRATEGY, SYNC_SEARCH_STRATEGY, getEsPreference, @@ -311,8 +369,44 @@ export { EsQuerySortValue, SortDirection, FetchOptions, + // tabify + TabbedAggColumn, + TabbedAggRow, + TabbedTable, } from './search'; +// Search namespace +export const search = { + aggs: { + AggConfigs, + aggGroupNamesMap, + aggTypeFilters, + CidrMask, + convertDateRangeToString, + convertIPRangeToString, + dateHistogramInterval, + intervalOptions, // only used in Discover + InvalidEsCalendarIntervalError, + InvalidEsIntervalFormatError, + isDateHistogramBucketAggConfig, + isStringType, + isType, + isValidEsInterval, + isValidInterval, + parentPipelineType, + parseEsInterval, + parseInterval, + propFilter, + siblingPipelineType, + termsAggFilter, + toAbsoluteDates, + }, + getRequestInspectorStats, + getResponseInspectorStats, + tabifyAggResponse, + tabifyGetColumns, +}; + /* * UI components */ @@ -354,8 +448,6 @@ export { // kbn field types castEsToKbnFieldTypeName, getKbnTypeNames, - // utils - parseInterval, } from '../common'; /* diff --git a/src/plugins/data/public/index_patterns/fields/field.ts b/src/plugins/data/public/index_patterns/fields/field.ts index f59fbefbea451e..1554565d1403ee 100644 --- a/src/plugins/data/public/index_patterns/fields/field.ts +++ b/src/plugins/data/public/index_patterns/fields/field.ts @@ -22,13 +22,8 @@ import { i18n } from '@kbn/i18n'; import { ObjDefine } from './obj_define'; import { IndexPattern } from '../index_patterns'; import { getNotifications, getFieldFormats } from '../../services'; -import { - IFieldType, - getKbnFieldType, - IFieldSubType, - shortenDottedString, - FieldFormat, -} from '../../../common'; +import { IFieldType, getKbnFieldType, IFieldSubType, FieldFormat } from '../../../common'; +import { shortenDottedString } from '../../../common/utils'; export type FieldSpec = Record; diff --git a/src/plugins/data/public/mocks.ts b/src/plugins/data/public/mocks.ts index 013b2f393b60be..c5cff1c5c68d91 100644 --- a/src/plugins/data/public/mocks.ts +++ b/src/plugins/data/public/mocks.ts @@ -17,13 +17,12 @@ * under the License. */ -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { coreMock } from '../../../../src/core/public/mocks'; import { Plugin, DataPublicPluginSetup, DataPublicPluginStart, IndexPatternsContract } from '.'; import { fieldFormatsMock } from '../common/field_formats/mocks'; import { searchSetupMock } from './search/mocks'; +import { AggTypeFieldFilters } from './search/aggs'; +import { searchAggsStartMock } from './search/aggs/mocks'; import { queryServiceMock } from './query/mocks'; -import { getCalculateAutoTimeExpression } from './search/aggs/buckets/lib/date_utils'; export type Setup = jest.Mocked>; export type Start = jest.Mocked>; @@ -53,17 +52,24 @@ const createSetupContract = (): Setup => { }; const createStartContract = (): Start => { - const coreStart = coreMock.createStart(); const queryStartMock = queryServiceMock.createStartContract(); const startContract = { + actions: { + createFiltersFromEvent: jest.fn().mockResolvedValue(['yes']), + }, autocomplete: autocompleteMock, getSuggestions: jest.fn(), search: { - aggs: { - calculateAutoTimeExpression: getCalculateAutoTimeExpression(coreStart.uiSettings), - }, + aggs: searchAggsStartMock(), search: jest.fn(), __LEGACY: { + AggConfig: jest.fn() as any, + AggType: jest.fn(), + aggTypeFieldFilters: new AggTypeFieldFilters(), + FieldParamType: jest.fn(), + MetricAggType: jest.fn(), + parentPipelineAggHelper: jest.fn() as any, + siblingPipelineAggHelper: jest.fn() as any, esClient: { search: jest.fn(), msearch: jest.fn(), @@ -95,7 +101,7 @@ const createStartContract = (): Start => { }; export { searchSourceMock } from './search/mocks'; -export { getCalculateAutoTimeExpression } from './search/aggs/buckets/lib/date_utils'; +export { getCalculateAutoTimeExpression } from './search/aggs'; export const dataPluginMock = { createSetupContract, diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index a199a0419aea64..a01c1337122068 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -38,20 +38,40 @@ import { QueryService } from './query'; import { createIndexPatternSelect } from './ui/index_pattern_select'; import { IndexPatternsService } from './index_patterns'; import { - setNotifications, setFieldFormats, - setOverlays, setIndexPatterns, + setInjectedMetadata, + setNotifications, + setOverlays, + setQueryService, + setSearchService, setUiSettings, } from './services'; -import { createFilterAction, ACTION_GLOBAL_APPLY_FILTER } from './actions'; -import { APPLY_FILTER_TRIGGER } from '../../embeddable/public'; import { createSearchBar } from './ui/search_bar/create_search_bar'; +import { esaggs } from './search/expressions'; +import { + SELECT_RANGE_TRIGGER, + VALUE_CLICK_TRIGGER, + APPLY_FILTER_TRIGGER, +} from '../../ui_actions/public'; +import { ACTION_GLOBAL_APPLY_FILTER, createFilterAction, createFiltersFromEvent } from './actions'; import { ApplyGlobalFilterActionContext } from './actions/apply_filter_action'; +import { + selectRangeAction, + SelectRangeActionContext, + ACTION_SELECT_RANGE, +} from './actions/select_range_action'; +import { + valueClickAction, + ACTION_VALUE_CLICK, + ValueClickActionContext, +} from './actions/value_click_action'; declare module '../../ui_actions/public' { export interface ActionContextMapping { [ACTION_GLOBAL_APPLY_FILTER]: ApplyGlobalFilterActionContext; + [ACTION_SELECT_RANGE]: SelectRangeActionContext; + [ACTION_VALUE_CLICK]: ValueClickActionContext; } } @@ -71,7 +91,14 @@ export class DataPublicPlugin implements Plugin; + +// Warning: (ae-forgotten-export) The symbol "BaseParamType" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "AggParam" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type AggParam = BaseParamType; + +// Warning: (ae-missing-release-tag) "AggParamOption" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface AggParamOption { + // (undocumented) + display: string; + // Warning: (ae-forgotten-export) The symbol "AggConfig" needs to be exported by the entry point index.d.ts + // + // (undocumented) + enabled?(agg: AggConfig): boolean; + // (undocumented) + val: string; +} + +// Warning: (ae-missing-release-tag) "AggParamType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export class AggParamType extends BaseParamType { + constructor(config: Record); + // (undocumented) + allowedAggs: string[]; + // (undocumented) + makeAgg: (agg: TAggConfig, state?: any) => TAggConfig; +} + +// Warning: (ae-missing-release-tag) "AggTypeFieldFilters" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "AggTypeFieldFilter" +// Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "AggType" +// +// @public +export class AggTypeFieldFilters { + // Warning: (ae-forgotten-export) The symbol "AggTypeFieldFilter" needs to be exported by the entry point index.d.ts + // Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "AggTypeFieldFilter" + addFilter(filter: AggTypeFieldFilter): void; + // Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "any" + filter(fields: IndexPatternField_2[], aggConfig: IAggConfig): IndexPatternField_2[]; + } + +// Warning: (ae-missing-release-tag) "AggTypeFilters" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "AggTypeFilter" +// Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "AggConfig" +// +// @public +export class AggTypeFilters { + // Warning: (ae-forgotten-export) The symbol "AggTypeFilter" needs to be exported by the entry point index.d.ts + // Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "AggTypeFilter" + addFilter(filter: AggTypeFilter): void; + // Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "AggType" + filter(aggTypes: IAggType[], indexPattern: IndexPattern, aggConfig: IAggConfig, aggFilter: string[]): IAggType[]; + } + // Warning: (ae-forgotten-export) The symbol "DateFormat" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "baseFormattersPublic" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) export const baseFormattersPublic: (import("../../common").IFieldFormatType | typeof DateFormat)[]; +// Warning: (ae-missing-release-tag) "BUCKET_TYPES" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export enum BUCKET_TYPES { + // (undocumented) + DATE_HISTOGRAM = "date_histogram", + // (undocumented) + DATE_RANGE = "date_range", + // (undocumented) + FILTER = "filter", + // (undocumented) + FILTERS = "filters", + // (undocumented) + GEOHASH_GRID = "geohash_grid", + // (undocumented) + GEOTILE_GRID = "geotile_grid", + // (undocumented) + HISTOGRAM = "histogram", + // (undocumented) + IP_RANGE = "ip_range", + // (undocumented) + RANGE = "range", + // (undocumented) + SIGNIFICANT_TERMS = "significant_terms", + // (undocumented) + TERMS = "terms" +} + // Warning: (ae-missing-release-tag) "castEsToKbnFieldTypeName" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public @@ -123,6 +222,10 @@ export interface DataPublicPluginSetup { // // @public (undocumented) export interface DataPublicPluginStart { + // (undocumented) + actions: { + createFiltersFromEvent: typeof createFiltersFromEvent; + }; // Warning: (ae-forgotten-export) The symbol "AutocompleteStart" needs to be exported by the entry point index.d.ts // // (undocumented) @@ -148,6 +251,16 @@ export interface DataPublicPluginStart { }; } +// Warning: (ae-missing-release-tag) "DateRangeKey" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface DateRangeKey { + // (undocumented) + from: number; + // (undocumented) + to: number; +} + // @public (undocumented) export enum ES_FIELD_TYPES { // (undocumented) @@ -345,7 +458,7 @@ export type FieldFormatId = FIELD_FORMAT_IDS | string; export const fieldFormats: { FieldFormat: typeof FieldFormat; FieldFormatsRegistry: typeof FieldFormatsRegistry; - serialize: (agg: import("../../../legacy/core_plugins/data/public/search").AggConfig) => import("../../expressions/common").SerializedFieldFormat; + serialize: (agg: import("./search").AggConfig) => import("../../expressions/common").SerializedFieldFormat; DEFAULT_CONVERTER_COLOR: { range: string; regex: string; @@ -473,6 +586,27 @@ export function getSearchErrorType({ message }: Pick): " // @public (undocumented) export function getTime(indexPattern: IIndexPattern | undefined, timeRange: TimeRange, forceNow?: Date): import("../..").RangeFilter | undefined; +// Warning: (ae-missing-release-tag) "IAggConfig" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export type IAggConfig = AggConfig; + +// Warning: (ae-forgotten-export) The symbol "AggConfigs" needs to be exported by the entry point index.d.ts +// +// @internal +export type IAggConfigs = AggConfigs; + +// Warning: (ae-missing-release-tag) "IAggGroupNames" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type IAggGroupNames = $Values; + +// Warning: (ae-forgotten-export) The symbol "AggType" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "IAggType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type IAggType = AggType; + // Warning: (ae-missing-release-tag) "IDataPluginServices" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -521,6 +655,12 @@ export type IFieldFormat = PublicMethodsOf; // @public (undocumented) export type IFieldFormatsRegistry = PublicMethodsOf; +// Warning: (ae-forgotten-export) The symbol "FieldParamType" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "IFieldParamType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type IFieldParamType = FieldParamType; + // Warning: (ae-missing-release-tag) "IFieldSubType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -613,6 +753,12 @@ export interface IKibanaSearchResponse { total?: number; } +// Warning: (ae-forgotten-export) The symbol "MetricAggType" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "IMetricAggType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type IMetricAggType = MetricAggType; + // Warning: (ae-missing-release-tag) "IndexPattern" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -878,6 +1024,18 @@ export type InputTimeRange = TimeRange | { to: Moment; }; +// Warning: (ae-missing-release-tag) "IpRangeKey" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type IpRangeKey = { + type: 'mask'; + mask: string; +} | { + type: 'range'; + from: string; + to: string; +}; + // Warning: (ae-missing-release-tag) "IRequestTypesMap" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -1005,10 +1163,92 @@ export type MatchAllFilter = Filter & { match_all: any; }; -// Warning: (ae-missing-release-tag) "parseInterval" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "METRIC_TYPES" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export function parseInterval(interval: string): moment.Duration | null; +export enum METRIC_TYPES { + // (undocumented) + AVG = "avg", + // (undocumented) + AVG_BUCKET = "avg_bucket", + // (undocumented) + CARDINALITY = "cardinality", + // (undocumented) + COUNT = "count", + // (undocumented) + CUMULATIVE_SUM = "cumulative_sum", + // (undocumented) + DERIVATIVE = "derivative", + // (undocumented) + GEO_BOUNDS = "geo_bounds", + // (undocumented) + GEO_CENTROID = "geo_centroid", + // (undocumented) + MAX = "max", + // (undocumented) + MAX_BUCKET = "max_bucket", + // (undocumented) + MEDIAN = "median", + // (undocumented) + MIN = "min", + // (undocumented) + MIN_BUCKET = "min_bucket", + // (undocumented) + MOVING_FN = "moving_avg", + // (undocumented) + PERCENTILE_RANKS = "percentile_ranks", + // (undocumented) + PERCENTILES = "percentiles", + // (undocumented) + SERIAL_DIFF = "serial_diff", + // (undocumented) + STD_DEV = "std_dev", + // (undocumented) + SUM = "sum", + // (undocumented) + SUM_BUCKET = "sum_bucket", + // (undocumented) + TOP_HITS = "top_hits" +} + +// Warning: (ae-missing-release-tag) "OptionedParamEditorProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface OptionedParamEditorProps { + // (undocumented) + aggParam: { + options: T[]; + }; +} + +// Warning: (ae-missing-release-tag) "OptionedParamType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export class OptionedParamType extends BaseParamType { + constructor(config: Record); + // (undocumented) + options: OptionedValueProp[]; +} + +// Warning: (ae-missing-release-tag) "OptionedValueProp" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface OptionedValueProp { + // (undocumented) + disabled?: boolean; + // (undocumented) + isCompatible: (agg: IAggConfig) => boolean; + // (undocumented) + text: string; + // (undocumented) + value: string; +} + +// Warning: (ae-forgotten-export) The symbol "parseEsInterval" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "ParsedInterval" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type ParsedInterval = ReturnType; // Warning: (ae-missing-release-tag) "PhraseFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1039,7 +1279,7 @@ export class Plugin implements Plugin_2>; +export const QueryStringInput: React.FC>; // @public (undocumented) export type QuerySuggestion = QuerySuggestionBasic | QuerySuggestionField; @@ -1247,11 +1487,52 @@ export type SavedQueryTimeFilter = TimeRange & { refreshInterval: RefreshInterval; }; +// Warning: (ae-missing-release-tag) "search" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const search: { + aggs: { + AggConfigs: typeof AggConfigs; + aggGroupNamesMap: () => Record<"buckets" | "metrics", string>; + aggTypeFilters: import("./search/aggs/filter/agg_type_filters").AggTypeFilters; + CidrMask: typeof CidrMask; + convertDateRangeToString: typeof convertDateRangeToString; + convertIPRangeToString: (range: import("./search").IpRangeKey, format: (val: any) => string) => string; + dateHistogramInterval: typeof dateHistogramInterval; + intervalOptions: ({ + display: string; + val: string; + enabled(agg: import("./search/aggs/buckets/_bucket_agg_type").IBucketAggConfig): boolean | "" | undefined; + } | { + display: string; + val: string; + })[]; + InvalidEsCalendarIntervalError: typeof InvalidEsCalendarIntervalError; + InvalidEsIntervalFormatError: typeof InvalidEsIntervalFormatError; + isDateHistogramBucketAggConfig: typeof isDateHistogramBucketAggConfig; + isStringType: (agg: import("./search").AggConfig) => boolean; + isType: (type: string) => (agg: import("./search").AggConfig) => boolean; + isValidEsInterval: typeof isValidEsInterval; + isValidInterval: typeof isValidInterval; + parentPipelineType: string; + parseEsInterval: typeof parseEsInterval; + parseInterval: typeof parseInterval; + propFilter: typeof propFilter; + siblingPipelineType: string; + termsAggFilter: string[]; + toAbsoluteDates: typeof toAbsoluteDates; + }; + getRequestInspectorStats: typeof getRequestInspectorStats; + getResponseInspectorStats: typeof getResponseInspectorStats; + tabifyAggResponse: typeof tabifyAggResponse; + tabifyGetColumns: typeof tabifyGetColumns; +}; + // Warning: (ae-missing-release-tag) "SearchBar" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const SearchBar: React.ComponentClass, "query" | "isLoading" | "indexPatterns" | "filters" | "refreshInterval" | "screenTitle" | "dataTestSubj" | "customSubmitButton" | "showQueryBar" | "showQueryInput" | "showFilterBar" | "showDatePicker" | "showAutoRefreshOnly" | "isRefreshPaused" | "dateRangeFrom" | "dateRangeTo" | "showSaveQuery" | "savedQuery" | "onQueryChange" | "onQuerySubmit" | "onSaved" | "onSavedQueryUpdated" | "onClearSavedQuery" | "onRefresh" | "timeHistory" | "onFiltersUpdated" | "onRefreshChange">, any> & { - WrappedComponent: React.ComponentType & ReactIntl.InjectedIntlProps>; +export const SearchBar: React.ComponentClass, "query" | "isLoading" | "indexPatterns" | "filters" | "onQueryChange" | "customSubmitButton" | "screenTitle" | "dataTestSubj" | "showQueryBar" | "showQueryInput" | "showFilterBar" | "showDatePicker" | "showAutoRefreshOnly" | "isRefreshPaused" | "refreshInterval" | "dateRangeFrom" | "dateRangeTo" | "showSaveQuery" | "savedQuery" | "onQuerySubmit" | "onSaved" | "onSavedQueryUpdated" | "onClearSavedQuery" | "onRefresh" | "timeHistory" | "onFiltersUpdated" | "onRefreshChange">, any> & { + WrappedComponent: React.ComponentType & ReactIntl.InjectedIntlProps>; }; // Warning: (ae-forgotten-export) The symbol "SearchBarOwnProps" needs to be exported by the entry point index.d.ts @@ -1310,7 +1591,7 @@ export class SearchSource { type?: string | undefined; query?: import("../..").Query | undefined; filter?: Filter | Filter[] | (() => Filter | Filter[] | undefined) | undefined; - sort?: Record | Record[] | undefined; + sort?: Record | Record[] | undefined; highlight?: any; highlightAll?: boolean | undefined; aggs?: any; @@ -1446,6 +1727,27 @@ export const syncQueryStateWithUrl: (query: Pick<{ hasInheritedQueryFromUrl: boolean; }; +// @public (undocumented) +export interface TabbedAggColumn { + // (undocumented) + aggConfig: IAggConfig; + // (undocumented) + id: string; + // (undocumented) + name: string; +} + +// @public (undocumented) +export type TabbedAggRow = Record; + +// @public (undocumented) +export interface TabbedTable { + // (undocumented) + columns: TabbedAggColumn[]; + // (undocumented) + rows: TabbedAggRow[]; +} + // Warning: (ae-forgotten-export) The symbol "Timefilter" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "TimefilterContract" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1526,9 +1828,25 @@ 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:379:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:379:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:379:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:379:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:384:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:385:1 - (ae-forgotten-export) The symbol "convertDateRangeToString" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:387:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:396:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:397:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:398:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:401:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:402:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:405:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:406:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:409: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:34: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:38:1 - (ae-forgotten-export) The symbol "QueryStateChange" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/types.ts:54:5 - (ae-forgotten-export) The symbol "IndexPatternSelectProps" 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 +// src/plugins/data/public/types.ts:60:5 - (ae-forgotten-export) The symbol "IndexPatternSelectProps" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/src/plugins/data/public/query/filter_manager/lib/compare_filters.test.ts b/src/plugins/data/public/query/filter_manager/lib/compare_filters.test.ts index 5d6c25b0d96c1d..da8f5b3564948e 100644 --- a/src/plugins/data/public/query/filter_manager/lib/compare_filters.test.ts +++ b/src/plugins/data/public/query/filter_manager/lib/compare_filters.test.ts @@ -48,6 +48,22 @@ describe('filter manager utilities', () => { expect(compareFilters(f1, f2)).toBeTruthy(); }); + test('should compare filters, where one filter is null', () => { + const f1 = buildQueryFilter( + { _type: { match: { query: 'apache', type: 'phrase' } } }, + 'index', + '' + ); + const f2 = null; + expect(compareFilters(f1, f2 as any)).toBeFalsy(); + }); + + test('should compare a null filter with an empty filter', () => { + const f1 = null; + const f2 = buildEmptyFilter(true); + expect(compareFilters(f1 as any, f2)).toBeFalsy(); + }); + test('should compare duplicates, ignoring meta attributes', () => { const f1 = buildQueryFilter( { _type: { match: { query: 'apache', type: 'phrase' } } }, diff --git a/src/plugins/data/public/query/filter_manager/lib/compare_filters.ts b/src/plugins/data/public/query/filter_manager/lib/compare_filters.ts index b4402885bc0beb..a2105fdc1d3efb 100644 --- a/src/plugins/data/public/query/filter_manager/lib/compare_filters.ts +++ b/src/plugins/data/public/query/filter_manager/lib/compare_filters.ts @@ -74,6 +74,8 @@ export const compareFilters = ( second: Filter | Filter[], comparatorOptions: FilterCompareOptions = {} ) => { + if (!first || !second) return false; + let comparators: FilterCompareOptions = {}; const excludedAttributes: string[] = ['$$hashKey', 'meta']; diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_config.test.ts b/src/plugins/data/public/search/aggs/agg_config.test.ts similarity index 96% rename from src/legacy/core_plugins/data/public/search/aggs/agg_config.test.ts rename to src/plugins/data/public/search/aggs/agg_config.test.ts index 36d5451a4cd00f..f979c9664f458a 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/agg_config.test.ts +++ b/src/plugins/data/public/search/aggs/agg_config.test.ts @@ -24,13 +24,10 @@ import { AggConfigs, CreateAggConfigParams } from './agg_configs'; import { AggType } from './agg_type'; import { AggTypesRegistryStart } from './agg_types_registry'; import { mockDataServices, mockAggTypesRegistry } from './test_helpers'; -import { IndexPatternField, IndexPattern } from '../../../../../../plugins/data/public'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { stubIndexPatternWithFields } from '../../../../../../plugins/data/public/stubs'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { dataPluginMock } from '../../../../../../plugins/data/public/mocks'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { setFieldFormats } from '../../../../../../plugins/data/public/services'; +import { Field as IndexPatternField, IndexPattern } from '../../index_patterns'; +import { stubIndexPatternWithFields } from '../../../public/stubs'; +import { dataPluginMock } from '../../../public/mocks'; +import { setFieldFormats } from '../../../public/services'; describe('AggConfig', () => { let indexPattern: IndexPattern; diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_config.ts b/src/plugins/data/public/search/aggs/agg_config.ts similarity index 97% rename from src/legacy/core_plugins/data/public/search/aggs/agg_config.ts rename to src/plugins/data/public/search/aggs/agg_config.ts index bf2d2f734c9896..d6948aaade63d7 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/agg_config.ts +++ b/src/plugins/data/public/search/aggs/agg_config.ts @@ -22,14 +22,10 @@ import { i18n } from '@kbn/i18n'; import { IAggType } from './agg_type'; import { writeParams } from './agg_params'; import { IAggConfigs } from './agg_configs'; -import { - ISearchSource, - FetchOptions, - FieldFormatsContentType, - KBN_FIELD_TYPES, -} from '../../../../../../plugins/data/public'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getFieldFormats } from '../../../../../../plugins/data/public/services'; +import { FetchOptions } from '../fetch'; +import { ISearchSource } from '../search_source'; +import { FieldFormatsContentType, KBN_FIELD_TYPES } from '../../../common'; +import { getFieldFormats } from '../../../public/services'; export interface AggConfigOptions { type: IAggType; diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_configs.test.ts b/src/plugins/data/public/search/aggs/agg_configs.test.ts similarity index 98% rename from src/legacy/core_plugins/data/public/search/aggs/agg_configs.test.ts rename to src/plugins/data/public/search/aggs/agg_configs.test.ts index d69376b4026d95..e20e6de6112a8a 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/agg_configs.test.ts +++ b/src/plugins/data/public/search/aggs/agg_configs.test.ts @@ -22,12 +22,8 @@ import { AggConfig } from './agg_config'; import { AggConfigs } from './agg_configs'; import { AggTypesRegistryStart } from './agg_types_registry'; import { mockDataServices, mockAggTypesRegistry } from './test_helpers'; -import { IndexPatternField, IndexPattern } from '../../../../../../plugins/data/public'; -import { - stubIndexPattern, - stubIndexPatternWithFields, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../../../plugins/data/public/stubs'; +import { Field as IndexPatternField, IndexPattern } from '../../index_patterns'; +import { stubIndexPattern, stubIndexPatternWithFields } from '../../../public/stubs'; describe('AggConfigs', () => { let indexPattern: IndexPattern; diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_configs.ts b/src/plugins/data/public/search/aggs/agg_configs.ts similarity index 98% rename from src/legacy/core_plugins/data/public/search/aggs/agg_configs.ts rename to src/plugins/data/public/search/aggs/agg_configs.ts index 4a48f356d3f796..c441b2a0eb46f8 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/agg_configs.ts +++ b/src/plugins/data/public/search/aggs/agg_configs.ts @@ -24,12 +24,10 @@ import { AggConfig, AggConfigOptions, IAggConfig } from './agg_config'; import { IAggType } from './agg_type'; import { AggTypesRegistryStart } from './agg_types_registry'; import { AggGroupNames } from './agg_groups'; -import { - IndexPattern, - ISearchSource, - FetchOptions, - TimeRange, -} from '../../../../../../plugins/data/public'; +import { IndexPattern } from '../../index_patterns'; +import { ISearchSource } from '../search_source'; +import { FetchOptions } from '../fetch'; +import { TimeRange } from '../../../common'; function removeParentAggs(obj: any) { for (const prop in obj) { diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_groups.ts b/src/plugins/data/public/search/aggs/agg_groups.ts similarity index 86% rename from src/legacy/core_plugins/data/public/search/aggs/agg_groups.ts rename to src/plugins/data/public/search/aggs/agg_groups.ts index d21f5c8968840f..9cebff76c96843 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/agg_groups.ts +++ b/src/plugins/data/public/search/aggs/agg_groups.ts @@ -25,9 +25,11 @@ export const AggGroupNames = Object.freeze({ Metrics: 'metrics' as 'metrics', None: 'none' as 'none', }); -export type AggGroupNames = $Values; +export type IAggGroupNames = $Values; -export const aggGroupNamesMap = () => ({ +type IAggGroupNamesMap = () => Record<'buckets' | 'metrics', string>; + +export const aggGroupNamesMap: IAggGroupNamesMap = () => ({ [AggGroupNames.Metrics]: i18n.translate('data.search.aggs.aggGroups.metricsText', { defaultMessage: 'Metrics', }), diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_params.test.ts b/src/plugins/data/public/search/aggs/agg_params.test.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/agg_params.test.ts rename to src/plugins/data/public/search/aggs/agg_params.test.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_params.ts b/src/plugins/data/public/search/aggs/agg_params.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/agg_params.ts rename to src/plugins/data/public/search/aggs/agg_params.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_type.test.ts b/src/plugins/data/public/search/aggs/agg_type.test.ts similarity index 95% rename from src/legacy/core_plugins/data/public/search/aggs/agg_type.test.ts rename to src/plugins/data/public/search/aggs/agg_type.test.ts index c78e56dd25887d..3fb03dc31e2b2b 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/agg_type.test.ts +++ b/src/plugins/data/public/search/aggs/agg_type.test.ts @@ -20,9 +20,8 @@ import { AggType, AggTypeConfig } from './agg_type'; import { IAggConfig } from './agg_config'; import { mockDataServices } from './test_helpers'; -import { dataPluginMock } from '../../../../../../plugins/data/public/mocks'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { setFieldFormats } from '../../../../../../plugins/data/public/services'; +import { dataPluginMock } from '../../../public/mocks'; +import { setFieldFormats } from '../../../public/services'; describe('AggType Class', () => { beforeEach(() => { diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_type.ts b/src/plugins/data/public/search/aggs/agg_type.ts similarity index 96% rename from src/legacy/core_plugins/data/public/search/aggs/agg_type.ts rename to src/plugins/data/public/search/aggs/agg_type.ts index 3cd9496d3f23d0..a63d01e196612a 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/agg_type.ts +++ b/src/plugins/data/public/search/aggs/agg_type.ts @@ -23,16 +23,12 @@ import { initParams } from './agg_params'; import { AggConfig } from './agg_config'; import { IAggConfigs } from './agg_configs'; -import { Adapters } from '../../../../../../plugins/inspector/public'; +import { Adapters } from '../../../../../plugins/inspector/public'; import { BaseParamType } from './param_types/base'; import { AggParamType } from './param_types/agg'; -import { - KBN_FIELD_TYPES, - IFieldFormat, - ISearchSource, -} from '../../../../../../plugins/data/public'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getFieldFormats } from '../../../../../../plugins/data/public/services'; +import { KBN_FIELD_TYPES, IFieldFormat } from '../../../common'; +import { ISearchSource } from '../search_source'; +import { getFieldFormats } from '../../../public/services'; export interface AggTypeConfig< TAggConfig extends AggConfig = AggConfig, diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_types.ts b/src/plugins/data/public/search/aggs/agg_types.ts similarity index 70% rename from src/legacy/core_plugins/data/public/search/aggs/agg_types.ts rename to src/plugins/data/public/search/aggs/agg_types.ts index 691598fe27e313..73c6a5046fd23c 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/agg_types.ts +++ b/src/plugins/data/public/search/aggs/agg_types.ts @@ -17,6 +17,8 @@ * under the License. */ +import { IUiSettingsClient } from 'src/core/public'; + import { countMetricAgg } from './metrics/count'; import { avgMetricAgg } from './metrics/avg'; import { sumMetricAgg } from './metrics/sum'; @@ -41,7 +43,7 @@ import { dateRangeBucketAgg } from './buckets/date_range'; import { ipRangeBucketAgg } from './buckets/ip_range'; import { termsBucketAgg } from './buckets/terms'; import { filterBucketAgg } from './buckets/filter'; -import { filtersBucketAgg } from './buckets/filters'; +import { getFiltersBucketAgg } from './buckets/filters'; import { significantTermsBucketAgg } from './buckets/significant_terms'; import { geoHashBucketAgg } from './buckets/geo_hash'; import { geoTileBucketAgg } from './buckets/geo_tile'; @@ -50,41 +52,44 @@ import { bucketAvgMetricAgg } from './metrics/bucket_avg'; import { bucketMinMetricAgg } from './metrics/bucket_min'; import { bucketMaxMetricAgg } from './metrics/bucket_max'; -export const aggTypes = { - metrics: [ - countMetricAgg, - avgMetricAgg, - sumMetricAgg, - medianMetricAgg, - minMetricAgg, - maxMetricAgg, - stdDeviationMetricAgg, - cardinalityMetricAgg, - percentilesMetricAgg, - percentileRanksMetricAgg, - topHitMetricAgg, - derivativeMetricAgg, - cumulativeSumMetricAgg, - movingAvgMetricAgg, - serialDiffMetricAgg, - bucketAvgMetricAgg, - bucketSumMetricAgg, - bucketMinMetricAgg, - bucketMaxMetricAgg, - geoBoundsMetricAgg, - geoCentroidMetricAgg, - ], - buckets: [ - dateHistogramBucketAgg, - histogramBucketAgg, - rangeBucketAgg, - dateRangeBucketAgg, - ipRangeBucketAgg, - termsBucketAgg, - filterBucketAgg, - filtersBucketAgg, - significantTermsBucketAgg, - geoHashBucketAgg, - geoTileBucketAgg, - ], -}; +export function getAggTypes(deps: { uiSettings: IUiSettingsClient }) { + const { uiSettings } = deps; + return { + metrics: [ + countMetricAgg, + avgMetricAgg, + sumMetricAgg, + medianMetricAgg, + minMetricAgg, + maxMetricAgg, + stdDeviationMetricAgg, + cardinalityMetricAgg, + percentilesMetricAgg, + percentileRanksMetricAgg, + topHitMetricAgg, + derivativeMetricAgg, + cumulativeSumMetricAgg, + movingAvgMetricAgg, + serialDiffMetricAgg, + bucketAvgMetricAgg, + bucketSumMetricAgg, + bucketMinMetricAgg, + bucketMaxMetricAgg, + geoBoundsMetricAgg, + geoCentroidMetricAgg, + ], + buckets: [ + dateHistogramBucketAgg, + histogramBucketAgg, + rangeBucketAgg, + dateRangeBucketAgg, + ipRangeBucketAgg, + termsBucketAgg, + filterBucketAgg, + getFiltersBucketAgg({ uiSettings }), + significantTermsBucketAgg, + geoHashBucketAgg, + geoTileBucketAgg, + ], + }; +} diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_types_registry.test.ts b/src/plugins/data/public/search/aggs/agg_types_registry.test.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/agg_types_registry.test.ts rename to src/plugins/data/public/search/aggs/agg_types_registry.test.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/agg_types_registry.ts b/src/plugins/data/public/search/aggs/agg_types_registry.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/agg_types_registry.ts rename to src/plugins/data/public/search/aggs/agg_types_registry.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/_bucket_agg_type.ts b/src/plugins/data/public/search/aggs/buckets/_bucket_agg_type.ts similarity index 96% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/_bucket_agg_type.ts rename to src/plugins/data/public/search/aggs/buckets/_bucket_agg_type.ts index d6ab58d5250a8c..03629c3189cbb4 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/_bucket_agg_type.ts +++ b/src/plugins/data/public/search/aggs/buckets/_bucket_agg_type.ts @@ -18,7 +18,7 @@ */ import { IAggConfig } from '../agg_config'; -import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../common'; import { AggType, AggTypeConfig } from '../agg_type'; import { AggParamType } from '../param_types/agg'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/_interval_options.ts b/src/plugins/data/public/search/aggs/buckets/_interval_options.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/_interval_options.ts rename to src/plugins/data/public/search/aggs/buckets/_interval_options.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.test.ts b/src/plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.test.ts similarity index 99% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.test.ts rename to src/plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.test.ts index 976ab57c00b631..9e4b93035384f6 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.test.ts @@ -217,8 +217,6 @@ const nestedOtherResponse = { status: 200, }; -jest.mock('ui/new_platform'); - describe('Terms Agg Other bucket helper', () => { const typesRegistry = mockAggTypesRegistry(); const getAggConfigs = (aggs: CreateAggConfigParams[] = []) => { diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.ts b/src/plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.ts similarity index 96% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.ts rename to src/plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.ts index 42db37c81eadd6..4fd988e7b7e663 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.ts +++ b/src/plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.ts @@ -18,7 +18,7 @@ */ import { isNumber, keys, values, find, each, cloneDeep, flatten } from 'lodash'; -import { esFilters, esQuery } from '../../../../../../../plugins/data/public'; +import { buildExistsFilter, buildPhrasesFilter, buildQueryFromFilters } from '../../../../common'; import { AggGroupNames } from '../agg_groups'; import { IAggConfigs } from '../agg_configs'; import { IBucketAggConfig } from './_bucket_agg_type'; @@ -207,7 +207,7 @@ export const buildOtherBucketAgg = ( agg.buckets.some((bucket: { key: string }) => bucket.key === '__missing__') ) { filters.push( - esFilters.buildExistsFilter( + buildExistsFilter( aggWithOtherBucket.params.field, aggWithOtherBucket.params.field.indexPattern ) @@ -223,7 +223,7 @@ export const buildOtherBucketAgg = ( }); resultAgg.filters.filters[key] = { - bool: esQuery.buildQueryFromFilters(filters, indexPattern), + bool: buildQueryFromFilters(filters, indexPattern), }; }; walkBucketTree(0, response.aggregations, bucketAggs[0].id, [], ''); @@ -259,7 +259,7 @@ export const mergeOtherBucketAggResponse = ( ); const requestFilterTerms = getOtherAggTerms(requestAgg, key, otherAgg); - const phraseFilter = esFilters.buildPhrasesFilter( + const phraseFilter = buildPhrasesFilter( otherAgg.params.field, requestFilterTerms, otherAgg.params.field.indexPattern @@ -274,7 +274,7 @@ export const mergeOtherBucketAggResponse = ( ) ) { bucket.filters.push( - esFilters.buildExistsFilter(otherAgg.params.field, otherAgg.params.field.indexPattern) + buildExistsFilter(otherAgg.params.field, otherAgg.params.field.indexPattern) ); } aggResultBuckets.push(bucket); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/bucket_agg_types.ts b/src/plugins/data/public/search/aggs/buckets/bucket_agg_types.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/bucket_agg_types.ts rename to src/plugins/data/public/search/aggs/buckets/bucket_agg_types.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts similarity index 98% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts rename to src/plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts index f21ca6c975809a..12817a9ba11591 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts @@ -24,7 +24,7 @@ import { AggConfigs } from '../../agg_configs'; import { mockDataServices, mockAggTypesRegistry } from '../../test_helpers'; import { dateHistogramBucketAgg, IBucketDateHistogramAggConfig } from '../date_histogram'; import { BUCKET_TYPES } from '../bucket_agg_types'; -import { RangeFilter } from '../../../../../../../../plugins/data/public'; +import { RangeFilter } from '../../../../../common'; describe('AggConfig Filters', () => { describe('date_histogram', () => { diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/date_histogram.ts similarity index 92% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.ts rename to src/plugins/data/public/search/aggs/buckets/create_filter/date_histogram.ts index e634b5daf0ac38..42b263415ff905 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_histogram.ts +++ b/src/plugins/data/public/search/aggs/buckets/create_filter/date_histogram.ts @@ -19,7 +19,7 @@ import moment from 'moment'; import { IBucketDateHistogramAggConfig } from '../date_histogram'; -import { esFilters } from '../../../../../../../../plugins/data/public'; +import { buildRangeFilter } from '../../../../../common'; export const createFilterDateHistogram = ( agg: IBucketDateHistogramAggConfig, @@ -28,7 +28,7 @@ export const createFilterDateHistogram = ( const start = moment(key); const interval = agg.buckets.getInterval(); - return esFilters.buildRangeFilter( + return buildRangeFilter( agg.params.field, { gte: start.toISOString(), diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts similarity index 94% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts rename to src/plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts index c594c7718e58bb..d18a30fb6c6f8a 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts @@ -20,7 +20,8 @@ import moment from 'moment'; import { dateRangeBucketAgg } from '../date_range'; import { createFilterDateRange } from './date_range'; -import { fieldFormats, FieldFormatsGetConfigFn } from '../../../../../../../../plugins/data/public'; +import { FieldFormatsGetConfigFn } from '../../../../../common'; +import { DateFormat } from '../../../../field_formats'; import { AggConfigs } from '../../agg_configs'; import { mockAggTypesRegistry } from '../../test_helpers'; import { BUCKET_TYPES } from '../bucket_agg_types'; @@ -33,7 +34,7 @@ describe('AggConfig Filters', () => { const getAggConfigs = () => { const field = { name: '@timestamp', - format: new fieldFormats.DateFormat({}, getConfig), + format: new DateFormat({}, getConfig), }; const indexPattern = { diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/date_range.ts similarity index 84% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.ts rename to src/plugins/data/public/search/aggs/buckets/create_filter/date_range.ts index 7af8ebc3236a77..9bfded0ce9729f 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/date_range.ts +++ b/src/plugins/data/public/search/aggs/buckets/create_filter/date_range.ts @@ -19,8 +19,8 @@ import moment from 'moment'; import { IBucketAggConfig } from '../_bucket_agg_type'; -import { DateRangeKey } from '../date_range'; -import { esFilters, RangeFilterParams } from '../../../../../../../../plugins/data/public'; +import { DateRangeKey } from '../lib/date_range'; +import { buildRangeFilter, RangeFilterParams } from '../../../../../common'; export const createFilterDateRange = (agg: IBucketAggConfig, { from, to }: DateRangeKey) => { const filter: RangeFilterParams = {}; @@ -28,5 +28,5 @@ export const createFilterDateRange = (agg: IBucketAggConfig, { from, to }: DateR if (to) filter.lt = moment(to).toISOString(); if (to && from) filter.format = 'strict_date_optional_time'; - return esFilters.buildRangeFilter(agg.params.field, filter, agg.getIndexPattern()); + return buildRangeFilter(agg.params.field, filter, agg.getIndexPattern()); }; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/filters.test.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/filters.test.ts similarity index 87% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/filters.test.ts rename to src/plugins/data/public/search/aggs/buckets/create_filter/filters.test.ts index 3b9c771e0f15f9..33ab1ce8186a11 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/filters.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/create_filter/filters.test.ts @@ -17,7 +17,9 @@ * under the License. */ -import { filtersBucketAgg } from '../filters'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { coreMock } from '../../../../../../../../src/core/public/mocks'; +import { getFiltersBucketAgg } from '../filters'; import { createFilterFilters } from './filters'; import { AggConfigs } from '../../agg_configs'; import { mockDataServices, mockAggTypesRegistry } from '../../test_helpers'; @@ -29,7 +31,11 @@ describe('AggConfig Filters', () => { mockDataServices(); }); - const typesRegistry = mockAggTypesRegistry([filtersBucketAgg]); + const typesRegistry = mockAggTypesRegistry([ + getFiltersBucketAgg({ + uiSettings: coreMock.createSetup().uiSettings, + }), + ]); const getAggConfigs = () => { const field = { diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/filters.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/filters.ts similarity index 89% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/filters.ts rename to src/plugins/data/public/search/aggs/buckets/create_filter/filters.ts index 715f6895374e63..3b568d805f7c0d 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/filters.ts +++ b/src/plugins/data/public/search/aggs/buckets/create_filter/filters.ts @@ -19,7 +19,7 @@ import { get } from 'lodash'; import { IBucketAggConfig } from '../_bucket_agg_type'; -import { esFilters } from '../../../../../../../../plugins/data/public'; +import { buildQueryFilter } from '../../../../../common'; export const createFilterFilters = (aggConfig: IBucketAggConfig, key: string) => { // have the aggConfig write agg dsl params @@ -28,6 +28,6 @@ export const createFilterFilters = (aggConfig: IBucketAggConfig, key: string) => const indexPattern = aggConfig.getIndexPattern(); if (filter && indexPattern && indexPattern.id) { - return esFilters.buildQueryFilter(filter.query, indexPattern.id, key); + return buildQueryFilter(filter.query, indexPattern.id, key); } }; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts similarity index 94% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts rename to src/plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts index b046c802c58c15..dc8414d80c0243 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts @@ -22,7 +22,7 @@ import { AggConfigs } from '../../agg_configs'; import { mockDataServices, mockAggTypesRegistry } from '../../test_helpers'; import { BUCKET_TYPES } from '../bucket_agg_types'; import { IBucketAggConfig } from '../_bucket_agg_type'; -import { fieldFormats, FieldFormatsGetConfigFn } from '../../../../../../../../plugins/data/public'; +import { BytesFormat, FieldFormatsGetConfigFn } from '../../../../../common'; describe('AggConfig Filters', () => { describe('histogram', () => { @@ -36,7 +36,7 @@ describe('AggConfig Filters', () => { const getAggConfigs = () => { const field = { name: 'bytes', - format: new fieldFormats.BytesFormat({}, getConfig), + format: new BytesFormat({}, getConfig), }; const indexPattern = { diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/histogram.ts similarity index 90% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.ts rename to src/plugins/data/public/search/aggs/buckets/create_filter/histogram.ts index badd6dba6ea8a9..d4c00a0991fe2c 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/histogram.ts +++ b/src/plugins/data/public/search/aggs/buckets/create_filter/histogram.ts @@ -18,13 +18,13 @@ */ import { IBucketAggConfig } from '../_bucket_agg_type'; -import { esFilters, RangeFilterParams } from '../../../../../../../../plugins/data/public'; +import { buildRangeFilter, RangeFilterParams } from '../../../../../common'; export const createFilterHistogram = (aggConfig: IBucketAggConfig, key: string) => { const value = parseInt(key, 10); const params: RangeFilterParams = { gte: value, lt: value + aggConfig.params.interval }; - return esFilters.buildRangeFilter( + return buildRangeFilter( aggConfig.params.field, params, aggConfig.getIndexPattern(), diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts similarity index 96% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts rename to src/plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts index 7572c48390dc25..ca51094da2f58a 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts @@ -21,7 +21,7 @@ import { ipRangeBucketAgg } from '../ip_range'; import { createFilterIpRange } from './ip_range'; import { AggConfigs, CreateAggConfigParams } from '../../agg_configs'; import { mockAggTypesRegistry } from '../../test_helpers'; -import { fieldFormats } from '../../../../../../../../plugins/data/public'; +import { IpFormat } from '../../../../../common'; import { BUCKET_TYPES } from '../bucket_agg_types'; import { IBucketAggConfig } from '../_bucket_agg_type'; @@ -31,7 +31,7 @@ describe('AggConfig Filters', () => { const getAggConfigs = (aggs: CreateAggConfigParams[]) => { const field = { name: 'ip', - format: fieldFormats.IpFormat, + format: IpFormat, }; const indexPattern = { diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/ip_range.ts similarity index 88% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.ts rename to src/plugins/data/public/search/aggs/buckets/create_filter/ip_range.ts index 36be4143838240..2d34c45aaab9da 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/ip_range.ts +++ b/src/plugins/data/public/search/aggs/buckets/create_filter/ip_range.ts @@ -19,8 +19,8 @@ import { CidrMask } from '../lib/cidr_mask'; import { IBucketAggConfig } from '../_bucket_agg_type'; -import { IpRangeKey } from '../ip_range'; -import { esFilters, RangeFilterParams } from '../../../../../../../../plugins/data/public'; +import { IpRangeKey } from '../lib/ip_range'; +import { buildRangeFilter, RangeFilterParams } from '../../../../../common'; export const createFilterIpRange = (aggConfig: IBucketAggConfig, key: IpRangeKey) => { let range: RangeFilterParams; @@ -34,7 +34,7 @@ export const createFilterIpRange = (aggConfig: IBucketAggConfig, key: IpRangeKey }; } - return esFilters.buildRangeFilter( + return buildRangeFilter( aggConfig.params.field, { gte: range.from, lte: range.to }, aggConfig.getIndexPattern() diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.test.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/range.test.ts similarity index 94% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.test.ts rename to src/plugins/data/public/search/aggs/buckets/create_filter/range.test.ts index 324d4252908324..3a6f8b36a9d964 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/create_filter/range.test.ts @@ -19,7 +19,7 @@ import { rangeBucketAgg } from '../range'; import { createFilterRange } from './range'; -import { fieldFormats, FieldFormatsGetConfigFn } from '../../../../../../../../plugins/data/public'; +import { BytesFormat, FieldFormatsGetConfigFn } from '../../../../../common'; import { AggConfigs } from '../../agg_configs'; import { mockDataServices, mockAggTypesRegistry } from '../../test_helpers'; import { BUCKET_TYPES } from '../bucket_agg_types'; @@ -37,7 +37,7 @@ describe('AggConfig Filters', () => { const getAggConfigs = () => { const field = { name: 'bytes', - format: new fieldFormats.BytesFormat({}, getConfig), + format: new BytesFormat({}, getConfig), }; const indexPattern = { diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/range.ts similarity index 90% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.ts rename to src/plugins/data/public/search/aggs/buckets/create_filter/range.ts index 125a30a1ab1dd3..d3d85f2441a8ba 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/range.ts +++ b/src/plugins/data/public/search/aggs/buckets/create_filter/range.ts @@ -18,10 +18,10 @@ */ import { IBucketAggConfig } from '../_bucket_agg_type'; -import { esFilters } from '../../../../../../../../plugins/data/public'; +import { buildRangeFilter } from '../../../../../common'; export const createFilterRange = (aggConfig: IBucketAggConfig, params: any) => { - return esFilters.buildRangeFilter( + return buildRangeFilter( aggConfig.params.field, params, aggConfig.getIndexPattern(), diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts similarity index 98% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts rename to src/plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts index 6db6eb11a5f527..511af450b0113a 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts @@ -23,7 +23,7 @@ import { AggConfigs, CreateAggConfigParams } from '../../agg_configs'; import { mockAggTypesRegistry } from '../../test_helpers'; import { BUCKET_TYPES } from '../bucket_agg_types'; import { IBucketAggConfig } from '../_bucket_agg_type'; -import { Filter, ExistsFilter } from '../../../../../../../../plugins/data/public'; +import { Filter, ExistsFilter } from '../../../../../common'; describe('AggConfig Filters', () => { describe('terms', () => { diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.ts b/src/plugins/data/public/search/aggs/buckets/create_filter/terms.ts similarity index 78% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.ts rename to src/plugins/data/public/search/aggs/buckets/create_filter/terms.ts index 4152258ffa0ee0..43ebfc0e90db2b 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/create_filter/terms.ts +++ b/src/plugins/data/public/search/aggs/buckets/create_filter/terms.ts @@ -18,7 +18,12 @@ */ import { IBucketAggConfig } from '../_bucket_agg_type'; -import { esFilters, Filter } from '../../../../../../../../plugins/data/public'; +import { + buildPhrasesFilter, + buildExistsFilter, + buildPhraseFilter, + Filter, +} from '../../../../../common'; export const createFilterTerms = (aggConfig: IBucketAggConfig, key: string, params: any) => { const field = aggConfig.params.field; @@ -27,20 +32,20 @@ export const createFilterTerms = (aggConfig: IBucketAggConfig, key: string, para if (key === '__other__') { const terms = params.terms; - const phraseFilter = esFilters.buildPhrasesFilter(field, terms, indexPattern); + const phraseFilter = buildPhrasesFilter(field, terms, indexPattern); phraseFilter.meta.negate = true; const filters: Filter[] = [phraseFilter]; if (terms.some((term: string) => term === '__missing__')) { - filters.push(esFilters.buildExistsFilter(field, indexPattern)); + filters.push(buildExistsFilter(field, indexPattern)); } return filters; } else if (key === '__missing__') { - const existsFilter = esFilters.buildExistsFilter(field, indexPattern); + const existsFilter = buildExistsFilter(field, indexPattern); existsFilter.meta.negate = true; return existsFilter; } - return esFilters.buildPhraseFilter(field, key, indexPattern); + return buildPhraseFilter(field, key, indexPattern); }; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/date_histogram.ts b/src/plugins/data/public/search/aggs/buckets/date_histogram.ts similarity index 95% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/date_histogram.ts rename to src/plugins/data/public/search/aggs/buckets/date_histogram.ts index 8c8911bda99a5d..d600b16f567647 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/date_histogram.ts +++ b/src/plugins/data/public/search/aggs/buckets/date_histogram.ts @@ -30,17 +30,9 @@ import { dateHistogramInterval } from '../../../../common'; import { writeParams } from '../agg_params'; import { isMetricAggType } from '../metrics/metric_agg_type'; -import { - fieldFormats, - KBN_FIELD_TYPES, - TimefilterContract, -} from '../../../../../../../plugins/data/public'; -import { - getFieldFormats, - getQueryService, - getUiSettings, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../../../../plugins/data/public/services'; +import { FIELD_FORMAT_IDS, KBN_FIELD_TYPES } from '../../../../common'; +import { TimefilterContract } from '../../../query'; +import { getFieldFormats, getQueryService, getUiSettings } from '../../../../public/services'; const detectedTimezone = moment.tz.guess(); const tzOffset = moment().format('Z'); @@ -117,7 +109,7 @@ export const dateHistogramBucketAgg = new BucketAggType { beforeEach(() => { diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/date_range.ts b/src/plugins/data/public/search/aggs/buckets/date_range.ts similarity index 87% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/date_range.ts rename to src/plugins/data/public/search/aggs/buckets/date_range.ts index 933cdd0577f8da..59e78af2d7b956 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/date_range.ts +++ b/src/plugins/data/public/search/aggs/buckets/date_range.ts @@ -23,13 +23,10 @@ import { i18n } from '@kbn/i18n'; import { BUCKET_TYPES } from './bucket_agg_types'; import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; import { createFilterDateRange } from './create_filter/date_range'; - -import { KBN_FIELD_TYPES, fieldFormats } from '../../../../../../../plugins/data/public'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getFieldFormats, getUiSettings } from '../../../../../../../plugins/data/public/services'; - import { convertDateRangeToString, DateRangeKey } from './lib/date_range'; -export { convertDateRangeToString, DateRangeKey }; // for BWC + +import { KBN_FIELD_TYPES, FieldFormat, TEXT_CONTEXT_TYPE } from '../../../../common'; +import { getFieldFormats, getUiSettings } from '../../../../public/services'; const dateRangeTitle = i18n.translate('data.search.aggs.buckets.dateRangeTitle', { defaultMessage: 'Date Range', @@ -46,10 +43,10 @@ export const dateRangeBucketAgg = new BucketAggType({ const fieldFormatsService = getFieldFormats(); const formatter = agg.fieldOwnFormatter( - fieldFormats.TEXT_CONTEXT_TYPE, + TEXT_CONTEXT_TYPE, fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.DATE) ); - const DateRangeFormat = fieldFormats.FieldFormat.from(function(range: DateRangeKey) { + const DateRangeFormat = FieldFormat.from(function(range: DateRangeKey) { return convertDateRangeToString(range, formatter); }); return new DateRangeFormat(); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/filter.ts b/src/plugins/data/public/search/aggs/buckets/filter.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/filter.ts rename to src/plugins/data/public/search/aggs/buckets/filter.ts diff --git a/src/plugins/data/public/search/aggs/buckets/filters.ts b/src/plugins/data/public/search/aggs/buckets/filters.ts new file mode 100644 index 00000000000000..0ad28b8be2132c --- /dev/null +++ b/src/plugins/data/public/search/aggs/buckets/filters.ts @@ -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 _ from 'lodash'; +import { i18n } from '@kbn/i18n'; + +import { IUiSettingsClient } from 'src/core/public'; + +import { createFilterFilters } from './create_filter/filters'; +import { toAngularJSON } from '../utils'; +import { BucketAggType } from './_bucket_agg_type'; +import { BUCKET_TYPES } from './bucket_agg_types'; +import { Storage } from '../../../../../../plugins/kibana_utils/public'; + +import { getEsQueryConfig, buildEsQuery, Query } from '../../../../common'; +import { getQueryLog } from '../../../query'; + +const filtersTitle = i18n.translate('data.search.aggs.buckets.filtersTitle', { + defaultMessage: 'Filters', + description: + 'The name of an aggregation, that allows to specify multiple individual filters to group data by.', +}); + +interface FilterValue { + input: Query; + label: string; + id: string; +} + +export function getFiltersBucketAgg(deps: { uiSettings: IUiSettingsClient }) { + const { uiSettings } = deps; + return new BucketAggType({ + name: BUCKET_TYPES.FILTERS, + title: filtersTitle, + createFilter: createFilterFilters, + customLabels: false, + params: [ + { + name: 'filters', + default: [ + { input: { query: '', language: uiSettings.get('search:queryLanguage') }, label: '' }, + ], + write(aggConfig, output) { + const inFilters: FilterValue[] = aggConfig.params.filters; + if (!_.size(inFilters)) return; + + inFilters.forEach(filter => { + const persistedLog = getQueryLog( + uiSettings, + new Storage(window.localStorage), + 'vis_default_editor', + filter.input.language + ); + persistedLog.add(filter.input.query); + }); + + const outFilters = _.transform( + inFilters, + function(filters, filter) { + const input = _.cloneDeep(filter.input); + + if (!input) { + console.log('malformed filter agg params, missing "input" query'); // eslint-disable-line no-console + return; + } + + const esQueryConfigs = getEsQueryConfig(uiSettings); + const query = buildEsQuery(aggConfig.getIndexPattern(), [input], [], esQueryConfigs); + + if (!query) { + console.log('malformed filter agg params, missing "query" on input'); // eslint-disable-line no-console + return; + } + + const matchAllLabel = filter.input.query === '' ? '*' : ''; + const label = + filter.label || + matchAllLabel || + (typeof filter.input.query === 'string' + ? filter.input.query + : toAngularJSON(filter.input.query)); + filters[label] = { query }; + }, + {} + ); + + if (!_.size(outFilters)) return; + + const params = output.params || (output.params = {}); + params.filters = outFilters; + }, + }, + ], + }); +} diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.test.ts b/src/plugins/data/public/search/aggs/buckets/geo_hash.test.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.test.ts rename to src/plugins/data/public/search/aggs/buckets/geo_hash.test.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.ts b/src/plugins/data/public/search/aggs/buckets/geo_hash.ts similarity index 97% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.ts rename to src/plugins/data/public/search/aggs/buckets/geo_hash.ts index 8732f926b0fb2e..3ffec09a843878 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_hash.ts +++ b/src/plugins/data/public/search/aggs/buckets/geo_hash.ts @@ -19,7 +19,7 @@ import { i18n } from '@kbn/i18n'; import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; -import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../common'; import { BUCKET_TYPES } from './bucket_agg_types'; const defaultBoundingBox = { diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_tile.ts b/src/plugins/data/public/search/aggs/buckets/geo_tile.ts similarity index 96% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/geo_tile.ts rename to src/plugins/data/public/search/aggs/buckets/geo_tile.ts index 9142a30338163c..759601fc0c180c 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/geo_tile.ts +++ b/src/plugins/data/public/search/aggs/buckets/geo_tile.ts @@ -22,7 +22,7 @@ import { noop } from 'lodash'; import { BucketAggType } from './_bucket_agg_type'; import { BUCKET_TYPES } from './bucket_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../common'; import { IBucketAggConfig } from './_bucket_agg_type'; import { METRIC_TYPES } from '../metrics/metric_agg_types'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.test.ts b/src/plugins/data/public/search/aggs/buckets/histogram.test.ts similarity index 98% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.test.ts rename to src/plugins/data/public/search/aggs/buckets/histogram.test.ts index 11dc8e42fd6538..07cf022dca83c7 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/histogram.test.ts @@ -17,14 +17,14 @@ * under the License. */ +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { coreMock } from '../../../../../../../src/core/public/mocks'; +import { setUiSettings } from '../../../../public/services'; import { AggConfigs } from '../agg_configs'; import { mockDataServices, mockAggTypesRegistry } from '../test_helpers'; import { BUCKET_TYPES } from './bucket_agg_types'; import { IBucketHistogramAggConfig, histogramBucketAgg, AutoBounds } from './histogram'; import { BucketAggType } from './_bucket_agg_type'; -import { coreMock } from '../../../../../../../../src/core/public/mocks'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { setUiSettings } from '../../../../../../../plugins/data/public/services'; describe('Histogram Agg', () => { beforeEach(() => { diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.ts b/src/plugins/data/public/search/aggs/buckets/histogram.ts similarity index 96% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.ts rename to src/plugins/data/public/search/aggs/buckets/histogram.ts index 70df2f230db094..7ccd5ae4bf98c8 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/histogram.ts +++ b/src/plugins/data/public/search/aggs/buckets/histogram.ts @@ -23,9 +23,8 @@ import { i18n } from '@kbn/i18n'; import { BucketAggType, IBucketAggConfig } from './_bucket_agg_type'; import { createFilterHistogram } from './create_filter/histogram'; import { BUCKET_TYPES } from './bucket_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getNotifications, getUiSettings } from '../../../../../../../plugins/data/public/services'; +import { KBN_FIELD_TYPES } from '../../../../common'; +import { getNotifications, getUiSettings } from '../../../../public/services'; export interface AutoBounds { min: number; diff --git a/src/legacy/core_plugins/data/common/parse_es_interval/index.ts b/src/plugins/data/public/search/aggs/buckets/index.ts similarity index 70% rename from src/legacy/core_plugins/data/common/parse_es_interval/index.ts rename to src/plugins/data/public/search/aggs/buckets/index.ts index 9c2c546af40d41..3a402b1498a775 100644 --- a/src/legacy/core_plugins/data/common/parse_es_interval/index.ts +++ b/src/plugins/data/public/search/aggs/buckets/index.ts @@ -17,7 +17,13 @@ * under the License. */ -export { parseEsInterval, ParsedInterval } from './parse_es_interval'; -export { InvalidEsCalendarIntervalError } from './invalid_es_calendar_interval_error'; -export { InvalidEsIntervalFormatError } from './invalid_es_interval_format_error'; -export { isValidEsInterval } from './is_valid_es_interval'; +export * from './_interval_options'; +export * from './bucket_agg_types'; +export * from './date_histogram'; +export * from './date_range'; +export * from './ip_range'; +export * from './lib/cidr_mask'; +export * from './lib/date_range'; +export * from './lib/ip_range'; +export * from './migrate_include_exclude_format'; +export * from './terms'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts b/src/plugins/data/public/search/aggs/buckets/ip_range.ts similarity index 87% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts rename to src/plugins/data/public/search/aggs/buckets/ip_range.ts index 3fb464d8fa7a8b..da6866d40a52fe 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/ip_range.ts +++ b/src/plugins/data/public/search/aggs/buckets/ip_range.ts @@ -23,13 +23,9 @@ import { BucketAggType } from './_bucket_agg_type'; import { BUCKET_TYPES } from './bucket_agg_types'; import { createFilterIpRange } from './create_filter/ip_range'; -import { KBN_FIELD_TYPES, fieldFormats } from '../../../../../../../plugins/data/public'; - import { IpRangeKey, convertIPRangeToString } from './lib/ip_range'; -export { IpRangeKey, convertIPRangeToString }; // for BWC - -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getFieldFormats } from '../../../../../../../plugins/data/public/services'; +import { KBN_FIELD_TYPES, FieldFormat, TEXT_CONTEXT_TYPE } from '../../../../common'; +import { getFieldFormats } from '../../../../public/services'; const ipRangeTitle = i18n.translate('data.search.aggs.buckets.ipRangeTitle', { defaultMessage: 'IPv4 Range', @@ -48,10 +44,10 @@ export const ipRangeBucketAgg = new BucketAggType({ getFormat(agg) { const fieldFormatsService = getFieldFormats(); const formatter = agg.fieldOwnFormatter( - fieldFormats.TEXT_CONTEXT_TYPE, + TEXT_CONTEXT_TYPE, fieldFormatsService.getDefaultInstance(KBN_FIELD_TYPES.IP) ); - const IpRangeFormat = fieldFormats.FieldFormat.from(function(range: IpRangeKey) { + const IpRangeFormat = FieldFormat.from(function(range: IpRangeKey) { return convertIPRangeToString(range, formatter); }); return new IpRangeFormat(); diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/cidr_mask.test.ts b/src/plugins/data/public/search/aggs/buckets/lib/cidr_mask.test.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/lib/cidr_mask.test.ts rename to src/plugins/data/public/search/aggs/buckets/lib/cidr_mask.test.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/cidr_mask.ts b/src/plugins/data/public/search/aggs/buckets/lib/cidr_mask.ts similarity index 95% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/lib/cidr_mask.ts rename to src/plugins/data/public/search/aggs/buckets/lib/cidr_mask.ts index 30c4e400fb806b..4535b5f5c5dd21 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/cidr_mask.ts +++ b/src/plugins/data/public/search/aggs/buckets/lib/cidr_mask.ts @@ -17,7 +17,7 @@ * under the License. */ -import { Ipv4Address } from '../../../../../../../../plugins/kibana_utils/public'; +import { Ipv4Address } from '../../../../../../../plugins/kibana_utils/public'; const NUM_BITS = 32; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/date_range.ts b/src/plugins/data/public/search/aggs/buckets/lib/date_range.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/lib/date_range.ts rename to src/plugins/data/public/search/aggs/buckets/lib/date_range.ts diff --git a/src/plugins/data/public/search/aggs/buckets/lib/date_utils.ts b/src/plugins/data/public/search/aggs/buckets/lib/date_utils.ts deleted file mode 100644 index 2ee3d9cf85e8a0..00000000000000 --- a/src/plugins/data/public/search/aggs/buckets/lib/date_utils.ts +++ /dev/null @@ -1,25 +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. - */ - -/** - * This temporarily re-exports a static function from the data shim plugin until - * the final agg_types cutover is complete. It is needed for use in Lens; and they - * are not currently using the legacy data shim, so we are moving it here first. - */ -export { getCalculateAutoTimeExpression } from '../../../../../../../legacy/core_plugins/data/public/search/aggs/buckets/lib/date_utils'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/ip_range.ts b/src/plugins/data/public/search/aggs/buckets/lib/ip_range.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/lib/ip_range.ts rename to src/plugins/data/public/search/aggs/buckets/lib/ip_range.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/time_buckets/calc_auto_interval.test.ts b/src/plugins/data/public/search/aggs/buckets/lib/time_buckets/calc_auto_interval.test.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/lib/time_buckets/calc_auto_interval.test.ts rename to src/plugins/data/public/search/aggs/buckets/lib/time_buckets/calc_auto_interval.test.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/time_buckets/calc_auto_interval.ts b/src/plugins/data/public/search/aggs/buckets/lib/time_buckets/calc_auto_interval.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/lib/time_buckets/calc_auto_interval.ts rename to src/plugins/data/public/search/aggs/buckets/lib/time_buckets/calc_auto_interval.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/time_buckets/calc_es_interval.ts b/src/plugins/data/public/search/aggs/buckets/lib/time_buckets/calc_es_interval.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/lib/time_buckets/calc_es_interval.ts rename to src/plugins/data/public/search/aggs/buckets/lib/time_buckets/calc_es_interval.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/time_buckets/index.ts b/src/plugins/data/public/search/aggs/buckets/lib/time_buckets/index.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/lib/time_buckets/index.ts rename to src/plugins/data/public/search/aggs/buckets/lib/time_buckets/index.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/time_buckets/time_buckets.ts b/src/plugins/data/public/search/aggs/buckets/lib/time_buckets/time_buckets.ts similarity index 98% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/lib/time_buckets/time_buckets.ts rename to src/plugins/data/public/search/aggs/buckets/lib/time_buckets/time_buckets.ts index 9f43181932d7ef..c14f02e7decdfd 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/time_buckets/time_buckets.ts +++ b/src/plugins/data/public/search/aggs/buckets/lib/time_buckets/time_buckets.ts @@ -20,9 +20,8 @@ import _ from 'lodash'; import moment from 'moment'; -import { IUiSettingsClient } from '../../../../../../../../../core/public'; -import { parseInterval } from '../../../../../../../../../plugins/data/public'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { IUiSettingsClient } from 'src/core/public'; +import { parseInterval } from '../../../../../../common'; import { calcAutoIntervalLessThan, calcAutoIntervalNear } from './calc_auto_interval'; import { convertDurationToNormalizedEsInterval, diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/migrate_include_exclude_format.ts b/src/plugins/data/public/search/aggs/buckets/migrate_include_exclude_format.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/migrate_include_exclude_format.ts rename to src/plugins/data/public/search/aggs/buckets/migrate_include_exclude_format.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/range.test.ts b/src/plugins/data/public/search/aggs/buckets/range.test.ts similarity index 94% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/range.test.ts rename to src/plugins/data/public/search/aggs/buckets/range.test.ts index 096b19fe7de66d..d9e1af149524cd 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/range.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/range.test.ts @@ -21,7 +21,7 @@ import { rangeBucketAgg } from './range'; import { AggConfigs } from '../agg_configs'; import { mockDataServices, mockAggTypesRegistry } from '../test_helpers'; import { BUCKET_TYPES } from './bucket_agg_types'; -import { FieldFormatsGetConfigFn, fieldFormats } from '../../../../../../../plugins/data/public'; +import { FieldFormatsGetConfigFn, NumberFormat } from '../../../../common'; const buckets = [ { @@ -54,7 +54,7 @@ describe('Range Agg', () => { const getAggConfigs = () => { const field = { name: 'bytes', - format: new fieldFormats.NumberFormat( + format: new NumberFormat( { pattern: '0,0.[000] b', }, diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/range.ts b/src/plugins/data/public/search/aggs/buckets/range.ts similarity index 94% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/range.ts rename to src/plugins/data/public/search/aggs/buckets/range.ts index f35db2cc759bda..036a0d4c1e8dae 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/range.ts +++ b/src/plugins/data/public/search/aggs/buckets/range.ts @@ -19,7 +19,7 @@ import { i18n } from '@kbn/i18n'; import { BucketAggType } from './_bucket_agg_type'; -import { fieldFormats, KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; +import { FieldFormat, KBN_FIELD_TYPES } from '../../../../common'; import { RangeKey } from './range_key'; import { createFilterRange } from './create_filter/range'; import { BUCKET_TYPES } from './bucket_agg_types'; @@ -65,7 +65,7 @@ export const rangeBucketAgg = new BucketAggType({ let aggFormat = formats.get(agg); if (aggFormat) return aggFormat; - const RangeFormat = fieldFormats.FieldFormat.from((range: any) => { + const RangeFormat = FieldFormat.from((range: any) => { const format = agg.fieldOwnFormatter(); const gte = '\u2265'; const lt = '\u003c'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/range_key.ts b/src/plugins/data/public/search/aggs/buckets/range_key.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/range_key.ts rename to src/plugins/data/public/search/aggs/buckets/range_key.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.test.ts b/src/plugins/data/public/search/aggs/buckets/significant_terms.test.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.test.ts rename to src/plugins/data/public/search/aggs/buckets/significant_terms.test.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.ts b/src/plugins/data/public/search/aggs/buckets/significant_terms.ts similarity index 97% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.ts rename to src/plugins/data/public/search/aggs/buckets/significant_terms.ts index bc6c63d569b110..f12ebe58e2de28 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/significant_terms.ts +++ b/src/plugins/data/public/search/aggs/buckets/significant_terms.ts @@ -22,7 +22,7 @@ import { BucketAggType } from './_bucket_agg_type'; import { createFilterTerms } from './create_filter/terms'; import { isStringType, migrateIncludeExcludeFormat } from './migrate_include_exclude_format'; import { BUCKET_TYPES } from './bucket_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../common'; const significantTermsTitle = i18n.translate('data.search.aggs.buckets.significantTermsTitle', { defaultMessage: 'Significant Terms', diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.test.ts b/src/plugins/data/public/search/aggs/buckets/terms.test.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/terms.test.ts rename to src/plugins/data/public/search/aggs/buckets/terms.test.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts b/src/plugins/data/public/search/aggs/buckets/terms.ts similarity index 97% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts rename to src/plugins/data/public/search/aggs/buckets/terms.ts index b387e9b7d306a2..813c657934a769 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/terms.ts +++ b/src/plugins/data/public/search/aggs/buckets/terms.ts @@ -19,7 +19,6 @@ import { noop } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { getRequestInspectorStats, getResponseInspectorStats } from '../../../index'; import { BucketAggType } from './_bucket_agg_type'; import { BUCKET_TYPES } from './bucket_agg_types'; import { IBucketAggConfig } from './_bucket_agg_type'; @@ -27,13 +26,10 @@ import { createFilterTerms } from './create_filter/terms'; import { isStringType, migrateIncludeExcludeFormat } from './migrate_include_exclude_format'; import { IAggConfigs } from '../agg_configs'; -import { Adapters } from '../../../../../../../plugins/inspector/public'; -import { - ISearchSource, - IFieldFormat, - FieldFormatsContentType, - KBN_FIELD_TYPES, -} from '../../../../../../../plugins/data/public'; +import { Adapters } from '../../../../../inspector/public'; +import { ISearchSource } from '../../search_source'; +import { IFieldFormat, FieldFormatsContentType, KBN_FIELD_TYPES } from '../../../../common'; +import { getRequestInspectorStats, getResponseInspectorStats } from '../../expressions'; import { buildOtherBucketAgg, diff --git a/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.test.ts b/src/plugins/data/public/search/aggs/filter/agg_type_filters.test.ts similarity index 97% rename from src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.test.ts rename to src/plugins/data/public/search/aggs/filter/agg_type_filters.test.ts index 90c29675c0db27..58f5aef0b9dfd4 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.test.ts +++ b/src/plugins/data/public/search/aggs/filter/agg_type_filters.test.ts @@ -17,7 +17,7 @@ * under the License. */ -import { IndexPattern } from '../../../../../../../plugins/data/public'; +import { IndexPattern } from '../../../index_patterns'; import { AggTypeFilters } from './agg_type_filters'; import { IAggConfig, IAggType } from '../types'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.ts b/src/plugins/data/public/search/aggs/filter/agg_type_filters.ts similarity index 97% rename from src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.ts rename to src/plugins/data/public/search/aggs/filter/agg_type_filters.ts index 8da547e592af91..b8d192cd66b5ac 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/filter/agg_type_filters.ts +++ b/src/plugins/data/public/search/aggs/filter/agg_type_filters.ts @@ -17,7 +17,7 @@ * under the License. */ -import { IndexPattern } from 'src/plugins/data/public'; +import { IndexPattern } from '../../../index_patterns'; import { IAggConfig, IAggType } from '../types'; type AggTypeFilter = ( diff --git a/src/legacy/core_plugins/data/public/search/aggs/filter/index.ts b/src/plugins/data/public/search/aggs/filter/index.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/filter/index.ts rename to src/plugins/data/public/search/aggs/filter/index.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/filter/prop_filter.test.ts b/src/plugins/data/public/search/aggs/filter/prop_filter.test.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/filter/prop_filter.test.ts rename to src/plugins/data/public/search/aggs/filter/prop_filter.test.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/filter/prop_filter.ts b/src/plugins/data/public/search/aggs/filter/prop_filter.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/filter/prop_filter.ts rename to src/plugins/data/public/search/aggs/filter/prop_filter.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/index.test.ts b/src/plugins/data/public/search/aggs/index.test.ts similarity index 88% rename from src/legacy/core_plugins/data/public/search/aggs/index.test.ts rename to src/plugins/data/public/search/aggs/index.test.ts index 4d0cd55b09d533..b5dedc9d45e84e 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/index.test.ts +++ b/src/plugins/data/public/search/aggs/index.test.ts @@ -17,11 +17,14 @@ * under the License. */ -import { aggTypes } from './index'; +import { coreMock } from '../../../../../../src/core/public/mocks'; +import { getAggTypes } from './index'; import { isBucketAggType } from './buckets/_bucket_agg_type'; import { isMetricAggType } from './metrics/metric_agg_type'; +const aggTypes = getAggTypes({ uiSettings: coreMock.createStart().uiSettings }); + const bucketAggs = aggTypes.buckets; const metricAggs = aggTypes.metrics; diff --git a/src/plugins/data/public/search/aggs/index.ts b/src/plugins/data/public/search/aggs/index.ts new file mode 100644 index 00000000000000..5dfb6aeff8d14f --- /dev/null +++ b/src/plugins/data/public/search/aggs/index.ts @@ -0,0 +1,31 @@ +/* + * 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 './agg_config'; +export * from './agg_configs'; +export * from './agg_groups'; +export * from './agg_type'; +export * from './agg_types'; +export * from './agg_types_registry'; +export * from './buckets'; +export * from './filter'; +export * from './metrics'; +export * from './param_types'; +export * from './types'; +export * from './utils'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/avg.ts b/src/plugins/data/public/search/aggs/metrics/avg.ts similarity index 95% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/avg.ts rename to src/plugins/data/public/search/aggs/metrics/avg.ts index b80671a43d2afa..008dede3e1985c 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/avg.ts +++ b/src/plugins/data/public/search/aggs/metrics/avg.ts @@ -20,7 +20,7 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../common'; const averageTitle = i18n.translate('data.search.aggs.metrics.averageTitle', { defaultMessage: 'Average', diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_avg.ts b/src/plugins/data/public/search/aggs/metrics/bucket_avg.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_avg.ts rename to src/plugins/data/public/search/aggs/metrics/bucket_avg.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_max.ts b/src/plugins/data/public/search/aggs/metrics/bucket_max.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_max.ts rename to src/plugins/data/public/search/aggs/metrics/bucket_max.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_min.ts b/src/plugins/data/public/search/aggs/metrics/bucket_min.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_min.ts rename to src/plugins/data/public/search/aggs/metrics/bucket_min.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_sum.ts b/src/plugins/data/public/search/aggs/metrics/bucket_sum.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/bucket_sum.ts rename to src/plugins/data/public/search/aggs/metrics/bucket_sum.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/cardinality.ts b/src/plugins/data/public/search/aggs/metrics/cardinality.ts similarity index 88% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/cardinality.ts rename to src/plugins/data/public/search/aggs/metrics/cardinality.ts index 4f7b6e555ca33e..aa41307b2a052a 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/cardinality.ts +++ b/src/plugins/data/public/search/aggs/metrics/cardinality.ts @@ -20,9 +20,8 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getFieldFormats } from '../../../../../../../plugins/data/public/services'; +import { KBN_FIELD_TYPES } from '../../../../common'; +import { getFieldFormats } from '../../../../public/services'; const uniqueCountTitle = i18n.translate('data.search.aggs.metrics.uniqueCountTitle', { defaultMessage: 'Unique Count', diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/count.ts b/src/plugins/data/public/search/aggs/metrics/count.ts similarity index 87% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/count.ts rename to src/plugins/data/public/search/aggs/metrics/count.ts index 8b3e0a488c68a1..3ec1e18d66ab98 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/count.ts +++ b/src/plugins/data/public/search/aggs/metrics/count.ts @@ -20,9 +20,8 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getFieldFormats } from '../../../../../../../plugins/data/public/services'; +import { KBN_FIELD_TYPES } from '../../../../common'; +import { getFieldFormats } from '../../../../public/services'; export const countMetricAgg = new MetricAggType({ name: METRIC_TYPES.COUNT, diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/cumulative_sum.ts b/src/plugins/data/public/search/aggs/metrics/cumulative_sum.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/cumulative_sum.ts rename to src/plugins/data/public/search/aggs/metrics/cumulative_sum.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/derivative.ts b/src/plugins/data/public/search/aggs/metrics/derivative.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/derivative.ts rename to src/plugins/data/public/search/aggs/metrics/derivative.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_bounds.ts b/src/plugins/data/public/search/aggs/metrics/geo_bounds.ts similarity index 95% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/geo_bounds.ts rename to src/plugins/data/public/search/aggs/metrics/geo_bounds.ts index 53bc72f9ce1dac..8a9f66f4b22a8a 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_bounds.ts +++ b/src/plugins/data/public/search/aggs/metrics/geo_bounds.ts @@ -20,7 +20,7 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../common'; const geoBoundsTitle = i18n.translate('data.search.aggs.metrics.geoBoundsTitle', { defaultMessage: 'Geo Bounds', diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_centroid.ts b/src/plugins/data/public/search/aggs/metrics/geo_centroid.ts similarity index 95% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/geo_centroid.ts rename to src/plugins/data/public/search/aggs/metrics/geo_centroid.ts index a79b2b34ad1cad..a4e4413843bdd6 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/geo_centroid.ts +++ b/src/plugins/data/public/search/aggs/metrics/geo_centroid.ts @@ -20,7 +20,7 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../common'; const geoCentroidTitle = i18n.translate('data.search.aggs.metrics.geoCentroidTitle', { defaultMessage: 'Geo Centroid', diff --git a/src/plugins/data/public/search/aggs/metrics/index.ts b/src/plugins/data/public/search/aggs/metrics/index.ts new file mode 100644 index 00000000000000..eb93e99427f654 --- /dev/null +++ b/src/plugins/data/public/search/aggs/metrics/index.ts @@ -0,0 +1,23 @@ +/* + * 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 './metric_agg_type'; +export * from './metric_agg_types'; +export * from './lib/parent_pipeline_agg_helper'; +export * from './lib/sibling_pipeline_agg_helper'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/get_response_agg_config_class.ts b/src/plugins/data/public/search/aggs/metrics/lib/get_response_agg_config_class.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/lib/get_response_agg_config_class.ts rename to src/plugins/data/public/search/aggs/metrics/lib/get_response_agg_config_class.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/make_nested_label.test.ts b/src/plugins/data/public/search/aggs/metrics/lib/make_nested_label.test.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/lib/make_nested_label.test.ts rename to src/plugins/data/public/search/aggs/metrics/lib/make_nested_label.test.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/make_nested_label.ts b/src/plugins/data/public/search/aggs/metrics/lib/make_nested_label.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/lib/make_nested_label.ts rename to src/plugins/data/public/search/aggs/metrics/lib/make_nested_label.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/nested_agg_helpers.ts b/src/plugins/data/public/search/aggs/metrics/lib/nested_agg_helpers.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/lib/nested_agg_helpers.ts rename to src/plugins/data/public/search/aggs/metrics/lib/nested_agg_helpers.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/ordinal_suffix.test.ts b/src/plugins/data/public/search/aggs/metrics/lib/ordinal_suffix.test.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/lib/ordinal_suffix.test.ts rename to src/plugins/data/public/search/aggs/metrics/lib/ordinal_suffix.test.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/ordinal_suffix.ts b/src/plugins/data/public/search/aggs/metrics/lib/ordinal_suffix.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/lib/ordinal_suffix.ts rename to src/plugins/data/public/search/aggs/metrics/lib/ordinal_suffix.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts b/src/plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts similarity index 93% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts rename to src/plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts index df4cbaf49c8b3f..3868d8f1bcd16c 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts +++ b/src/plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts @@ -24,7 +24,7 @@ import { forwardModifyAggConfigOnSearchRequestStart } from './nested_agg_helpers import { IMetricAggConfig, MetricAggParam } from '../metric_agg_type'; import { parentPipelineAggWriter } from './parent_pipeline_agg_writer'; -import { fieldFormats } from '../../../../../../../../plugins/data/public'; +import { FieldFormat } from '../../../../../common'; const metricAggFilter = [ '!top_hits', @@ -86,7 +86,7 @@ const parentPipelineAggHelper = { } else { subAgg = agg.aggConfigs.byId(agg.getParam('metricAgg')); } - return subAgg ? subAgg.type.getFormat(subAgg) : new (fieldFormats.FieldFormat.from(identity))(); + return subAgg ? subAgg.type.getFormat(subAgg) : new (FieldFormat.from(identity))(); }, }; diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_writer.ts b/src/plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_writer.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_writer.ts rename to src/plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_writer.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts b/src/plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts similarity index 95% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts rename to src/plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts index 33d6d725408684..c1d05a39285b70 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts +++ b/src/plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts @@ -22,7 +22,7 @@ import { i18n } from '@kbn/i18n'; import { siblingPipelineAggWriter } from './sibling_pipeline_agg_writer'; import { forwardModifyAggConfigOnSearchRequestStart } from './nested_agg_helpers'; import { IMetricAggConfig, MetricAggParam } from '../metric_agg_type'; -import { fieldFormats } from '../../../../../../../../plugins/data/public'; +import { FieldFormat } from '../../../../../common'; const metricAggFilter: string[] = [ '!top_hits', @@ -95,7 +95,7 @@ const siblingPipelineAggHelper = { const customMetric = agg.getParam('customMetric'); return customMetric ? customMetric.type.getFormat(customMetric) - : new (fieldFormats.FieldFormat.from(identity))(); + : new (FieldFormat.from(identity))(); }, }; diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_writer.ts b/src/plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_writer.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_writer.ts rename to src/plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_writer.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/max.ts b/src/plugins/data/public/search/aggs/metrics/max.ts similarity index 95% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/max.ts rename to src/plugins/data/public/search/aggs/metrics/max.ts index d561788936b51e..0cfb7be699a95c 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/max.ts +++ b/src/plugins/data/public/search/aggs/metrics/max.ts @@ -20,7 +20,7 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../common'; const maxTitle = i18n.translate('data.search.aggs.metrics.maxTitle', { defaultMessage: 'Max', diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/median.test.ts b/src/plugins/data/public/search/aggs/metrics/median.test.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/median.test.ts rename to src/plugins/data/public/search/aggs/metrics/median.test.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/median.ts b/src/plugins/data/public/search/aggs/metrics/median.ts similarity index 95% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/median.ts rename to src/plugins/data/public/search/aggs/metrics/median.ts index 68fc98261118c2..f2636d52e34844 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/median.ts +++ b/src/plugins/data/public/search/aggs/metrics/median.ts @@ -20,7 +20,7 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../common'; const medianTitle = i18n.translate('data.search.aggs.metrics.medianTitle', { defaultMessage: 'Median', diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_type.ts b/src/plugins/data/public/search/aggs/metrics/metric_agg_type.ts similarity index 93% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_type.ts rename to src/plugins/data/public/search/aggs/metrics/metric_agg_type.ts index 82b042a1e3378d..05c4cb3de4bdf4 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_type.ts +++ b/src/plugins/data/public/search/aggs/metrics/metric_agg_type.ts @@ -22,9 +22,8 @@ import { AggType, AggTypeConfig } from '../agg_type'; import { AggParamType } from '../param_types/agg'; import { AggConfig } from '../agg_config'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getFieldFormats } from '../../../../../../../plugins/data/public/services'; +import { KBN_FIELD_TYPES } from '../../../../common'; +import { getFieldFormats } from '../../../../public/services'; import { FieldTypes } from '../param_types'; export interface IMetricAggConfig extends AggConfig { diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_types.ts b/src/plugins/data/public/search/aggs/metrics/metric_agg_types.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/metric_agg_types.ts rename to src/plugins/data/public/search/aggs/metrics/metric_agg_types.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/min.ts b/src/plugins/data/public/search/aggs/metrics/min.ts similarity index 95% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/min.ts rename to src/plugins/data/public/search/aggs/metrics/min.ts index 1806c6d9d77107..0a9abf1edcd043 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/min.ts +++ b/src/plugins/data/public/search/aggs/metrics/min.ts @@ -20,7 +20,7 @@ import { i18n } from '@kbn/i18n'; import { MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; +import { KBN_FIELD_TYPES } from '../../../../common'; const minTitle = i18n.translate('data.search.aggs.metrics.minTitle', { defaultMessage: 'Min', diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/moving_avg.ts b/src/plugins/data/public/search/aggs/metrics/moving_avg.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/moving_avg.ts rename to src/plugins/data/public/search/aggs/metrics/moving_avg.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/parent_pipeline.test.ts b/src/plugins/data/public/search/aggs/metrics/parent_pipeline.test.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/parent_pipeline.test.ts rename to src/plugins/data/public/search/aggs/metrics/parent_pipeline.test.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/percentile_ranks.test.ts b/src/plugins/data/public/search/aggs/metrics/percentile_ranks.test.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/percentile_ranks.test.ts rename to src/plugins/data/public/search/aggs/metrics/percentile_ranks.test.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/percentile_ranks.ts b/src/plugins/data/public/search/aggs/metrics/percentile_ranks.ts similarity index 90% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/percentile_ranks.ts rename to src/plugins/data/public/search/aggs/metrics/percentile_ranks.ts index 1d640a9c1fa42f..71b1c1415d98e0 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/percentile_ranks.ts +++ b/src/plugins/data/public/search/aggs/metrics/percentile_ranks.ts @@ -22,9 +22,8 @@ import { MetricAggType } from './metric_agg_type'; import { getResponseAggConfigClass, IResponseAggConfig } from './lib/get_response_agg_config_class'; import { getPercentileValue } from './percentiles_get_value'; import { METRIC_TYPES } from './metric_agg_types'; -import { fieldFormats, KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getFieldFormats } from '../../../../../../../plugins/data/public/services'; +import { FIELD_FORMAT_IDS, KBN_FIELD_TYPES } from '../../../../common'; +import { getFieldFormats } from '../../../../public/services'; // required by the values editor export type IPercentileRanksAggConfig = IResponseAggConfig; @@ -81,7 +80,7 @@ export const percentileRanksMetricAgg = new MetricAggType { let aggDsl: Record; diff --git a/src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.ts b/src/plugins/data/public/search/aggs/metrics/top_hit.ts similarity index 97% rename from src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.ts rename to src/plugins/data/public/search/aggs/metrics/top_hit.ts index c850eb4ff22206..738de6b62bccbb 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/metrics/top_hit.ts +++ b/src/plugins/data/public/search/aggs/metrics/top_hit.ts @@ -21,10 +21,7 @@ import _ from 'lodash'; import { i18n } from '@kbn/i18n'; import { IMetricAggConfig, MetricAggType } from './metric_agg_type'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; - -// @ts-ignore -import { wrapWithInlineComp } from '../buckets/inline_comp_wrapper'; +import { KBN_FIELD_TYPES } from '../../../../common'; const isNumericFieldSelected = (agg: IMetricAggConfig) => { const field = agg.getParam('field'); diff --git a/src/legacy/core_plugins/data/public/search/mocks.ts b/src/plugins/data/public/search/aggs/mocks.ts similarity index 60% rename from src/legacy/core_plugins/data/public/search/mocks.ts rename to src/plugins/data/public/search/aggs/mocks.ts index 46c26dc8f1bd0a..7a5dcc9be45929 100644 --- a/src/legacy/core_plugins/data/public/search/mocks.ts +++ b/src/plugins/data/public/search/aggs/mocks.ts @@ -19,11 +19,14 @@ // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { coreMock } from '../../../../../../src/core/public/mocks'; -import { SearchSetup, SearchStart } from './search_service'; -import { AggTypesRegistrySetup, AggTypesRegistryStart } from './aggs/agg_types_registry'; -import { getCalculateAutoTimeExpression } from './aggs'; -import { AggConfigs } from './aggs/agg_configs'; -import { mockAggTypesRegistry } from './aggs/test_helpers'; +import { + AggConfigs, + AggTypesRegistrySetup, + AggTypesRegistryStart, + getCalculateAutoTimeExpression, +} from './'; +import { SearchAggsSetup, SearchAggsStart } from './types'; +import { mockAggTypesRegistry } from './test_helpers'; const aggTypeBaseParamMock = () => ({ name: 'some_param', @@ -59,30 +62,17 @@ export const aggTypesRegistryStartMock = (): AggTypesRegistryStart => ({ })), }); -export const searchSetupMock = (): SearchSetup => ({ - aggs: { - calculateAutoTimeExpression: getCalculateAutoTimeExpression(coreMock.createSetup().uiSettings), - types: aggTypesRegistrySetupMock(), - }, +export const searchAggsSetupMock = (): SearchAggsSetup => ({ + calculateAutoTimeExpression: getCalculateAutoTimeExpression(coreMock.createSetup().uiSettings), + types: aggTypesRegistrySetupMock(), }); -export const searchStartMock = (): SearchStart => ({ - aggs: { - calculateAutoTimeExpression: getCalculateAutoTimeExpression(coreMock.createStart().uiSettings), - createAggConfigs: jest.fn().mockImplementation((indexPattern, configStates = [], schemas) => { - return new AggConfigs(indexPattern, configStates, { - typesRegistry: mockAggTypesRegistry(), - }); - }), - types: mockAggTypesRegistry(), - __LEGACY: { - AggConfig: jest.fn() as any, - AggType: jest.fn(), - aggTypeFieldFilters: jest.fn() as any, - FieldParamType: jest.fn(), - MetricAggType: jest.fn(), - parentPipelineAggHelper: jest.fn() as any, - siblingPipelineAggHelper: jest.fn() as any, - }, - }, +export const searchAggsStartMock = (): SearchAggsStart => ({ + calculateAutoTimeExpression: getCalculateAutoTimeExpression(coreMock.createStart().uiSettings), + createAggConfigs: jest.fn().mockImplementation((indexPattern, configStates = [], schemas) => { + return new AggConfigs(indexPattern, configStates, { + typesRegistry: mockAggTypesRegistry(), + }); + }), + types: mockAggTypesRegistry(), }); diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/agg.ts b/src/plugins/data/public/search/aggs/param_types/agg.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/param_types/agg.ts rename to src/plugins/data/public/search/aggs/param_types/agg.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/base.ts b/src/plugins/data/public/search/aggs/param_types/base.ts similarity index 96% rename from src/legacy/core_plugins/data/public/search/aggs/param_types/base.ts rename to src/plugins/data/public/search/aggs/param_types/base.ts index 95ad71a616ab27..2cbc5866e284db 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/param_types/base.ts +++ b/src/plugins/data/public/search/aggs/param_types/base.ts @@ -19,7 +19,8 @@ import { IAggConfigs } from '../agg_configs'; import { IAggConfig } from '../agg_config'; -import { FetchOptions, ISearchSource } from '../../../../../../../plugins/data/public'; +import { FetchOptions } from '../../fetch'; +import { ISearchSource } from '../../search_source'; export class BaseParamType { name: string; diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/field.test.ts b/src/plugins/data/public/search/aggs/param_types/field.test.ts similarity index 96% rename from src/legacy/core_plugins/data/public/search/aggs/param_types/field.test.ts rename to src/plugins/data/public/search/aggs/param_types/field.test.ts index 18b666f454664f..0182471392910c 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/param_types/field.test.ts +++ b/src/plugins/data/public/search/aggs/param_types/field.test.ts @@ -19,7 +19,7 @@ import { BaseParamType } from './base'; import { FieldParamType } from './field'; -import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; +import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '../../../../common'; import { IAggConfig } from '../agg_config'; describe('Field', () => { diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts b/src/plugins/data/public/search/aggs/param_types/field.ts similarity index 89% rename from src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts rename to src/plugins/data/public/search/aggs/param_types/field.ts index 6882b8aa39e7ee..34b77e14a3a71c 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/param_types/field.ts +++ b/src/plugins/data/public/search/aggs/param_types/field.ts @@ -19,16 +19,12 @@ import { i18n } from '@kbn/i18n'; import { IAggConfig } from '../agg_config'; -import { SavedObjectNotFound } from '../../../../../../../plugins/kibana_utils/public'; +import { SavedObjectNotFound } from '../../../../../../plugins/kibana_utils/public'; import { BaseParamType } from './base'; import { propFilter } from '../filter'; -import { - IndexPatternField, - indexPatterns, - KBN_FIELD_TYPES, -} from '../../../../../../../plugins/data/public'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getNotifications } from '../../../../../../../plugins/data/public/services'; +import { isNestedField, KBN_FIELD_TYPES } from '../../../../common'; +import { Field as IndexPatternField } from '../../../index_patterns'; +import { getNotifications } from '../../../../public/services'; const filterByType = propFilter('type'); @@ -118,7 +114,7 @@ export class FieldParamType extends BaseParamType { const { onlyAggregatable, scriptable, filterFieldTypes } = this; if ( - (onlyAggregatable && (!field.aggregatable || indexPatterns.isNestedField(field))) || + (onlyAggregatable && (!field.aggregatable || isNestedField(field))) || (!scriptable && field.scripted) ) { return false; diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/filter/field_filters.test.ts b/src/plugins/data/public/search/aggs/param_types/filter/field_filters.test.ts similarity index 96% rename from src/legacy/core_plugins/data/public/search/aggs/param_types/filter/field_filters.test.ts rename to src/plugins/data/public/search/aggs/param_types/filter/field_filters.test.ts index 1a453a225797db..f776a3deb23a15 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/param_types/filter/field_filters.test.ts +++ b/src/plugins/data/public/search/aggs/param_types/filter/field_filters.test.ts @@ -19,7 +19,7 @@ import { AggTypeFieldFilters } from './field_filters'; import { IAggConfig } from '../../agg_config'; -import { IndexPatternField } from '../../../../../../../../plugins/data/public'; +import { Field as IndexPatternField } from '../../../../index_patterns'; describe('AggTypeFieldFilters', () => { let registry: AggTypeFieldFilters; diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/filter/field_filters.ts b/src/plugins/data/public/search/aggs/param_types/filter/field_filters.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/param_types/filter/field_filters.ts rename to src/plugins/data/public/search/aggs/param_types/filter/field_filters.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/filter/index.ts b/src/plugins/data/public/search/aggs/param_types/filter/index.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/param_types/filter/index.ts rename to src/plugins/data/public/search/aggs/param_types/filter/index.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/index.ts b/src/plugins/data/public/search/aggs/param_types/index.ts similarity index 94% rename from src/legacy/core_plugins/data/public/search/aggs/param_types/index.ts rename to src/plugins/data/public/search/aggs/param_types/index.ts index 3414e6a71ecdc3..c9e8a9879f427c 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/param_types/index.ts +++ b/src/plugins/data/public/search/aggs/param_types/index.ts @@ -17,8 +17,10 @@ * under the License. */ +export * from './agg'; export * from './base'; export * from './field'; +export * from './filter'; export * from './json'; export * from './optioned'; export * from './string'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/json.test.ts b/src/plugins/data/public/search/aggs/param_types/json.test.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/param_types/json.test.ts rename to src/plugins/data/public/search/aggs/param_types/json.test.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/json.ts b/src/plugins/data/public/search/aggs/param_types/json.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/param_types/json.ts rename to src/plugins/data/public/search/aggs/param_types/json.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/optioned.test.ts b/src/plugins/data/public/search/aggs/param_types/optioned.test.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/param_types/optioned.test.ts rename to src/plugins/data/public/search/aggs/param_types/optioned.test.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/optioned.ts b/src/plugins/data/public/search/aggs/param_types/optioned.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/param_types/optioned.ts rename to src/plugins/data/public/search/aggs/param_types/optioned.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/string.test.ts b/src/plugins/data/public/search/aggs/param_types/string.test.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/param_types/string.test.ts rename to src/plugins/data/public/search/aggs/param_types/string.test.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/param_types/string.ts b/src/plugins/data/public/search/aggs/param_types/string.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/param_types/string.ts rename to src/plugins/data/public/search/aggs/param_types/string.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/test_helpers/index.ts b/src/plugins/data/public/search/aggs/test_helpers/index.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/aggs/test_helpers/index.ts rename to src/plugins/data/public/search/aggs/test_helpers/index.ts diff --git a/src/legacy/core_plugins/data/public/search/aggs/test_helpers/mock_agg_types_registry.ts b/src/plugins/data/public/search/aggs/test_helpers/mock_agg_types_registry.ts similarity index 88% rename from src/legacy/core_plugins/data/public/search/aggs/test_helpers/mock_agg_types_registry.ts rename to src/plugins/data/public/search/aggs/test_helpers/mock_agg_types_registry.ts index d6bb7938664932..1ebd0ea29c9ffc 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/test_helpers/mock_agg_types_registry.ts +++ b/src/plugins/data/public/search/aggs/test_helpers/mock_agg_types_registry.ts @@ -17,8 +17,10 @@ * under the License. */ +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { coreMock } from '../../../../../../../src/core/public/mocks'; import { AggTypesRegistry, AggTypesRegistryStart } from '../agg_types_registry'; -import { aggTypes } from '../agg_types'; +import { getAggTypes } from '../agg_types'; import { BucketAggType } from '../buckets/_bucket_agg_type'; import { MetricAggType } from '../metrics/metric_agg_type'; @@ -49,6 +51,7 @@ export function mockAggTypesRegistry | MetricAggTyp } }); } else { + const aggTypes = getAggTypes({ uiSettings: coreMock.createSetup().uiSettings }); aggTypes.buckets.forEach(type => registrySetup.registerBucket(type)); aggTypes.metrics.forEach(type => registrySetup.registerMetric(type)); } diff --git a/src/legacy/core_plugins/data/public/search/aggs/test_helpers/mock_data_services.ts b/src/plugins/data/public/search/aggs/test_helpers/mock_data_services.ts similarity index 76% rename from src/legacy/core_plugins/data/public/search/aggs/test_helpers/mock_data_services.ts rename to src/plugins/data/public/search/aggs/test_helpers/mock_data_services.ts index c4e78ab8f64226..d1d591771743c7 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/test_helpers/mock_data_services.ts +++ b/src/plugins/data/public/search/aggs/test_helpers/mock_data_services.ts @@ -17,20 +17,19 @@ * under the License. */ -import { coreMock } from '../../../../../../../../src/core/public/mocks'; -import { dataPluginMock } from '../../../../../../../plugins/data/public/mocks'; -import { searchStartMock } from '../../mocks'; -import { setSearchServiceShim } from '../../../services'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { coreMock } from '../../../../../../../src/core/public/mocks'; +import { dataPluginMock } from '../../../../public/mocks'; import { setFieldFormats, setIndexPatterns, + setInjectedMetadata, setNotifications, setOverlays, setQueryService, setSearchService, setUiSettings, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../../../../plugins/data/public/services'; +} from '../../../../public/services'; /** * Testing helper which calls all of the service setters used in the @@ -41,11 +40,10 @@ import { export function mockDataServices() { const core = coreMock.createStart(); const data = dataPluginMock.createStartContract(); - const searchShim = searchStartMock(); - setSearchServiceShim(searchShim); setFieldFormats(data.fieldFormats); setIndexPatterns(data.indexPatterns); + setInjectedMetadata(core.injectedMetadata); setNotifications(core.notifications); setOverlays(core.overlays); setQueryService(data.query); diff --git a/src/plugins/data/public/search/aggs/types.ts b/src/plugins/data/public/search/aggs/types.ts new file mode 100644 index 00000000000000..4b2b1620ad1d38 --- /dev/null +++ b/src/plugins/data/public/search/aggs/types.ts @@ -0,0 +1,72 @@ +/* + * 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 { IndexPattern } from '../../index_patterns'; +import { + AggType, + AggTypesRegistrySetup, + AggTypesRegistryStart, + AggConfig, + AggConfigs, + CreateAggConfigParams, + FieldParamType, + getCalculateAutoTimeExpression, + MetricAggType, + aggTypeFieldFilters, + parentPipelineAggHelper, + siblingPipelineAggHelper, +} from './'; + +export { IAggConfig } from './agg_config'; +export { CreateAggConfigParams, IAggConfigs } from './agg_configs'; +export { IAggType } from './agg_type'; +export { AggParam, AggParamOption } from './agg_params'; +export { IFieldParamType } from './param_types'; +export { IMetricAggType } from './metrics/metric_agg_type'; +export { DateRangeKey } from './buckets/lib/date_range'; +export { IpRangeKey } from './buckets/lib/ip_range'; +export { OptionedValueProp, OptionedParamEditorProps } from './param_types/optioned'; + +/** @internal */ +export interface SearchAggsSetup { + calculateAutoTimeExpression: ReturnType; + types: AggTypesRegistrySetup; +} + +/** @internal */ +export interface SearchAggsStartLegacy { + AggConfig: typeof AggConfig; + AggType: typeof AggType; + aggTypeFieldFilters: typeof aggTypeFieldFilters; + FieldParamType: typeof FieldParamType; + MetricAggType: typeof MetricAggType; + parentPipelineAggHelper: typeof parentPipelineAggHelper; + siblingPipelineAggHelper: typeof siblingPipelineAggHelper; +} + +/** @internal */ +export interface SearchAggsStart { + calculateAutoTimeExpression: ReturnType; + createAggConfigs: ( + indexPattern: IndexPattern, + configStates?: CreateAggConfigParams[], + schemas?: Record + ) => InstanceType; + types: AggTypesRegistryStart; +} diff --git a/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/date_utils.ts b/src/plugins/data/public/search/aggs/utils/calculate_auto_time_expression.ts similarity index 70% rename from src/legacy/core_plugins/data/public/search/aggs/buckets/lib/date_utils.ts rename to src/plugins/data/public/search/aggs/utils/calculate_auto_time_expression.ts index c333a1dbe8524b..459de66d057d43 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/buckets/lib/date_utils.ts +++ b/src/plugins/data/public/search/aggs/utils/calculate_auto_time_expression.ts @@ -17,24 +17,9 @@ * under the License. */ -import dateMath from '@elastic/datemath'; -import { TimeBuckets } from './time_buckets'; -import { TimeRange } from '../../../../../../../../plugins/data/public'; -import { IUiSettingsClient } from '../../../../../../../../core/public'; - -export function toAbsoluteDates(range: TimeRange) { - const fromDate = dateMath.parse(range.from); - const toDate = dateMath.parse(range.to, { roundUp: true }); - - if (!fromDate || !toDate) { - return; - } - - return { - from: fromDate.toDate(), - to: toDate.toDate(), - }; -} +import { IUiSettingsClient } from 'src/core/public'; +import { TimeBuckets } from '../buckets/lib/time_buckets'; +import { toAbsoluteDates, TimeRange } from '../../../../common'; export function getCalculateAutoTimeExpression(uiSettings: IUiSettingsClient) { return function calculateAutoTimeExpression(range: TimeRange) { diff --git a/src/plugins/data/public/search/aggs/utils/index.ts b/src/plugins/data/public/search/aggs/utils/index.ts new file mode 100644 index 00000000000000..23606bd1093424 --- /dev/null +++ b/src/plugins/data/public/search/aggs/utils/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 './calculate_auto_time_expression'; +export * from './to_angular_json'; diff --git a/src/legacy/core_plugins/data/public/search/aggs/utils.ts b/src/plugins/data/public/search/aggs/utils/to_angular_json.ts similarity index 64% rename from src/legacy/core_plugins/data/public/search/aggs/utils.ts rename to src/plugins/data/public/search/aggs/utils/to_angular_json.ts index 9fcd3f7930b066..f91a240741b6ae 100644 --- a/src/legacy/core_plugins/data/public/search/aggs/utils.ts +++ b/src/plugins/data/public/search/aggs/utils/to_angular_json.ts @@ -17,32 +17,12 @@ * under the License. */ -import { leastCommonInterval } from 'ui/vis/lib/least_common_interval'; -import { isValidEsInterval } from '../../../common'; - -export function isValidInterval(value: string, baseInterval?: string) { - if (baseInterval) { - return _parseWithBase(value, baseInterval); - } else { - return isValidEsInterval(value); - } -} - -// When base interval is set, check for least common interval and allow -// input the value is the same. This means that the input interval is a -// multiple of the base interval. -function _parseWithBase(value: string, baseInterval: string) { - try { - const interval = leastCommonInterval(baseInterval, value); - return interval === value.replace(/\s/g, ''); - } catch (e) { - return false; - } -} - -// An inlined version of angular.toJSON() -// source: https://github.com/angular/angular.js/blob/master/src/Angular.js#L1312 -// @internal +/** + * An inlined version of angular.toJSON(). Source: + * https://github.com/angular/angular.js/blob/master/src/Angular.js#L1312 + * + * @internal + */ export function toAngularJSON(obj: any, pretty?: any): string { if (obj === undefined) return ''; if (typeof pretty === 'number') { diff --git a/src/legacy/core_plugins/data/public/search/expressions/build_tabular_inspector_data.ts b/src/plugins/data/public/search/expressions/build_tabular_inspector_data.ts similarity index 97% rename from src/legacy/core_plugins/data/public/search/expressions/build_tabular_inspector_data.ts rename to src/plugins/data/public/search/expressions/build_tabular_inspector_data.ts index bd05fa21bfd5de..89a46db27e8940 100644 --- a/src/legacy/core_plugins/data/public/search/expressions/build_tabular_inspector_data.ts +++ b/src/plugins/data/public/search/expressions/build_tabular_inspector_data.ts @@ -18,12 +18,9 @@ */ import { set } from 'lodash'; -// @ts-ignore -import { FormattedData } from '../../../../../../plugins/inspector/public'; - -import { createFilter } from './create_filter'; - +import { FormattedData } from '../../../../../plugins/inspector/public'; import { TabbedTable } from '../tabify'; +import { createFilter } from './create_filter'; /** * @deprecated diff --git a/src/legacy/core_plugins/data/public/search/expressions/create_filter.test.ts b/src/plugins/data/public/search/expressions/create_filter.test.ts similarity index 90% rename from src/legacy/core_plugins/data/public/search/expressions/create_filter.test.ts rename to src/plugins/data/public/search/expressions/create_filter.test.ts index 890ec81778d4bf..23da060cba2032 100644 --- a/src/legacy/core_plugins/data/public/search/expressions/create_filter.test.ts +++ b/src/plugins/data/public/search/expressions/create_filter.test.ts @@ -17,15 +17,10 @@ * under the License. */ -import { - fieldFormats, - FieldFormatsGetConfigFn, - esFilters, -} from '../../../../../../plugins/data/public'; import { createFilter } from './create_filter'; +import { AggConfigs, IAggConfig } from '../aggs'; import { TabbedTable } from '../tabify'; -import { AggConfigs } from '../aggs/agg_configs'; -import { IAggConfig } from '../aggs/agg_config'; +import { isRangeFilter, BytesFormat, FieldFormatsGetConfigFn } from '../../../common'; import { mockDataServices, mockAggTypesRegistry } from '../aggs/test_helpers'; describe('createFilter', () => { @@ -41,7 +36,7 @@ describe('createFilter', () => { indexPattern: { id: '1234', }, - format: new fieldFormats.BytesFormat({}, (() => {}) as FieldFormatsGetConfigFn), + format: new BytesFormat({}, (() => {}) as FieldFormatsGetConfigFn), }; const indexPattern = { @@ -121,7 +116,7 @@ describe('createFilter', () => { const [rangeFilter] = filters; - if (esFilters.isRangeFilter(rangeFilter)) { + if (isRangeFilter(rangeFilter)) { expect(rangeFilter.range.bytes.gte).toEqual(2048); expect(rangeFilter.range.bytes.lt).toEqual(2078); } diff --git a/src/legacy/core_plugins/data/public/search/expressions/create_filter.ts b/src/plugins/data/public/search/expressions/create_filter.ts similarity index 93% rename from src/legacy/core_plugins/data/public/search/expressions/create_filter.ts rename to src/plugins/data/public/search/expressions/create_filter.ts index 77e011932195ca..2e2bd435151b61 100644 --- a/src/legacy/core_plugins/data/public/search/expressions/create_filter.ts +++ b/src/plugins/data/public/search/expressions/create_filter.ts @@ -17,9 +17,9 @@ * under the License. */ -import { IAggConfig } from 'ui/agg_types'; -import { Filter } from '../../../../../../plugins/data/public'; +import { IAggConfig } from '../aggs'; import { TabbedTable } from '../tabify'; +import { Filter } from '../../../common'; const getOtherBucketFilterTerms = (table: TabbedTable, columnIndex: number, rowIndex: number) => { if (rowIndex === -1) { @@ -45,7 +45,7 @@ const getOtherBucketFilterTerms = (table: TabbedTable, columnIndex: number, rowI ]; }; -const createFilter = ( +export const createFilter = ( aggConfigs: IAggConfig[], table: TabbedTable, columnIndex: number, @@ -76,5 +76,3 @@ const createFilter = ( return filter; }; - -export { createFilter }; diff --git a/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts b/src/plugins/data/public/search/expressions/esaggs.ts similarity index 89% rename from src/legacy/core_plugins/data/public/search/expressions/esaggs.ts rename to src/plugins/data/public/search/expressions/esaggs.ts index bb954cb887ef3f..2341f4fe447dbc 100644 --- a/src/legacy/core_plugins/data/public/search/expressions/esaggs.ts +++ b/src/plugins/data/public/search/expressions/esaggs.ts @@ -19,33 +19,24 @@ import { get, has } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { createAggConfigs, IAggConfigs } from 'ui/agg_types'; -import { createFormat } from 'ui/visualize/loader/pipeline_helpers/utilities'; import { KibanaContext, KibanaDatatable, ExpressionFunctionDefinition, KibanaDatatableColumn, -} from 'src/plugins/expressions/public'; -import { - ISearchSource, - SearchSource, - Query, - TimeRange, - Filter, - getTime, - FilterManager, -} from '../../../../../../plugins/data/public'; - +} from '../../../../../plugins/expressions/public'; +import { calculateObjectHash } from '../../../../../plugins/kibana_utils/public'; +import { PersistedState } from '../../../../../plugins/visualizations/public'; +import { Adapters } from '../../../../../plugins/inspector/public'; + +import { IAggConfigs } from '../aggs'; +import { ISearchSource, SearchSource } from '../search_source'; +import { tabifyAggResponse } from '../tabify'; +import { Filter, Query, serializeFieldFormat, TimeRange } from '../../../common'; +import { FilterManager, getTime } from '../../query'; +import { getSearchService, getQueryService, getIndexPatterns } from '../../services'; import { buildTabularInspectorData } from './build_tabular_inspector_data'; -import { calculateObjectHash } from '../../../../../../plugins/kibana_utils/common'; -import { tabifyAggResponse } from '../../../../../core_plugins/data/public'; -import { PersistedState } from '../../../../../../plugins/visualizations/public'; -import { Adapters } from '../../../../../../plugins/inspector/public'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getQueryService, getIndexPatterns } from '../../../../../../plugins/data/public/services'; -import { getRequestInspectorStats, getResponseInspectorStats } from '../..'; -import { serializeAggConfig } from './utils'; +import { getRequestInspectorStats, getResponseInspectorStats, serializeAggConfig } from './utils'; export interface RequestHandlerParams { searchSource: ISearchSource; @@ -255,10 +246,11 @@ export const esaggs = (): ExpressionFunctionDefinition diff --git a/src/legacy/core_plugins/dashboard_embeddable_container/public/np_ready/public/index.ts b/src/plugins/data/public/search/expressions/utils/index.ts similarity index 90% rename from src/legacy/core_plugins/dashboard_embeddable_container/public/np_ready/public/index.ts rename to src/plugins/data/public/search/expressions/utils/index.ts index d8c0de2bce3f4a..0fd51f3e158a62 100644 --- a/src/legacy/core_plugins/dashboard_embeddable_container/public/np_ready/public/index.ts +++ b/src/plugins/data/public/search/expressions/utils/index.ts @@ -17,4 +17,5 @@ * under the License. */ -export * from '../../../../../../plugins/dashboard_embeddable_container/public'; +export * from './courier_inspector_stats'; +export * from './serialize_agg_config'; diff --git a/src/legacy/core_plugins/data/public/search/expressions/utils.ts b/src/plugins/data/public/search/expressions/utils/serialize_agg_config.ts similarity index 85% rename from src/legacy/core_plugins/data/public/search/expressions/utils.ts rename to src/plugins/data/public/search/expressions/utils/serialize_agg_config.ts index 79763b577f2e2d..4ca976d328c919 100644 --- a/src/legacy/core_plugins/data/public/search/expressions/utils.ts +++ b/src/plugins/data/public/search/expressions/utils/serialize_agg_config.ts @@ -17,11 +17,12 @@ * under the License. */ -import { getSearchServiceShim } from '../../services'; -import { IAggConfig } from '../aggs/types'; -import { KibanaDatatableColumnMeta } from '../../../../../../plugins/expressions/common/expression_types'; -import { IndexPattern } from '../../../../../../plugins/data/public'; +import { KibanaDatatableColumnMeta } from '../../../../../../plugins/expressions/public'; +import { IAggConfig } from '../../aggs'; +import { IndexPattern } from '../../../index_patterns'; +import { getSearchService } from '../../../../public/services'; +/** @internal */ export const serializeAggConfig = (aggConfig: IAggConfig): KibanaDatatableColumnMeta => { return { type: aggConfig.type.name, @@ -36,12 +37,13 @@ interface DeserializeAggConfigParams { indexPattern: IndexPattern; } +/** @internal */ export const deserializeAggConfig = ({ type, aggConfigParams, indexPattern, }: DeserializeAggConfigParams) => { - const { aggs } = getSearchServiceShim(); + const { aggs } = getSearchService(); const aggConfigs = aggs.createAggConfigs(indexPattern); const aggConfig = aggConfigs.createAggConfig({ enabled: true, diff --git a/src/legacy/core_plugins/data/public/search/utils/types.ts b/src/plugins/data/public/search/expressions/utils/types.ts similarity index 88% rename from src/legacy/core_plugins/data/public/search/utils/types.ts rename to src/plugins/data/public/search/expressions/utils/types.ts index e0afe99aa81fac..b2311e664820ea 100644 --- a/src/legacy/core_plugins/data/public/search/utils/types.ts +++ b/src/plugins/data/public/search/expressions/utils/types.ts @@ -17,12 +17,13 @@ * under the License. */ -export interface InspectorStat { +interface InspectorStat { label: string; value: string; description: string; } +/** @internal */ export interface RequestInspectorStats { indexPattern?: InspectorStat; indexPatternId?: InspectorStat; @@ -31,9 +32,3 @@ export interface RequestInspectorStats { hits?: InspectorStat; requestTime?: InspectorStat; } - -export interface AggResponseBucket { - key_as_string: string; - key: number; - doc_count: number; -} diff --git a/src/plugins/data/public/search/index.ts b/src/plugins/data/public/search/index.ts index 6ccd90c6a9eff9..ac72cfd6f62ca9 100644 --- a/src/plugins/data/public/search/index.ts +++ b/src/plugins/data/public/search/index.ts @@ -17,6 +17,10 @@ * under the License. */ +export * from './aggs'; +export * from './expressions'; +export * from './tabify'; + export { ISearchSetup, ISearchStart, diff --git a/src/plugins/data/public/search/mocks.ts b/src/plugins/data/public/search/mocks.ts index f537a28849f22f..71b4eece91cefe 100644 --- a/src/plugins/data/public/search/mocks.ts +++ b/src/plugins/data/public/search/mocks.ts @@ -17,16 +17,12 @@ * under the License. */ -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { coreMock } from '../../../../../src/core/public/mocks'; -import { getCalculateAutoTimeExpression } from './aggs/buckets/lib/date_utils'; +import { searchAggsSetupMock } from './aggs/mocks'; export * from './search_source/mocks'; export const searchSetupMock = { - aggs: { - calculateAutoTimeExpression: getCalculateAutoTimeExpression(coreMock.createSetup().uiSettings), - }, + aggs: searchAggsSetupMock(), registerSearchStrategyContext: jest.fn(), registerSearchStrategyProvider: jest.fn(), }; diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index 4b9a5f6729877a..691c8aa0e984db 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -19,13 +19,25 @@ import { Plugin, CoreSetup, CoreStart, PackageInfo } from '../../../../core/public'; -import { getCalculateAutoTimeExpression } from './aggs/buckets/lib/date_utils'; 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 { ES_SEARCH_STRATEGY, DEFAULT_SEARCH_STRATEGY } from '../../common/search'; import { esSearchStrategyProvider } from './es_search/es_search_strategy'; +import { + getAggTypes, + AggType, + AggTypesRegistry, + AggConfig, + AggConfigs, + FieldParamType, + getCalculateAutoTimeExpression, + MetricAggType, + aggTypeFieldFilters, + parentPipelineAggHelper, + siblingPipelineAggHelper, +} from './aggs'; /** * The search plugin exposes two registration methods for other plugins: @@ -44,6 +56,7 @@ export class SearchService implements Plugin { private searchStrategies: TSearchStrategiesMap = {}; private esClient?: LegacyApiCaller; + private readonly aggTypesRegistry = new AggTypesRegistry(); private registerSearchStrategyProvider = ( name: T, @@ -60,23 +73,35 @@ export class SearchService implements Plugin { public setup(core: CoreSetup, packageInfo: PackageInfo): ISearchSetup { this.esClient = getEsClient(core.injectedMetadata, core.http, packageInfo); - this.registerSearchStrategyProvider(SYNC_SEARCH_STRATEGY, syncSearchStrategyProvider); - this.registerSearchStrategyProvider(ES_SEARCH_STRATEGY, esSearchStrategyProvider); + const aggTypesSetup = this.aggTypesRegistry.setup(); + const aggTypes = getAggTypes({ uiSettings: core.uiSettings }); + aggTypes.buckets.forEach(b => aggTypesSetup.registerBucket(b)); + aggTypes.metrics.forEach(m => aggTypesSetup.registerMetric(m)); + return { aggs: { calculateAutoTimeExpression: getCalculateAutoTimeExpression(core.uiSettings), + types: aggTypesSetup, }, registerSearchStrategyProvider: this.registerSearchStrategyProvider, }; } public start(core: CoreStart): ISearchStart { + const aggTypesStart = this.aggTypesRegistry.start(); + return { aggs: { calculateAutoTimeExpression: getCalculateAutoTimeExpression(core.uiSettings), + createAggConfigs: (indexPattern, configStates = [], schemas) => { + return new AggConfigs(indexPattern, configStates, { + typesRegistry: aggTypesStart, + }); + }, + types: aggTypesStart, }, search: (request, options, strategyName) => { const strategyProvider = this.getSearchStrategy(strategyName || DEFAULT_SEARCH_STRATEGY); @@ -88,6 +113,13 @@ export class SearchService implements Plugin { }, __LEGACY: { esClient: this.esClient!, + AggConfig, + AggType, + aggTypeFieldFilters, + FieldParamType, + MetricAggType, + parentPipelineAggHelper, + siblingPipelineAggHelper, }, }; } diff --git a/src/plugins/data/public/search/search_source/normalize_sort_request.test.ts b/src/plugins/data/public/search/search_source/normalize_sort_request.test.ts index 5939074d773bf0..13a6167544b5e9 100644 --- a/src/plugins/data/public/search/search_source/normalize_sort_request.test.ts +++ b/src/plugins/data/public/search/search_source/normalize_sort_request.test.ts @@ -21,8 +21,6 @@ import { normalizeSortRequest } from './normalize_sort_request'; import { SortDirection } from './types'; import { IIndexPattern } from '../..'; -jest.mock('ui/new_platform'); - describe('SearchSource#normalizeSortRequest', function() { const scriptedField = { name: 'script string', 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 7ca15bb4b77ab6..d2b8308bfb258f 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 @@ -19,27 +19,7 @@ import { SearchSource } from '../search_source'; import { IndexPattern } from '../..'; -import { setSearchService, setUiSettings, setInjectedMetadata } from '../../services'; - -import { - injectedMetadataServiceMock, - uiSettingsServiceMock, -} from '../../../../../core/public/mocks'; - -setUiSettings(uiSettingsServiceMock.createStartContract()); -setInjectedMetadata(injectedMetadataServiceMock.createSetupContract()); -setSearchService({ - aggs: { - calculateAutoTimeExpression: jest.fn().mockReturnValue('1d'), - }, - search: jest.fn(), - __LEGACY: { - esClient: { - search: jest.fn(), - msearch: jest.fn(), - }, - }, -}); +import { mockDataServices } from '../aggs/test_helpers'; jest.mock('../fetch', () => ({ fetchSoon: jest.fn().mockResolvedValue({}), @@ -64,6 +44,10 @@ const indexPattern2 = ({ } as unknown) as IndexPattern; describe('SearchSource', function() { + beforeEach(() => { + mockDataServices(); + }); + describe('#setField()', function() { it('sets the value for the property', function() { const searchSource = new SearchSource(); diff --git a/src/plugins/data/public/search/search_strategy/default_search_strategy.test.ts b/src/plugins/data/public/search/search_strategy/default_search_strategy.test.ts index e4206322a0afdd..e4f492c89e0efd 100644 --- a/src/plugins/data/public/search/search_strategy/default_search_strategy.test.ts +++ b/src/plugins/data/public/search/search_strategy/default_search_strategy.test.ts @@ -18,6 +18,7 @@ */ import { IUiSettingsClient } from '../../../../../core/public'; +import { ISearchStart } from '../types'; import { SearchStrategySearchParams } from './types'; import { defaultSearchStrategy } from './default_search_strategy'; @@ -62,10 +63,7 @@ describe('defaultSearchStrategy', function() { }, ], esShardTimeout: 0, - searchService: { - aggs: { - calculateAutoTimeExpression: jest.fn().mockReturnValue('1d'), - }, + searchService: ({ search: newSearchMock, __LEGACY: { esClient: { @@ -73,7 +71,7 @@ describe('defaultSearchStrategy', function() { msearch: msearchMock, }, }, - }, + } as unknown) as jest.Mocked, }; es = searchArgs.searchService.__LEGACY.esClient; diff --git a/src/legacy/core_plugins/data/public/search/tabify/buckets.test.ts b/src/plugins/data/public/search/tabify/buckets.test.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/tabify/buckets.test.ts rename to src/plugins/data/public/search/tabify/buckets.test.ts diff --git a/src/legacy/core_plugins/data/public/search/tabify/buckets.ts b/src/plugins/data/public/search/tabify/buckets.ts similarity index 97% rename from src/legacy/core_plugins/data/public/search/tabify/buckets.ts rename to src/plugins/data/public/search/tabify/buckets.ts index 8078136299f8c6..971e820ac6ddf6 100644 --- a/src/legacy/core_plugins/data/public/search/tabify/buckets.ts +++ b/src/plugins/data/public/search/tabify/buckets.ts @@ -20,8 +20,7 @@ import { get, isPlainObject, keys, findKey } from 'lodash'; import moment from 'moment'; import { IAggConfig } from '../aggs'; -import { TabbedRangeFilterParams } from './types'; -import { AggResponseBucket } from '../types'; +import { AggResponseBucket, TabbedRangeFilterParams } from './types'; type AggParams = IAggConfig['params'] & { drop_partials: boolean; diff --git a/src/legacy/core_plugins/data/public/search/tabify/get_columns.test.ts b/src/plugins/data/public/search/tabify/get_columns.test.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/tabify/get_columns.test.ts rename to src/plugins/data/public/search/tabify/get_columns.test.ts diff --git a/src/legacy/core_plugins/data/public/search/tabify/get_columns.ts b/src/plugins/data/public/search/tabify/get_columns.ts similarity index 99% rename from src/legacy/core_plugins/data/public/search/tabify/get_columns.ts rename to src/plugins/data/public/search/tabify/get_columns.ts index 8bffca65b4ae2f..ee8c636fb2e864 100644 --- a/src/legacy/core_plugins/data/public/search/tabify/get_columns.ts +++ b/src/plugins/data/public/search/tabify/get_columns.ts @@ -20,6 +20,7 @@ import { groupBy } from 'lodash'; import { IAggConfig } from '../aggs'; import { TabbedAggColumn } from './types'; + const getColumn = (agg: IAggConfig, i: number): TabbedAggColumn => { return { aggConfig: agg, diff --git a/src/legacy/core_plugins/data/public/search/tabify/index.ts b/src/plugins/data/public/search/tabify/index.ts similarity index 100% rename from src/legacy/core_plugins/data/public/search/tabify/index.ts rename to src/plugins/data/public/search/tabify/index.ts diff --git a/src/legacy/core_plugins/data/public/search/tabify/response_writer.test.ts b/src/plugins/data/public/search/tabify/response_writer.test.ts similarity index 99% rename from src/legacy/core_plugins/data/public/search/tabify/response_writer.test.ts rename to src/plugins/data/public/search/tabify/response_writer.test.ts index 91835bc948abb0..ca84f08de8c8ac 100644 --- a/src/legacy/core_plugins/data/public/search/tabify/response_writer.test.ts +++ b/src/plugins/data/public/search/tabify/response_writer.test.ts @@ -20,7 +20,6 @@ import { TabbedAggResponseWriter } from './response_writer'; import { AggConfigs, BUCKET_TYPES } from '../aggs'; import { mockDataServices, mockAggTypesRegistry } from '../aggs/test_helpers'; - import { TabbedResponseWriterOptions } from './types'; describe('TabbedAggResponseWriter class', () => { diff --git a/src/legacy/core_plugins/data/public/search/tabify/response_writer.ts b/src/plugins/data/public/search/tabify/response_writer.ts similarity index 98% rename from src/legacy/core_plugins/data/public/search/tabify/response_writer.ts rename to src/plugins/data/public/search/tabify/response_writer.ts index c910eda0245404..cacecbec3be0b4 100644 --- a/src/legacy/core_plugins/data/public/search/tabify/response_writer.ts +++ b/src/plugins/data/public/search/tabify/response_writer.ts @@ -18,7 +18,7 @@ */ import { isEmpty } from 'lodash'; -import { IAggConfigs } from '../aggs/agg_configs'; +import { IAggConfigs } from '../aggs'; import { tabifyGetColumns } from './get_columns'; import { TabbedResponseWriterOptions, TabbedAggColumn, TabbedAggRow, TabbedTable } from './types'; diff --git a/src/legacy/core_plugins/data/public/search/tabify/tabify.test.ts b/src/plugins/data/public/search/tabify/tabify.test.ts similarity index 97% rename from src/legacy/core_plugins/data/public/search/tabify/tabify.test.ts rename to src/plugins/data/public/search/tabify/tabify.test.ts index 7e7748c00ab435..c9bf04ae9f0fc3 100644 --- a/src/legacy/core_plugins/data/public/search/tabify/tabify.test.ts +++ b/src/plugins/data/public/search/tabify/tabify.test.ts @@ -17,9 +17,9 @@ * under the License. */ -import { IndexPattern } from '../../../../../../plugins/data/public'; import { tabifyAggResponse } from './tabify'; -import { IAggConfig, IAggConfigs, AggConfigs } from '../aggs'; +import { IndexPattern } from '../../index_patterns'; +import { AggConfigs, IAggConfig, IAggConfigs } from '../aggs'; import { mockAggTypesRegistry } from '../aggs/test_helpers'; import { metricOnly, threeTermBuckets } from 'fixtures/fake_hierarchical_data'; diff --git a/src/legacy/core_plugins/data/public/search/tabify/tabify.ts b/src/plugins/data/public/search/tabify/tabify.ts similarity index 98% rename from src/legacy/core_plugins/data/public/search/tabify/tabify.ts rename to src/plugins/data/public/search/tabify/tabify.ts index 078d3f7f72759b..e93e9890342529 100644 --- a/src/legacy/core_plugins/data/public/search/tabify/tabify.ts +++ b/src/plugins/data/public/search/tabify/tabify.ts @@ -21,8 +21,8 @@ import { get } from 'lodash'; import { TabbedAggResponseWriter } from './response_writer'; import { TabifyBuckets } from './buckets'; import { TabbedResponseWriterOptions, TabbedRangeFilterParams } from './types'; -import { AggResponseBucket } from '../types'; -import { IAggConfigs, AggGroupNames } from '../aggs'; +import { AggResponseBucket } from './types'; +import { AggGroupNames, IAggConfigs } from '../aggs'; /** * Sets up the ResponseWriter and kicks off bucket collection. diff --git a/src/legacy/core_plugins/data/public/search/tabify/types.ts b/src/plugins/data/public/search/tabify/types.ts similarity index 89% rename from src/legacy/core_plugins/data/public/search/tabify/types.ts rename to src/plugins/data/public/search/tabify/types.ts index 964a9d2080e7bd..1e051880d3f19f 100644 --- a/src/legacy/core_plugins/data/public/search/tabify/types.ts +++ b/src/plugins/data/public/search/tabify/types.ts @@ -17,7 +17,7 @@ * under the License. */ -import { RangeFilterParams } from '../../../../../../plugins/data/public'; +import { RangeFilterParams } from '../../../common'; import { IAggConfig } from '../aggs'; /** @internal **/ @@ -32,6 +32,13 @@ export interface TabbedResponseWriterOptions { timeRange?: { [key: string]: RangeFilterParams }; } +/** @internal */ +export interface AggResponseBucket { + key_as_string: string; + key: number; + doc_count: number; +} + /** @public **/ export interface TabbedAggColumn { aggConfig: IAggConfig; diff --git a/src/plugins/data/public/search/types.ts b/src/plugins/data/public/search/types.ts index caea178212f560..1732c384b1a856 100644 --- a/src/plugins/data/public/search/types.ts +++ b/src/plugins/data/public/search/types.ts @@ -18,7 +18,7 @@ */ import { CoreStart } from 'kibana/public'; -import { TimeRange } from '../../common'; +import { SearchAggsSetup, SearchAggsStart, SearchAggsStartLegacy } from './aggs'; import { ISearch, ISearchGeneric } from './i_search'; import { TStrategyTypes } from './strategy_types'; import { LegacyApiCaller } from './es_client'; @@ -67,12 +67,8 @@ export type TRegisterSearchStrategyProvider = ( searchStrategyProvider: TSearchStrategyProvider ) => void; -interface SearchAggsSetup { - calculateAutoTimeExpression: (range: TimeRange) => string | undefined; -} - -interface SearchAggsStart { - calculateAutoTimeExpression: (range: TimeRange) => string | undefined; +interface ISearchStartLegacy { + esClient: LegacyApiCaller; } /** @@ -91,7 +87,5 @@ export interface ISearchSetup { export interface ISearchStart { aggs: SearchAggsStart; search: ISearchGeneric; - __LEGACY: { - esClient: LegacyApiCaller; - }; + __LEGACY: ISearchStartLegacy & SearchAggsStartLegacy; } diff --git a/src/plugins/data/public/types.ts b/src/plugins/data/public/types.ts index c1480920809dd9..45160cbf301799 100644 --- a/src/plugins/data/public/types.ts +++ b/src/plugins/data/public/types.ts @@ -20,9 +20,11 @@ import React from 'react'; import { CoreStart } from 'src/core/public'; import { IStorageWrapper } from 'src/plugins/kibana_utils/public'; +import { ExpressionsSetup } from 'src/plugins/expressions/public'; import { UiActionsSetup, UiActionsStart } from 'src/plugins/ui_actions/public'; import { AutocompleteSetup, AutocompleteStart } from './autocomplete'; import { FieldFormatsSetup, FieldFormatsStart } from './field_formats'; +import { createFiltersFromEvent } from './actions'; import { ISearchSetup, ISearchStart } from './search'; import { QuerySetup, QueryStart } from './query'; import { IndexPatternSelectProps } from './ui/index_pattern_select'; @@ -30,6 +32,7 @@ import { IndexPatternsContract } from './index_patterns'; import { StatefulSearchBarProps } from './ui/search_bar/create_search_bar'; export interface DataSetupDependencies { + expressions: ExpressionsSetup; uiActions: UiActionsSetup; } @@ -45,6 +48,9 @@ export interface DataPublicPluginSetup { } export interface DataPublicPluginStart { + actions: { + createFiltersFromEvent: typeof createFiltersFromEvent; + }; autocomplete: AutocompleteStart; indexPatterns: IndexPatternsContract; search: ISearchStart; diff --git a/src/plugins/data/server/index.ts b/src/plugins/data/server/index.ts index 18ba1130cc26ab..0165486fc2de71 100644 --- a/src/plugins/data/server/index.ts +++ b/src/plugins/data/server/index.ts @@ -151,6 +151,19 @@ export { * Search */ +import { + dateHistogramInterval, + InvalidEsCalendarIntervalError, + InvalidEsIntervalFormatError, + isValidEsInterval, + isValidInterval, + parseEsInterval, + parseInterval, + toAbsoluteDates, +} from '../common'; + +export { ParsedInterval } from '../common'; + export { ISearch, ICancel, @@ -162,6 +175,20 @@ export { getDefaultSearchParams, } from './search'; +// Search namespace +export const search = { + aggs: { + dateHistogramInterval, + InvalidEsCalendarIntervalError, + InvalidEsIntervalFormatError, + isValidEsInterval, + isValidInterval, + parseEsInterval, + parseInterval, + toAbsoluteDates, + }, +}; + /** * Types to be shared externally * @public diff --git a/src/plugins/data/server/index_patterns/index_patterns_service.ts b/src/plugins/data/server/index_patterns/index_patterns_service.ts index 78f34e21b9e416..58e8fbae9f9e24 100644 --- a/src/plugins/data/server/index_patterns/index_patterns_service.ts +++ b/src/plugins/data/server/index_patterns/index_patterns_service.ts @@ -19,10 +19,13 @@ import { CoreSetup, Plugin } from 'kibana/server'; import { registerRoutes } from './routes'; +import { indexPatternSavedObjectType } from '../saved_objects'; export class IndexPatternsService implements Plugin { - public setup({ http }: CoreSetup) { - registerRoutes(http); + public setup(core: CoreSetup) { + core.savedObjects.registerType(indexPatternSavedObjectType); + + registerRoutes(core.http); } public start() {} diff --git a/src/plugins/data/server/plugin.ts b/src/plugins/data/server/plugin.ts index 616e65ad872ab7..efb8759e7beade 100644 --- a/src/plugins/data/server/plugin.ts +++ b/src/plugins/data/server/plugin.ts @@ -21,6 +21,7 @@ import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from '../../.. import { IndexPatternsService } from './index_patterns'; import { ISearchSetup } from './search'; import { SearchService } from './search/search_service'; +import { QueryService } from './query/query_service'; import { ScriptsService } from './scripts'; import { KqlTelemetryService } from './kql_telemetry'; import { UsageCollectionSetup } from '../../usage_collection/server'; @@ -47,6 +48,7 @@ export class DataServerPlugin implements Plugin( - 'searchShim' -); +export class QueryService implements Plugin { + public setup(core: CoreSetup) { + core.savedObjects.registerType(querySavedObjectType); + } + + public start() {} +} diff --git a/src/legacy/core_plugins/dashboard_embeddable_container/index.ts b/src/plugins/data/server/saved_objects/index.ts similarity index 83% rename from src/legacy/core_plugins/dashboard_embeddable_container/index.ts rename to src/plugins/data/server/saved_objects/index.ts index 4a609225e6d7f1..5d980974474de8 100644 --- a/src/legacy/core_plugins/dashboard_embeddable_container/index.ts +++ b/src/plugins/data/server/saved_objects/index.ts @@ -17,7 +17,6 @@ * under the License. */ -// eslint-disable-next-line import/no-default-export -export default function(kibana: any) { - return new kibana.Plugin({}); -} +export { searchSavedObjectType } from './search'; +export { querySavedObjectType } from './query'; +export { indexPatternSavedObjectType } from './index_patterns'; diff --git a/src/plugins/data/server/saved_objects/index_pattern_migrations.test.ts b/src/plugins/data/server/saved_objects/index_pattern_migrations.test.ts new file mode 100644 index 00000000000000..b1410e24986676 --- /dev/null +++ b/src/plugins/data/server/saved_objects/index_pattern_migrations.test.ts @@ -0,0 +1,97 @@ +/* + * 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 { SavedObjectMigrationContext } from 'kibana/server'; +import { indexPatternSavedObjectTypeMigrations } from './index_pattern_migrations'; + +const savedObjectMigrationContext = (null as unknown) as SavedObjectMigrationContext; + +describe('migration index-pattern', () => { + describe('6.5.0', () => { + const migrationFn = indexPatternSavedObjectTypeMigrations['6.5.0']; + + test('adds "type" and "typeMeta" properties to object when not declared', () => { + expect( + migrationFn( + { + type: 'index-pattern', + attributes: {}, + }, + savedObjectMigrationContext + ) + ).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "type": undefined, + "typeMeta": undefined, + }, + "type": "index-pattern", +} +`); + }); + + test('keeps "type" and "typeMeta" properties as is when declared', () => { + expect( + migrationFn( + { + type: 'index-pattern', + attributes: { + type: '123', + typeMeta: '123', + }, + }, + savedObjectMigrationContext + ) + ).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "type": "123", + "typeMeta": "123", + }, + "type": "index-pattern", +} +`); + }); + }); + + describe('7.6.0', () => { + const migrationFn = indexPatternSavedObjectTypeMigrations['7.6.0']; + + test('should remove the parent property and update the subType prop on every field that has them', () => { + const input = { + type: 'index-pattern', + attributes: { + title: 'test', + fields: + '[{"name":"customer_name","type":"string","esTypes":["text"],"count":0,"scripted":false,"searchable":true,"aggregatable":false,"readFromDocValues":false},{"name":"customer_name.keyword","type":"string","esTypes":["keyword"],"count":0,"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true,"subType":"multi","parent":"customer_name"}]', + }, + }; + const expected = { + type: 'index-pattern', + attributes: { + title: 'test', + fields: + '[{"name":"customer_name","type":"string","esTypes":["text"],"count":0,"scripted":false,"searchable":true,"aggregatable":false,"readFromDocValues":false},{"name":"customer_name.keyword","type":"string","esTypes":["keyword"],"count":0,"scripted":false,"searchable":true,"aggregatable":true,"readFromDocValues":true,"subType":{"multi":{"parent":"customer_name"}}}]', + }, + }; + + expect(migrationFn(input, savedObjectMigrationContext)).toEqual(expected); + }); + }); +}); diff --git a/src/plugins/data/server/saved_objects/index_pattern_migrations.ts b/src/plugins/data/server/saved_objects/index_pattern_migrations.ts new file mode 100644 index 00000000000000..7a16386ea484c8 --- /dev/null +++ b/src/plugins/data/server/saved_objects/index_pattern_migrations.ts @@ -0,0 +1,60 @@ +/* + * 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 { flow, omit } from 'lodash'; +import { SavedObjectMigrationFn } from 'kibana/server'; + +const migrateAttributeTypeAndAttributeTypeMeta: SavedObjectMigrationFn = doc => ({ + ...doc, + attributes: { + ...doc.attributes, + type: doc.attributes.type || undefined, + typeMeta: doc.attributes.typeMeta || undefined, + }, +}); + +const migrateSubTypeAndParentFieldProperties: SavedObjectMigrationFn = doc => { + if (!doc.attributes.fields) return doc; + + const fieldsString = doc.attributes.fields; + const fields = JSON.parse(fieldsString) as any[]; + const migratedFields = fields.map(field => { + if (field.subType === 'multi') { + return { + ...omit(field, 'parent'), + subType: { multi: { parent: field.parent } }, + }; + } + + return field; + }); + + return { + ...doc, + attributes: { + ...doc.attributes, + fields: JSON.stringify(migratedFields), + }, + }; +}; + +export const indexPatternSavedObjectTypeMigrations = { + '6.5.0': flow(migrateAttributeTypeAndAttributeTypeMeta), + '7.6.0': flow(migrateSubTypeAndParentFieldProperties), +}; diff --git a/src/plugins/data/server/saved_objects/index_patterns.ts b/src/plugins/data/server/saved_objects/index_patterns.ts new file mode 100644 index 00000000000000..9838071eee5a4e --- /dev/null +++ b/src/plugins/data/server/saved_objects/index_patterns.ts @@ -0,0 +1,58 @@ +/* + * 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 { SavedObjectsType } from 'kibana/server'; +import { indexPatternSavedObjectTypeMigrations } from './index_pattern_migrations'; + +export const indexPatternSavedObjectType: SavedObjectsType = { + name: 'index-pattern', + hidden: false, + namespaceAgnostic: false, + management: { + icon: 'indexPatternApp', + defaultSearchField: 'title', + importableAndExportable: true, + getTitle(obj) { + return obj.attributes.title; + }, + getEditUrl(obj) { + return `/management/kibana/index_patterns/${encodeURIComponent(obj.id)}`; + }, + getInAppUrl(obj) { + return { + path: `/app/kibana#/management/kibana/index_patterns/${encodeURIComponent(obj.id)}`, + uiCapabilitiesPath: 'management.kibana.index_patterns', + }; + }, + }, + mappings: { + properties: { + fieldFormatMap: { type: 'text' }, + fields: { type: 'text' }, + intervalName: { type: 'keyword' }, + notExpandable: { type: 'boolean' }, + sourceFilters: { type: 'text' }, + timeFieldName: { type: 'keyword' }, + title: { type: 'text' }, + type: { type: 'keyword' }, + typeMeta: { type: 'keyword' }, + }, + }, + migrations: indexPatternSavedObjectTypeMigrations, +}; diff --git a/src/legacy/core_plugins/data/mappings.ts b/src/plugins/data/server/saved_objects/query.ts similarity index 50% rename from src/legacy/core_plugins/data/mappings.ts rename to src/plugins/data/server/saved_objects/query.ts index 90777ec8e36512..ff0a6cfde8113d 100644 --- a/src/legacy/core_plugins/data/mappings.ts +++ b/src/plugins/data/server/saved_objects/query.ts @@ -17,34 +17,36 @@ * under the License. */ -export const mappings = { - query: { +import { SavedObjectsType } from 'kibana/server'; + +export const querySavedObjectType: SavedObjectsType = { + name: 'query', + hidden: false, + namespaceAgnostic: false, + management: { + icon: 'search', + defaultSearchField: 'title', + importableAndExportable: true, + getTitle(obj) { + return obj.attributes.title; + }, + getInAppUrl(obj) { + return { + path: `/app/kibana#/discover?_a=(savedQuery:'${encodeURIComponent(obj.id)}')`, + uiCapabilitiesPath: 'discover.show', + }; + }, + }, + mappings: { properties: { - title: { - type: 'text', - }, - description: { - type: 'text', - }, + title: { type: 'text' }, + description: { type: 'text' }, query: { - properties: { - language: { - type: 'keyword', - }, - query: { - type: 'keyword', - index: false, - }, - }, - }, - filters: { - type: 'object', - enabled: false, - }, - timefilter: { - type: 'object', - enabled: false, + properties: { language: { type: 'keyword' }, query: { type: 'keyword', index: false } }, }, + filters: { type: 'object', enabled: false }, + timefilter: { type: 'object', enabled: false }, }, }, + migrations: {}, }; diff --git a/src/plugins/data/server/saved_objects/search.ts b/src/plugins/data/server/saved_objects/search.ts new file mode 100644 index 00000000000000..8b30ff7d08201d --- /dev/null +++ b/src/plugins/data/server/saved_objects/search.ts @@ -0,0 +1,60 @@ +/* + * 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 { SavedObjectsType } from 'kibana/server'; +import { searchSavedObjectTypeMigrations } from './search_migrations'; + +export const searchSavedObjectType: SavedObjectsType = { + name: 'search', + hidden: false, + namespaceAgnostic: false, + management: { + icon: 'discoverApp', + defaultSearchField: 'title', + importableAndExportable: true, + getTitle(obj) { + return obj.attributes.title; + }, + getEditUrl(obj) { + return `/management/kibana/objects/savedSearches/${encodeURIComponent(obj.id)}`; + }, + getInAppUrl(obj) { + return { + path: `/app/kibana#/discover/${encodeURIComponent(obj.id)}`, + uiCapabilitiesPath: 'discover.show', + }; + }, + }, + mappings: { + properties: { + columns: { type: 'keyword' }, + description: { type: 'text' }, + hits: { type: 'integer' }, + kibanaSavedObjectMeta: { + properties: { + searchSourceJSON: { type: 'text' }, + }, + }, + sort: { type: 'keyword' }, + title: { type: 'text' }, + version: { type: 'integer' }, + }, + }, + migrations: searchSavedObjectTypeMigrations, +}; diff --git a/src/plugins/data/server/saved_objects/search_migrations.test.ts b/src/plugins/data/server/saved_objects/search_migrations.test.ts new file mode 100644 index 00000000000000..7fdf2e14aefedf --- /dev/null +++ b/src/plugins/data/server/saved_objects/search_migrations.test.ts @@ -0,0 +1,299 @@ +/* + * 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 { SavedObjectMigrationContext } from 'kibana/server'; +import { searchSavedObjectTypeMigrations } from './search_migrations'; + +const savedObjectMigrationContext = (null as unknown) as SavedObjectMigrationContext; + +describe('migration search', () => { + describe('7.0.0', () => { + const migrationFn = searchSavedObjectTypeMigrations['7.0.0']; + + test('skips errors when searchSourceJSON is null', () => { + const doc = { + id: '123', + type: 'search', + attributes: { + foo: true, + kibanaSavedObjectMeta: { + searchSourceJSON: null, + }, + }, + }; + const migratedDoc = migrationFn(doc, savedObjectMigrationContext); + + expect(migratedDoc).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "foo": true, + "kibanaSavedObjectMeta": Object { + "searchSourceJSON": null, + }, + }, + "id": "123", + "references": Array [], + "type": "search", +} +`); + }); + + test('skips errors when searchSourceJSON is undefined', () => { + const doc = { + id: '123', + type: 'search', + attributes: { + foo: true, + kibanaSavedObjectMeta: { + searchSourceJSON: undefined, + }, + }, + }; + const migratedDoc = migrationFn(doc, savedObjectMigrationContext); + + expect(migratedDoc).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "foo": true, + "kibanaSavedObjectMeta": Object { + "searchSourceJSON": undefined, + }, + }, + "id": "123", + "references": Array [], + "type": "search", +} +`); + }); + + test('skips error when searchSourceJSON is not a string', () => { + const doc = { + id: '123', + type: 'search', + attributes: { + foo: true, + kibanaSavedObjectMeta: { + searchSourceJSON: 123, + }, + }, + }; + const migratedDoc = migrationFn(doc, savedObjectMigrationContext); + + expect(migratedDoc).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "foo": true, + "kibanaSavedObjectMeta": Object { + "searchSourceJSON": 123, + }, + }, + "id": "123", + "references": Array [], + "type": "search", +} +`); + }); + + test('skips error when searchSourceJSON is invalid json', () => { + const doc = { + id: '123', + type: 'search', + attributes: { + foo: true, + kibanaSavedObjectMeta: { + searchSourceJSON: '{abc123}', + }, + }, + }; + const migratedDoc = migrationFn(doc, savedObjectMigrationContext); + + expect(migratedDoc).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "foo": true, + "kibanaSavedObjectMeta": Object { + "searchSourceJSON": "{abc123}", + }, + }, + "id": "123", + "references": Array [], + "type": "search", +} +`); + }); + + test('skips error when "index" and "filter" is missing from searchSourceJSON', () => { + const doc = { + id: '123', + type: 'search', + attributes: { + foo: true, + kibanaSavedObjectMeta: { + searchSourceJSON: JSON.stringify({ bar: true }), + }, + }, + }; + const migratedDoc = migrationFn(doc, savedObjectMigrationContext); + + expect(migratedDoc).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "foo": true, + "kibanaSavedObjectMeta": Object { + "searchSourceJSON": "{\\"bar\\":true}", + }, + }, + "id": "123", + "references": Array [], + "type": "search", +} +`); + }); + + test('extracts "index" attribute from doc', () => { + const doc = { + id: '123', + type: 'search', + attributes: { + foo: true, + kibanaSavedObjectMeta: { + searchSourceJSON: JSON.stringify({ bar: true, index: 'pattern*' }), + }, + }, + }; + const migratedDoc = migrationFn(doc, savedObjectMigrationContext); + + expect(migratedDoc).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "foo": true, + "kibanaSavedObjectMeta": Object { + "searchSourceJSON": "{\\"bar\\":true,\\"indexRefName\\":\\"kibanaSavedObjectMeta.searchSourceJSON.index\\"}", + }, + }, + "id": "123", + "references": Array [ + Object { + "id": "pattern*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern", + }, + ], + "type": "search", +} +`); + }); + + test('extracts index patterns from filter', () => { + const doc = { + id: '123', + type: 'search', + attributes: { + foo: true, + kibanaSavedObjectMeta: { + searchSourceJSON: JSON.stringify({ + bar: true, + filter: [ + { + meta: { + foo: true, + index: 'my-index', + }, + }, + ], + }), + }, + }, + }; + const migratedDoc = migrationFn(doc, savedObjectMigrationContext); + + expect(migratedDoc).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "foo": true, + "kibanaSavedObjectMeta": Object { + "searchSourceJSON": "{\\"bar\\":true,\\"filter\\":[{\\"meta\\":{\\"foo\\":true,\\"indexRefName\\":\\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\\"}}]}", + }, + }, + "id": "123", + "references": Array [ + Object { + "id": "my-index", + "name": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index", + "type": "index-pattern", + }, + ], + "type": "search", +} +`); + }); + }); + + describe('7.4.0', function() { + const migrationFn = searchSavedObjectTypeMigrations['7.4.0']; + + test('transforms one dimensional sort arrays into two dimensional arrays', () => { + const doc = { + id: '123', + type: 'search', + attributes: { + sort: ['bytes', 'desc'], + }, + }; + + const expected = { + id: '123', + type: 'search', + attributes: { + sort: [['bytes', 'desc']], + }, + }; + + const migratedDoc = migrationFn(doc, savedObjectMigrationContext); + + expect(migratedDoc).toEqual(expected); + }); + + test("doesn't modify search docs that already have two dimensional sort arrays", () => { + const doc = { + id: '123', + type: 'search', + attributes: { + sort: [['bytes', 'desc']], + }, + }; + + const migratedDoc = migrationFn(doc, savedObjectMigrationContext); + + expect(migratedDoc).toEqual(doc); + }); + + test("doesn't modify search docs that have no sort array", () => { + const doc = { + id: '123', + type: 'search', + attributes: {}, + }; + + const migratedDoc = migrationFn(doc, savedObjectMigrationContext); + + expect(migratedDoc).toEqual(doc); + }); + }); +}); diff --git a/src/plugins/data/server/saved_objects/search_migrations.ts b/src/plugins/data/server/saved_objects/search_migrations.ts new file mode 100644 index 00000000000000..db545e52ce170e --- /dev/null +++ b/src/plugins/data/server/saved_objects/search_migrations.ts @@ -0,0 +1,92 @@ +/* + * 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 { flow, get } from 'lodash'; +import { SavedObjectMigrationFn } from 'kibana/server'; + +const migrateIndexPattern: SavedObjectMigrationFn = doc => { + const searchSourceJSON = get(doc, 'attributes.kibanaSavedObjectMeta.searchSourceJSON'); + if (typeof searchSourceJSON !== 'string') { + return doc; + } + let searchSource; + try { + searchSource = JSON.parse(searchSourceJSON); + } catch (e) { + // Let it go, the data is invalid and we'll leave it as is + return doc; + } + + if (searchSource.index && Array.isArray(doc.references)) { + searchSource.indexRefName = 'kibanaSavedObjectMeta.searchSourceJSON.index'; + doc.references.push({ + name: searchSource.indexRefName, + type: 'index-pattern', + id: searchSource.index, + }); + delete searchSource.index; + } + if (searchSource.filter) { + searchSource.filter.forEach((filterRow: any, i: number) => { + if (!filterRow.meta || !filterRow.meta.index || !Array.isArray(doc.references)) { + return; + } + filterRow.meta.indexRefName = `kibanaSavedObjectMeta.searchSourceJSON.filter[${i}].meta.index`; + doc.references.push({ + name: filterRow.meta.indexRefName, + type: 'index-pattern', + id: filterRow.meta.index, + }); + delete filterRow.meta.index; + }); + } + + doc.attributes.kibanaSavedObjectMeta.searchSourceJSON = JSON.stringify(searchSource); + + return doc; +}; + +const setNewReferences: SavedObjectMigrationFn = (doc, context) => { + doc.references = doc.references || []; + // Migrate index pattern + return migrateIndexPattern(doc, context); +}; + +const migrateSearchSortToNestedArray: SavedObjectMigrationFn = doc => { + const sort = get(doc, 'attributes.sort'); + if (!sort) return doc; + + // Don't do anything if we already have a two dimensional array + if (Array.isArray(sort) && sort.length > 0 && Array.isArray(sort[0])) { + return doc; + } + + return { + ...doc, + attributes: { + ...doc.attributes, + sort: [doc.attributes.sort], + }, + }; +}; + +export const searchSavedObjectTypeMigrations = { + '7.0.0': flow(setNewReferences), + '7.4.0': flow(migrateSearchSortToNestedArray), +}; diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index 09bb150594177e..5ee19cd3df19f3 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -34,6 +34,8 @@ import { import { IRouteHandlerSearchContext } from './i_route_handler_search_context'; import { ES_SEARCH_STRATEGY, esSearchStrategyProvider } from './es_search'; +import { searchSavedObjectType } from '../saved_objects'; + declare module 'kibana/server' { interface RequestHandlerContext { search?: IRouteHandlerSearchContext; @@ -53,9 +55,11 @@ export class SearchService implements Plugin { this.contextContainer = core.context.createContextContainer(); + core.savedObjects.registerType(searchSavedObjectType); + core.http.registerRouteHandlerContext<'search'>('search', context => { return createApi({ - caller: context.core!.elasticsearch.dataClient.callAsCurrentUser, + caller: context.core.elasticsearch.dataClient.callAsCurrentUser, searchStrategies: this.searchStrategies, }); }); diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index a1f59b776328c5..2a2d9bb414c14f 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -143,6 +143,7 @@ import { TasksListParams } from 'elasticsearch'; import { TermvectorsParams } from 'elasticsearch'; import { Type } from '@kbn/config-schema'; import { TypeOf } from '@kbn/config-schema'; +import { Unit } from '@elastic/datemath'; import { UpdateDocumentByQueryParams } from 'elasticsearch'; import { UpdateDocumentParams } from 'elasticsearch'; import { Url } from 'url'; @@ -280,7 +281,7 @@ export interface FieldFormatConfig { export const fieldFormats: { FieldFormatsRegistry: typeof FieldFormatsRegistry; FieldFormat: typeof FieldFormat; - serializeFieldFormat: (agg: import("../../../legacy/core_plugins/data/public/search").AggConfig) => import("../../expressions/common").SerializedFieldFormat; + serializeFieldFormat: (agg: import("../public/search").AggConfig) => import("../../expressions/common").SerializedFieldFormat; BoolFormat: typeof BoolFormat; BytesFormat: typeof BytesFormat; ColorFormat: typeof ColorFormat; @@ -575,6 +576,12 @@ export interface KueryNode { type: keyof NodeTypes; } +// Warning: (ae-forgotten-export) The symbol "parseEsInterval" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "ParsedInterval" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type ParsedInterval = ReturnType; + // Warning: (ae-missing-release-tag) "parseInterval" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -655,6 +662,22 @@ export interface RefreshInterval { value: number; } +// Warning: (ae-missing-release-tag) "search" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const search: { + aggs: { + dateHistogramInterval: typeof dateHistogramInterval; + InvalidEsCalendarIntervalError: typeof InvalidEsCalendarIntervalError; + InvalidEsIntervalFormatError: typeof InvalidEsIntervalFormatError; + isValidEsInterval: typeof isValidEsInterval; + isValidInterval: typeof isValidInterval; + parseEsInterval: typeof parseEsInterval; + parseInterval: typeof parseInterval; + toAbsoluteDates: typeof toAbsoluteDates; + }; +}; + // Warning: (ae-missing-release-tag) "shouldReadFieldFromDocValues" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -704,7 +727,13 @@ export type TSearchStrategyProvider = (context: ISearc // src/plugins/data/server/index.ts:102:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index.ts:130:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index.ts:130:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/plugin.ts:62:14 - (ae-forgotten-export) The symbol "ISearchSetup" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:181:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:182:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:183:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:184:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:185:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:188:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/plugin.ts:64:14 - (ae-forgotten-export) The symbol "ISearchSetup" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/src/plugins/embeddable/public/api/index.ts b/src/plugins/embeddable/public/api/index.ts deleted file mode 100644 index aec539330de9af..00000000000000 --- a/src/plugins/embeddable/public/api/index.ts +++ /dev/null @@ -1,47 +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 { - EmbeddableApiPure, - EmbeddableDependencies, - EmbeddableApi, - EmbeddableDependenciesInternal, -} from './types'; -import { getEmbeddableFactories } from './get_embeddable_factories'; -import { getEmbeddableFactory } from './get_embeddable_factory'; -import { registerEmbeddableFactory } from './register_embeddable_factory'; - -export * from './types'; - -export const pureApi: EmbeddableApiPure = { - getEmbeddableFactories, - getEmbeddableFactory, - registerEmbeddableFactory, -}; - -export const createApi = (deps: EmbeddableDependencies) => { - const partialApi: Partial = {}; - const depsInternal: EmbeddableDependenciesInternal = { ...deps, api: partialApi }; - for (const [key, fn] of Object.entries(pureApi)) { - (partialApi as any)[key] = fn(depsInternal); - } - Object.freeze(partialApi); - const api = partialApi as EmbeddableApi; - return { api, depsInternal }; -}; diff --git a/src/plugins/embeddable/public/api/types.ts b/src/plugins/embeddable/public/api/types.ts deleted file mode 100644 index 179d96a4aff8cf..00000000000000 --- a/src/plugins/embeddable/public/api/types.ts +++ /dev/null @@ -1,43 +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 { EmbeddableFactoryRegistry } from '../types'; -import { EmbeddableFactory, GetEmbeddableFactories } from '../lib'; - -export interface EmbeddableApi { - getEmbeddableFactory: (embeddableFactoryId: string) => EmbeddableFactory; - getEmbeddableFactories: GetEmbeddableFactories; - // TODO: Make `registerEmbeddableFactory` receive only `factory` argument. - registerEmbeddableFactory: ( - id: string, - factory: TEmbeddableFactory - ) => void; -} - -export interface EmbeddableDependencies { - embeddableFactories: EmbeddableFactoryRegistry; -} - -export interface EmbeddableDependenciesInternal extends EmbeddableDependencies { - api: Readonly>; -} - -export type EmbeddableApiPure = { - [K in keyof EmbeddableApi]: (deps: EmbeddableDependenciesInternal) => EmbeddableApi[K]; -}; diff --git a/src/plugins/embeddable/public/bootstrap.ts b/src/plugins/embeddable/public/bootstrap.ts index e69361178eeba1..c8c4f0b95c4587 100644 --- a/src/plugins/embeddable/public/bootstrap.ts +++ b/src/plugins/embeddable/public/bootstrap.ts @@ -17,20 +17,11 @@ * under the License. */ import { UiActionsSetup } from '../../ui_actions/public'; -import { Filter } from '../../data/public'; import { - applyFilterTrigger, contextMenuTrigger, createFilterAction, panelBadgeTrigger, - selectRangeTrigger, - valueClickTrigger, - EmbeddableVisTriggerContext, - IEmbeddable, EmbeddableContext, - APPLY_FILTER_TRIGGER, - VALUE_CLICK_TRIGGER, - SELECT_RANGE_TRIGGER, CONTEXT_MENU_TRIGGER, PANEL_BADGE_TRIGGER, ACTION_ADD_PANEL, @@ -44,12 +35,6 @@ import { declare module '../../ui_actions/public' { export interface TriggerContextMapping { - [SELECT_RANGE_TRIGGER]: EmbeddableVisTriggerContext; - [VALUE_CLICK_TRIGGER]: EmbeddableVisTriggerContext; - [APPLY_FILTER_TRIGGER]: { - embeddable: IEmbeddable; - filters: Filter[]; - }; [CONTEXT_MENU_TRIGGER]: EmbeddableContext; [PANEL_BADGE_TRIGGER]: EmbeddableContext; } @@ -70,10 +55,7 @@ declare module '../../ui_actions/public' { */ export const bootstrap = (uiActions: UiActionsSetup) => { uiActions.registerTrigger(contextMenuTrigger); - uiActions.registerTrigger(applyFilterTrigger); uiActions.registerTrigger(panelBadgeTrigger); - uiActions.registerTrigger(selectRangeTrigger); - uiActions.registerTrigger(valueClickTrigger); const actionApplyFilter = createFilterAction(); diff --git a/src/plugins/embeddable/public/index.ts b/src/plugins/embeddable/public/index.ts index 0b5fd8184deb10..eca74af4ec2530 100644 --- a/src/plugins/embeddable/public/index.ts +++ b/src/plugins/embeddable/public/index.ts @@ -27,8 +27,6 @@ export { ACTION_ADD_PANEL, AddPanelAction, ACTION_APPLY_FILTER, - APPLY_FILTER_TRIGGER, - applyFilterTrigger, Container, ContainerInput, ContainerOutput, @@ -50,8 +48,6 @@ export { EmbeddableRoot, EmbeddableVisTriggerContext, ErrorEmbeddable, - GetEmbeddableFactories, - GetEmbeddableFactory, IContainer, IEmbeddable, isErrorEmbeddable, @@ -62,10 +58,6 @@ export { PanelNotFoundError, PanelState, PropertySpec, - SELECT_RANGE_TRIGGER, - selectRangeTrigger, - VALUE_CLICK_TRIGGER, - valueClickTrigger, ViewMode, withEmbeddableSubscription, } from './lib'; @@ -74,4 +66,4 @@ export function plugin(initializerContext: PluginInitializerContext) { return new EmbeddablePublicPlugin(initializerContext); } -export { IEmbeddableSetup, IEmbeddableStart } from './plugin'; +export { EmbeddableSetup, EmbeddableStart } from './plugin'; diff --git a/src/plugins/embeddable/public/lib/actions/edit_panel_action.test.tsx b/src/plugins/embeddable/public/lib/actions/edit_panel_action.test.tsx index 142a237a6a311e..9aeaf34f3311b8 100644 --- a/src/plugins/embeddable/public/lib/actions/edit_panel_action.test.tsx +++ b/src/plugins/embeddable/public/lib/actions/edit_panel_action.test.tsx @@ -19,11 +19,13 @@ import { EditPanelAction } from './edit_panel_action'; import { EmbeddableFactory, Embeddable, EmbeddableInput } from '../embeddables'; -import { GetEmbeddableFactory, ViewMode } from '../types'; +import { ViewMode } from '../types'; import { ContactCardEmbeddable } from '../test_samples'; +import { EmbeddableStart } from '../../plugin'; const embeddableFactories = new Map(); -const getFactory: GetEmbeddableFactory = (id: string) => embeddableFactories.get(id); +const getFactory = ((id: string) => + embeddableFactories.get(id)) as EmbeddableStart['getEmbeddableFactory']; class EditableEmbeddable extends Embeddable { public readonly type = 'EDITABLE_EMBEDDABLE'; @@ -82,7 +84,8 @@ test('is not compatible when edit url is not available', async () => { test('is not visible when edit url is available but in view mode', async () => { embeddableFactories.clear(); - const action = new EditPanelAction(type => embeddableFactories.get(type)); + const action = new EditPanelAction((type => + embeddableFactories.get(type)) as EmbeddableStart['getEmbeddableFactory']); expect( await action.isCompatible({ embeddable: new EditableEmbeddable( @@ -98,7 +101,8 @@ test('is not visible when edit url is available but in view mode', async () => { test('is not compatible when edit url is available, in edit mode, but not editable', async () => { embeddableFactories.clear(); - const action = new EditPanelAction(type => embeddableFactories.get(type)); + const action = new EditPanelAction((type => + embeddableFactories.get(type)) as EmbeddableStart['getEmbeddableFactory']); expect( await action.isCompatible({ embeddable: new EditableEmbeddable( diff --git a/src/plugins/embeddable/public/lib/actions/edit_panel_action.ts b/src/plugins/embeddable/public/lib/actions/edit_panel_action.ts index 82f8e33b7ae2f1..9125dc0813f986 100644 --- a/src/plugins/embeddable/public/lib/actions/edit_panel_action.ts +++ b/src/plugins/embeddable/public/lib/actions/edit_panel_action.ts @@ -19,9 +19,10 @@ import { i18n } from '@kbn/i18n'; import { Action } from 'src/plugins/ui_actions/public'; -import { GetEmbeddableFactory, ViewMode } from '../types'; +import { ViewMode } from '../types'; import { EmbeddableFactoryNotFoundError } from '../errors'; import { IEmbeddable } from '../embeddables'; +import { EmbeddableStart } from '../../plugin'; export const ACTION_EDIT_PANEL = 'editPanel'; @@ -34,7 +35,7 @@ export class EditPanelAction implements Action { public readonly id = ACTION_EDIT_PANEL; public order = 15; - constructor(private readonly getEmbeddableFactory: GetEmbeddableFactory) {} + constructor(private readonly getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory']) {} public getDisplayName({ embeddable }: ActionContext) { const factory = this.getEmbeddableFactory(embeddable.type); diff --git a/src/plugins/embeddable/public/lib/containers/container.ts b/src/plugins/embeddable/public/lib/containers/container.ts index 71e7cca3552bbf..5ce79537ccaf3d 100644 --- a/src/plugins/embeddable/public/lib/containers/container.ts +++ b/src/plugins/embeddable/public/lib/containers/container.ts @@ -29,7 +29,7 @@ import { } from '../embeddables'; import { IContainer, ContainerInput, ContainerOutput, PanelState } from './i_container'; import { PanelNotFoundError, EmbeddableFactoryNotFoundError } from '../errors'; -import { GetEmbeddableFactory } from '../types'; +import { EmbeddableStart } from '../../plugin'; const getKeys = (o: T): Array => Object.keys(o) as Array; @@ -49,7 +49,7 @@ export abstract class Container< constructor( input: TContainerInput, output: TContainerOutput, - protected readonly getFactory: GetEmbeddableFactory, + protected readonly getFactory: EmbeddableStart['getEmbeddableFactory'], parent?: Container ) { super(input, output, parent); diff --git a/src/plugins/embeddable/public/lib/containers/embeddable_child_panel.test.tsx b/src/plugins/embeddable/public/lib/containers/embeddable_child_panel.test.tsx index 3c9e6e31220b22..07915ce59e6ca2 100644 --- a/src/plugins/embeddable/public/lib/containers/embeddable_child_panel.test.tsx +++ b/src/plugins/embeddable/public/lib/containers/embeddable_child_panel.test.tsx @@ -20,7 +20,6 @@ import React from 'react'; import { nextTick } from 'test_utils/enzyme_helpers'; import { EmbeddableChildPanel } from './embeddable_child_panel'; -import { GetEmbeddableFactory } from '../types'; import { EmbeddableFactory } from '../embeddables'; import { CONTACT_CARD_EMBEDDABLE } from '../test_samples/embeddables/contact_card/contact_card_embeddable_factory'; import { SlowContactCardEmbeddableFactory } from '../test_samples/embeddables/contact_card/slow_contact_card_embeddable_factory'; @@ -42,7 +41,7 @@ test('EmbeddableChildPanel renders an embeddable when it is done loading', async CONTACT_CARD_EMBEDDABLE, new SlowContactCardEmbeddableFactory({ execAction: (() => null) as any }) ); - const getEmbeddableFactory: GetEmbeddableFactory = (id: string) => embeddableFactories.get(id); + const getEmbeddableFactory = (id: string) => embeddableFactories.get(id); const container = new HelloWorldContainer({ id: 'hello', panels: {} }, { getEmbeddableFactory, @@ -88,7 +87,7 @@ test('EmbeddableChildPanel renders an embeddable when it is done loading', async test(`EmbeddableChildPanel renders an error message if the factory doesn't exist`, async () => { const inspector = inspectorPluginMock.createStartContract(); - const getEmbeddableFactory: GetEmbeddableFactory = () => undefined; + const getEmbeddableFactory = () => undefined; const container = new HelloWorldContainer( { id: 'hello', diff --git a/src/plugins/embeddable/public/lib/containers/embeddable_child_panel.tsx b/src/plugins/embeddable/public/lib/containers/embeddable_child_panel.tsx index e15f1faaa397c2..4c08a80a356bff 100644 --- a/src/plugins/embeddable/public/lib/containers/embeddable_child_panel.tsx +++ b/src/plugins/embeddable/public/lib/containers/embeddable_child_panel.tsx @@ -29,15 +29,15 @@ import { Start as InspectorStartContract } from 'src/plugins/inspector/public'; import { ErrorEmbeddable, IEmbeddable } from '../embeddables'; import { EmbeddablePanel } from '../panel'; import { IContainer } from './i_container'; -import { GetEmbeddableFactory, GetEmbeddableFactories } from '../types'; +import { EmbeddableStart } from '../../plugin'; export interface EmbeddableChildPanelProps { embeddableId: string; className?: string; container: IContainer; getActions: UiActionsService['getTriggerCompatibleActions']; - getEmbeddableFactory: GetEmbeddableFactory; - getAllEmbeddableFactories: GetEmbeddableFactories; + getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory']; + getAllEmbeddableFactories: EmbeddableStart['getEmbeddableFactories']; overlays: CoreStart['overlays']; notifications: CoreStart['notifications']; inspector: InspectorStartContract; diff --git a/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx b/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx index a1b332bb656174..eb10c16806640e 100644 --- a/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx +++ b/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx @@ -22,6 +22,7 @@ import { Adapters } from '../types'; import { IContainer } from '../containers'; import { IEmbeddable, EmbeddableInput, EmbeddableOutput } from './i_embeddable'; import { ViewMode } from '../types'; +import { TriggerContextMapping } from '../ui_actions'; import { EmbeddableActionStorage } from './embeddable_action_storage'; function getPanelTitle(input: EmbeddableInput, output: EmbeddableOutput) { @@ -195,4 +196,8 @@ export abstract class Embeddable< this.onResetInput(newInput); } + + public supportedTriggers(): Array { + return []; + } } diff --git a/src/plugins/embeddable/public/lib/embeddables/embeddable_factory.ts b/src/plugins/embeddable/public/lib/embeddables/embeddable_factory.ts index 162da75c228aa5..81f7f35c900c98 100644 --- a/src/plugins/embeddable/public/lib/embeddables/embeddable_factory.ts +++ b/src/plugins/embeddable/public/lib/embeddables/embeddable_factory.ts @@ -74,13 +74,11 @@ export abstract class EmbeddableFactory< this.savedObjectMetaData = savedObjectMetaData; } - // TODO: Can this be a property? If this "...should be based of capabilities service...", - // TODO: maybe then it should be *async*? /** * Returns whether the current user should be allowed to edit this type of - * embeddable. Most of the time this should be based off the capabilities service. + * embeddable. Most of the time this should be based off the capabilities service, hence it's async. */ - public abstract isEditable(): boolean; + public abstract async isEditable(): Promise; /** * Returns a display name for this type of embeddable. Used in "Create new... " options diff --git a/src/plugins/embeddable/public/lib/embeddables/embeddable_factory_renderer.test.tsx b/src/plugins/embeddable/public/lib/embeddables/embeddable_factory_renderer.test.tsx index 7c3a1c6ca45c41..51b83ea0ecaa34 100644 --- a/src/plugins/embeddable/public/lib/embeddables/embeddable_factory_renderer.test.tsx +++ b/src/plugins/embeddable/public/lib/embeddables/embeddable_factory_renderer.test.tsx @@ -22,21 +22,21 @@ import { HelloWorldEmbeddableFactory, } from '../../../../../../examples/embeddable_examples/public'; import { EmbeddableFactory } from './embeddable_factory'; -import { GetEmbeddableFactory } from '../types'; import { EmbeddableFactoryRenderer } from './embeddable_factory_renderer'; import { mount } from 'enzyme'; import { nextTick } from 'test_utils/enzyme_helpers'; // @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; +import { EmbeddableStart } from '../../plugin'; test('EmbeddableFactoryRenderer renders an embeddable', async () => { const embeddableFactories = new Map(); embeddableFactories.set(HELLO_WORLD_EMBEDDABLE, new HelloWorldEmbeddableFactory()); - const getEmbeddableFactory: GetEmbeddableFactory = (id: string) => embeddableFactories.get(id); + const getEmbeddableFactory = (id: string) => embeddableFactories.get(id); const component = mount( @@ -54,7 +54,7 @@ test('EmbeddableFactoryRenderer renders an embeddable', async () => { }); test('EmbeddableRoot renders an error if the type does not exist', async () => { - const getEmbeddableFactory: GetEmbeddableFactory = (id: string) => undefined; + const getEmbeddableFactory = (id: string) => undefined; const component = mount( ; } diff --git a/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx b/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx index fdff82e63faec1..757d4e6bfddefb 100644 --- a/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx +++ b/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx @@ -26,7 +26,7 @@ import { findTestSubject } from '@elastic/eui/lib/test'; import { I18nProvider } from '@kbn/i18n/react'; import { CONTEXT_MENU_TRIGGER } from '../triggers'; import { Action, UiActionsStart, ActionType } from 'src/plugins/ui_actions/public'; -import { Trigger, GetEmbeddableFactory, ViewMode } from '../types'; +import { Trigger, ViewMode } from '../types'; import { EmbeddableFactory, isErrorEmbeddable } from '../embeddables'; import { EmbeddablePanel } from './embeddable_panel'; import { createEditModeAction } from '../test_samples/actions'; @@ -47,7 +47,7 @@ import { EuiBadge } from '@elastic/eui'; const actionRegistry = new Map>(); const triggerRegistry = new Map(); const embeddableFactories = new Map(); -const getEmbeddableFactory: GetEmbeddableFactory = (id: string) => embeddableFactories.get(id); +const getEmbeddableFactory = (id: string) => embeddableFactories.get(id); const editModeAction = createEditModeAction(); const trigger: Trigger = { diff --git a/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx b/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx index 28474544f40b57..b95060a73252f0 100644 --- a/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx +++ b/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx @@ -27,7 +27,7 @@ import { toMountPoint } from '../../../../kibana_react/public'; import { Start as InspectorStartContract } from '../inspector'; import { CONTEXT_MENU_TRIGGER, PANEL_BADGE_TRIGGER, EmbeddableContext } from '../triggers'; import { IEmbeddable } from '../embeddables/i_embeddable'; -import { ViewMode, GetEmbeddableFactory, GetEmbeddableFactories } from '../types'; +import { ViewMode } from '../types'; import { RemovePanelAction } from './panel_header/panel_actions'; import { AddPanelAction } from './panel_header/panel_actions/add_panel/add_panel_action'; @@ -36,12 +36,13 @@ import { PanelHeader } from './panel_header/panel_header'; import { InspectPanelAction } from './panel_header/panel_actions/inspect_panel_action'; import { EditPanelAction } from '../actions'; import { CustomizePanelModal } from './panel_header/panel_actions/customize_title/customize_panel_modal'; +import { EmbeddableStart } from '../../plugin'; interface Props { embeddable: IEmbeddable; getActions: UiActionsService['getTriggerCompatibleActions']; - getEmbeddableFactory: GetEmbeddableFactory; - getAllEmbeddableFactories: GetEmbeddableFactories; + getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory']; + getAllEmbeddableFactories: EmbeddableStart['getEmbeddableFactories']; overlays: CoreStart['overlays']; notifications: CoreStart['notifications']; inspector: InspectorStartContract; diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.test.tsx b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.test.tsx index 028d6a530236a6..8ee8c8dad9df36 100644 --- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.test.tsx +++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.test.tsx @@ -27,15 +27,15 @@ import { } from '../../../../test_samples/embeddables/filterable_embeddable'; import { FilterableEmbeddableFactory } from '../../../../test_samples/embeddables/filterable_embeddable_factory'; import { FilterableContainer } from '../../../../test_samples/embeddables/filterable_container'; -import { GetEmbeddableFactory } from '../../../../types'; // eslint-disable-next-line import { coreMock } from '../../../../../../../../core/public/mocks'; import { ContactCardEmbeddable } from '../../../../test_samples'; import { esFilters, Filter } from '../../../../../../../../plugins/data/public'; +import { EmbeddableStart } from 'src/plugins/embeddable/public/plugin'; const embeddableFactories = new Map(); embeddableFactories.set(FILTERABLE_EMBEDDABLE, new FilterableEmbeddableFactory()); -const getFactory: GetEmbeddableFactory = (id: string) => embeddableFactories.get(id); +const getFactory = (id: string) => embeddableFactories.get(id); let container: FilterableContainer; let embeddable: FilterableEmbeddable; @@ -58,7 +58,7 @@ beforeEach(async () => { }; container = new FilterableContainer( { id: 'hello', panels: {}, filters: [derivedFilter] }, - getFactory + getFactory as EmbeddableStart['getEmbeddableFactory'] ); const filterableEmbeddable = await container.addNewEmbeddable< diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.ts b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.ts index 36bb742040ccc1..f3a483bb4bda4b 100644 --- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.ts +++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.ts @@ -19,7 +19,8 @@ import { i18n } from '@kbn/i18n'; import { Action } from 'src/plugins/ui_actions/public'; import { NotificationsStart, OverlayStart } from 'src/core/public'; -import { ViewMode, GetEmbeddableFactory, GetEmbeddableFactories } from '../../../../types'; +import { EmbeddableStart } from 'src/plugins/embeddable/public/plugin'; +import { ViewMode } from '../../../../types'; import { openAddPanelFlyout } from './open_add_panel_flyout'; import { IContainer } from '../../../../containers'; @@ -34,8 +35,8 @@ export class AddPanelAction implements Action { public readonly id = ACTION_ADD_PANEL; constructor( - private readonly getFactory: GetEmbeddableFactory, - private readonly getAllFactories: GetEmbeddableFactories, + private readonly getFactory: EmbeddableStart['getEmbeddableFactory'], + private readonly getAllFactories: EmbeddableStart['getEmbeddableFactories'], private readonly overlays: OverlayStart, private readonly notifications: NotificationsStart, private readonly SavedObjectFinder: React.ComponentType diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.test.tsx b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.test.tsx index 5f06e4ec447873..2fa21e40ca0f07 100644 --- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.test.tsx +++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.test.tsx @@ -19,7 +19,6 @@ import * as React from 'react'; import { AddPanelFlyout } from './add_panel_flyout'; -import { GetEmbeddableFactory } from '../../../../types'; import { ContactCardEmbeddableFactory, CONTACT_CARD_EMBEDDABLE, @@ -32,6 +31,7 @@ import { ReactWrapper } from 'enzyme'; import { coreMock } from '../../../../../../../../core/public/mocks'; // @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; +import { EmbeddableStart } from 'src/plugins/embeddable/public/plugin'; function DummySavedObjectFinder(props: { children: React.ReactNode }) { return ( @@ -55,7 +55,7 @@ test('createNewEmbeddable() add embeddable to container', async () => { firstName: 'foo', lastName: 'bar', } as any); - const getEmbeddableFactory: GetEmbeddableFactory = (id: string) => contactCardEmbeddableFactory; + const getEmbeddableFactory = (id: string) => contactCardEmbeddableFactory; const input: ContainerInput<{ firstName: string; lastName: string }> = { id: '1', panels: {}, @@ -66,7 +66,7 @@ test('createNewEmbeddable() add embeddable to container', async () => { new Set([contactCardEmbeddableFactory]).values()} notifications={core.notifications} SavedObjectFinder={() => null} @@ -100,7 +100,8 @@ test('selecting embeddable in "Create new ..." list calls createNewEmbeddable()' firstName: 'foo', lastName: 'bar', } as any); - const getEmbeddableFactory: GetEmbeddableFactory = (id: string) => contactCardEmbeddableFactory; + const getEmbeddableFactory = ((id: string) => + contactCardEmbeddableFactory) as EmbeddableStart['getEmbeddableFactory']; const input: ContainerInput<{ firstName: string; lastName: string }> = { id: '1', panels: {}, diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.tsx b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.tsx index 815394ebd97e05..95eeb63710c32e 100644 --- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.tsx +++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.tsx @@ -29,16 +29,16 @@ import { EuiTitle, } from '@elastic/eui'; +import { EmbeddableStart } from 'src/plugins/embeddable/public/plugin'; import { IContainer } from '../../../../containers'; import { EmbeddableFactoryNotFoundError } from '../../../../errors'; -import { GetEmbeddableFactories, GetEmbeddableFactory } from '../../../../types'; import { SavedObjectFinderCreateNew } from './saved_object_finder_create_new'; interface Props { onClose: () => void; container: IContainer; - getFactory: GetEmbeddableFactory; - getAllFactories: GetEmbeddableFactories; + getFactory: EmbeddableStart['getEmbeddableFactory']; + getAllFactories: EmbeddableStart['getEmbeddableFactories']; notifications: CoreSetup['notifications']; SavedObjectFinder: React.ComponentType; } diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/open_add_panel_flyout.tsx b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/open_add_panel_flyout.tsx index 481693501066c9..a452e07b515771 100644 --- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/open_add_panel_flyout.tsx +++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/open_add_panel_flyout.tsx @@ -18,15 +18,15 @@ */ import React from 'react'; import { NotificationsStart, OverlayStart } from 'src/core/public'; +import { EmbeddableStart } from '../../../../../plugin'; import { toMountPoint } from '../../../../../../../kibana_react/public'; import { IContainer } from '../../../../containers'; import { AddPanelFlyout } from './add_panel_flyout'; -import { GetEmbeddableFactory, GetEmbeddableFactories } from '../../../../types'; export async function openAddPanelFlyout(options: { embeddable: IContainer; - getFactory: GetEmbeddableFactory; - getAllFactories: GetEmbeddableFactories; + getFactory: EmbeddableStart['getEmbeddableFactory']; + getAllFactories: EmbeddableStart['getEmbeddableFactories']; overlays: OverlayStart; notifications: NotificationsStart; SavedObjectFinder: React.ComponentType; diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/customize_title/customize_panel_action.test.ts b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/customize_title/customize_panel_action.test.ts index 4ba63bb025a87a..3f7c917cd16173 100644 --- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/customize_title/customize_panel_action.test.ts +++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/customize_title/customize_panel_action.test.ts @@ -32,7 +32,6 @@ import { ContactCardEmbeddableFactory, } from '../../../../test_samples/embeddables/contact_card/contact_card_embeddable_factory'; import { HelloWorldContainer } from '../../../../test_samples/embeddables/hello_world_container'; -import { GetEmbeddableFactory } from '../../../../types'; import { EmbeddableFactory } from '../../../../embeddables'; let container: Container; @@ -40,7 +39,7 @@ let embeddable: ContactCardEmbeddable; function createHelloWorldContainer(input = { id: '123', panels: {} }) { const embeddableFactories = new Map(); - const getEmbeddableFactory: GetEmbeddableFactory = (id: string) => embeddableFactories.get(id); + const getEmbeddableFactory = (id: string) => embeddableFactories.get(id); embeddableFactories.set( CONTACT_CARD_EMBEDDABLE, new ContactCardEmbeddableFactory({}, (() => {}) as any, {} as any) diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/inspect_panel_action.test.tsx b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/inspect_panel_action.test.tsx index 8d9beec940acc0..e19acda8419da7 100644 --- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/inspect_panel_action.test.tsx +++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/inspect_panel_action.test.tsx @@ -34,14 +34,14 @@ import { isErrorEmbeddable, ErrorEmbeddable, } from '../../../embeddables'; -import { GetEmbeddableFactory } from '../../../types'; import { of } from '../../../../tests/helpers'; import { esFilters } from '../../../../../../../plugins/data/public'; +import { EmbeddableStart } from 'src/plugins/embeddable/public/plugin'; const setup = async () => { const embeddableFactories = new Map(); embeddableFactories.set(FILTERABLE_EMBEDDABLE, new FilterableEmbeddableFactory()); - const getFactory: GetEmbeddableFactory = (id: string) => embeddableFactories.get(id); + const getFactory = (id: string) => embeddableFactories.get(id); const container = new FilterableContainer( { id: 'hello', @@ -54,7 +54,7 @@ const setup = async () => { }, ], }, - getFactory + getFactory as EmbeddableStart['getEmbeddableFactory'] ); const embeddable: FilterableEmbeddable | ErrorEmbeddable = await container.addNewEmbeddable< diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/remove_panel_action.test.tsx b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/remove_panel_action.test.tsx index be096a4cc60cef..f4d5aa148373bd 100644 --- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/remove_panel_action.test.tsx +++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/remove_panel_action.test.tsx @@ -20,6 +20,7 @@ import { EmbeddableOutput, isErrorEmbeddable } from '../../../'; import { RemovePanelAction } from './remove_panel_action'; import { EmbeddableFactory } from '../../../embeddables'; +import { EmbeddableStart } from '../../../../plugin'; import { FILTERABLE_EMBEDDABLE, FilterableEmbeddable, @@ -27,13 +28,13 @@ import { } from '../../../test_samples/embeddables/filterable_embeddable'; import { FilterableEmbeddableFactory } from '../../../test_samples/embeddables/filterable_embeddable_factory'; import { FilterableContainer } from '../../../test_samples/embeddables/filterable_container'; -import { GetEmbeddableFactory, ViewMode } from '../../../types'; +import { ViewMode } from '../../../types'; import { ContactCardEmbeddable } from '../../../test_samples/embeddables/contact_card/contact_card_embeddable'; import { esFilters, Filter } from '../../../../../../../plugins/data/public'; const embeddableFactories = new Map(); embeddableFactories.set(FILTERABLE_EMBEDDABLE, new FilterableEmbeddableFactory()); -const getFactory: GetEmbeddableFactory = (id: string) => embeddableFactories.get(id); +const getFactory = (id: string) => embeddableFactories.get(id); let container: FilterableContainer; let embeddable: FilterableEmbeddable; @@ -46,7 +47,7 @@ beforeEach(async () => { }; container = new FilterableContainer( { id: 'hello', panels: {}, filters: [derivedFilter], viewMode: ViewMode.EDIT }, - getFactory + getFactory as EmbeddableStart['getEmbeddableFactory'] ); const filterableEmbeddable = await container.addNewEmbeddable< diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_factory.tsx b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_factory.tsx index 7a9ba4fbbf6d62..20a5a8112f4d36 100644 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_factory.tsx +++ b/src/plugins/embeddable/public/lib/test_samples/embeddables/contact_card/contact_card_embeddable_factory.tsx @@ -42,7 +42,7 @@ export class ContactCardEmbeddableFactory extends EmbeddableFactory { public readonly type = FILTERABLE_CONTAINER; constructor( - private readonly getFactory: GetEmbeddableFactory, + private readonly getFactory: EmbeddableStart['getEmbeddableFactory'], options: EmbeddableFactoryOptions = {} ) { super(options); @@ -43,7 +43,7 @@ export class FilterableContainerFactory extends EmbeddableFactory { public readonly type = FILTERABLE_EMBEDDABLE; - public isEditable() { + public async isEditable() { return true; } diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/hello_world_container.tsx b/src/plugins/embeddable/public/lib/test_samples/embeddables/hello_world_container.tsx index c5ba054bebb7ac..a88c3ba0863259 100644 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/hello_world_container.tsx +++ b/src/plugins/embeddable/public/lib/test_samples/embeddables/hello_world_container.tsx @@ -24,7 +24,7 @@ import { UiActionsService } from 'src/plugins/ui_actions/public'; import { Start as InspectorStartContract } from 'src/plugins/inspector/public'; import { Container, ViewMode, ContainerInput } from '../..'; import { HelloWorldContainerComponent } from './hello_world_container_component'; -import { GetEmbeddableFactory, GetEmbeddableFactories } from '../../types'; +import { EmbeddableStart } from '../../../plugin'; export const HELLO_WORLD_CONTAINER = 'HELLO_WORLD_CONTAINER'; @@ -46,8 +46,8 @@ interface HelloWorldContainerInput extends ContainerInput { interface HelloWorldContainerOptions { getActions: UiActionsService['getTriggerCompatibleActions']; - getEmbeddableFactory: GetEmbeddableFactory; - getAllEmbeddableFactories: GetEmbeddableFactories; + getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory']; + getAllEmbeddableFactories: EmbeddableStart['getEmbeddableFactories']; overlays: CoreStart['overlays']; notifications: CoreStart['notifications']; inspector: InspectorStartContract; diff --git a/src/plugins/embeddable/public/lib/test_samples/embeddables/hello_world_container_component.tsx b/src/plugins/embeddable/public/lib/test_samples/embeddables/hello_world_container_component.tsx index e9acfd45397683..e8c1464edab384 100644 --- a/src/plugins/embeddable/public/lib/test_samples/embeddables/hello_world_container_component.tsx +++ b/src/plugins/embeddable/public/lib/test_samples/embeddables/hello_world_container_component.tsx @@ -24,13 +24,13 @@ import { CoreStart } from 'src/core/public'; import { UiActionsService } from 'src/plugins/ui_actions/public'; import { Start as InspectorStartContract } from 'src/plugins/inspector/public'; import { IContainer, PanelState, EmbeddableChildPanel } from '../..'; -import { GetEmbeddableFactory, GetEmbeddableFactories } from '../../types'; +import { EmbeddableStart } from '../../../plugin'; interface Props { container: IContainer; getActions: UiActionsService['getTriggerCompatibleActions']; - getEmbeddableFactory: GetEmbeddableFactory; - getAllEmbeddableFactories: GetEmbeddableFactories; + getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory']; + getAllEmbeddableFactories: EmbeddableStart['getEmbeddableFactories']; overlays: CoreStart['overlays']; notifications: CoreStart['notifications']; inspector: InspectorStartContract; diff --git a/src/plugins/embeddable/public/lib/triggers/triggers.ts b/src/plugins/embeddable/public/lib/triggers/triggers.ts index a348e1ed79d8db..0052403816eb84 100644 --- a/src/plugins/embeddable/public/lib/triggers/triggers.ts +++ b/src/plugins/embeddable/public/lib/triggers/triggers.ts @@ -33,20 +33,6 @@ export interface EmbeddableVisTriggerContext { }; } -export const SELECT_RANGE_TRIGGER = 'SELECT_RANGE_TRIGGER'; -export const selectRangeTrigger: Trigger<'SELECT_RANGE_TRIGGER'> = { - id: SELECT_RANGE_TRIGGER, - title: 'Select range', - description: 'Applies a range filter', -}; - -export const VALUE_CLICK_TRIGGER = 'VALUE_CLICK_TRIGGER'; -export const valueClickTrigger: Trigger<'VALUE_CLICK_TRIGGER'> = { - id: VALUE_CLICK_TRIGGER, - title: 'Value clicked', - description: 'Value was clicked', -}; - export const CONTEXT_MENU_TRIGGER = 'CONTEXT_MENU_TRIGGER'; export const contextMenuTrigger: Trigger<'CONTEXT_MENU_TRIGGER'> = { id: CONTEXT_MENU_TRIGGER, @@ -54,13 +40,6 @@ export const contextMenuTrigger: Trigger<'CONTEXT_MENU_TRIGGER'> = { description: 'Triggered on top-right corner context-menu select.', }; -export const APPLY_FILTER_TRIGGER = 'FILTER_TRIGGER'; -export const applyFilterTrigger: Trigger<'FILTER_TRIGGER'> = { - id: APPLY_FILTER_TRIGGER, - title: 'Filter click', - description: 'Triggered when user applies filter to an embeddable.', -}; - export const PANEL_BADGE_TRIGGER = 'PANEL_BADGE_TRIGGER'; export const panelBadgeTrigger: Trigger<'PANEL_BADGE_TRIGGER'> = { id: PANEL_BADGE_TRIGGER, diff --git a/src/plugins/embeddable/public/lib/types.ts b/src/plugins/embeddable/public/lib/types.ts index 68ea5bc17f7c97..1cfff7baca1862 100644 --- a/src/plugins/embeddable/public/lib/types.ts +++ b/src/plugins/embeddable/public/lib/types.ts @@ -18,7 +18,6 @@ */ import { Adapters } from './inspector'; -import { EmbeddableFactory } from './embeddables/embeddable_factory'; export interface Trigger { id: string; @@ -40,6 +39,3 @@ export enum ViewMode { } export { Adapters }; - -export type GetEmbeddableFactory = (id: string) => EmbeddableFactory | undefined; -export type GetEmbeddableFactories = () => IterableIterator; diff --git a/src/plugins/embeddable/public/mocks.ts b/src/plugins/embeddable/public/mocks.ts index fd299bc626fb9e..ba2f78e42e10eb 100644 --- a/src/plugins/embeddable/public/mocks.ts +++ b/src/plugins/embeddable/public/mocks.ts @@ -17,15 +17,15 @@ * under the License. */ -import { IEmbeddableStart, IEmbeddableSetup } from '.'; +import { EmbeddableStart, EmbeddableSetup } from '.'; import { EmbeddablePublicPlugin } from './plugin'; import { coreMock } from '../../../core/public/mocks'; // eslint-disable-next-line import { uiActionsPluginMock } from '../../ui_actions/public/mocks'; -export type Setup = jest.Mocked; -export type Start = jest.Mocked; +export type Setup = jest.Mocked; +export type Start = jest.Mocked; const createSetupContract = (): Setup => { const setupContract: Setup = { @@ -36,7 +36,6 @@ const createSetupContract = (): Setup => { const createStartContract = (): Start => { const startContract: Start = { - registerEmbeddableFactory: jest.fn(), getEmbeddableFactories: jest.fn(), getEmbeddableFactory: jest.fn(), }; diff --git a/src/plugins/embeddable/public/api/tests/registry.test.ts b/src/plugins/embeddable/public/plugin.test.ts similarity index 70% rename from src/plugins/embeddable/public/api/tests/registry.test.ts rename to src/plugins/embeddable/public/plugin.test.ts index 30a8a71d243f95..c334411004e2c1 100644 --- a/src/plugins/embeddable/public/api/tests/registry.test.ts +++ b/src/plugins/embeddable/public/plugin.test.ts @@ -16,18 +16,20 @@ * specific language governing permissions and limitations * under the License. */ - -import { createApi } from '..'; -import { createDeps } from './helpers'; +import { coreMock } from '../../../core/public/mocks'; +import { testPlugin } from './tests/test_plugin'; test('cannot register embeddable factory with the same ID', async () => { - const deps = createDeps(); - const { api } = createApi(deps); + const coreSetup = coreMock.createSetup(); + const coreStart = coreMock.createStart(); + const { setup } = testPlugin(coreSetup, coreStart); const embeddableFactoryId = 'ID'; const embeddableFactory = {} as any; - api.registerEmbeddableFactory(embeddableFactoryId, embeddableFactory); - expect(() => api.registerEmbeddableFactory(embeddableFactoryId, embeddableFactory)).toThrowError( + setup.registerEmbeddableFactory(embeddableFactoryId, embeddableFactory); + expect(() => + setup.registerEmbeddableFactory(embeddableFactoryId, embeddableFactory) + ).toThrowError( 'Embeddable factory [embeddableFactoryId = ID] already registered in Embeddables API.' ); }); diff --git a/src/plugins/embeddable/public/plugin.ts b/src/plugins/embeddable/public/plugin.ts index c84fb888412e13..381665c359ffd2 100644 --- a/src/plugins/embeddable/public/plugin.ts +++ b/src/plugins/embeddable/public/plugin.ts @@ -16,45 +16,78 @@ * specific language governing permissions and limitations * under the License. */ - import { UiActionsSetup } from 'src/plugins/ui_actions/public'; import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from '../../../core/public'; import { EmbeddableFactoryRegistry } from './types'; -import { createApi, EmbeddableApi } from './api'; import { bootstrap } from './bootstrap'; +import { EmbeddableFactory, EmbeddableInput, EmbeddableOutput } from './lib'; -export interface IEmbeddableSetupDependencies { +export interface EmbeddableSetupDependencies { uiActions: UiActionsSetup; } -export interface IEmbeddableSetup { - registerEmbeddableFactory: EmbeddableApi['registerEmbeddableFactory']; +export interface EmbeddableSetup { + registerEmbeddableFactory: ( + id: string, + factory: EmbeddableFactory + ) => void; +} +export interface EmbeddableStart { + getEmbeddableFactory: < + I extends EmbeddableInput = EmbeddableInput, + O extends EmbeddableOutput = EmbeddableOutput + >( + embeddableFactoryId: string + ) => EmbeddableFactory | undefined; + getEmbeddableFactories: () => IterableIterator; } -export type IEmbeddableStart = EmbeddableApi; - -export class EmbeddablePublicPlugin implements Plugin { +export class EmbeddablePublicPlugin implements Plugin { private readonly embeddableFactories: EmbeddableFactoryRegistry = new Map(); - private api!: EmbeddableApi; constructor(initializerContext: PluginInitializerContext) {} - public setup(core: CoreSetup, { uiActions }: IEmbeddableSetupDependencies) { - ({ api: this.api } = createApi({ - embeddableFactories: this.embeddableFactories, - })); + public setup(core: CoreSetup, { uiActions }: EmbeddableSetupDependencies) { bootstrap(uiActions); - const { registerEmbeddableFactory } = this.api; - return { - registerEmbeddableFactory, + registerEmbeddableFactory: this.registerEmbeddableFactory, }; } public start(core: CoreStart) { - return this.api; + return { + getEmbeddableFactory: this.getEmbeddableFactory, + getEmbeddableFactories: () => this.embeddableFactories.values(), + }; } public stop() {} + + private registerEmbeddableFactory = (embeddableFactoryId: string, factory: EmbeddableFactory) => { + if (this.embeddableFactories.has(embeddableFactoryId)) { + throw new Error( + `Embeddable factory [embeddableFactoryId = ${embeddableFactoryId}] already registered in Embeddables API.` + ); + } + + this.embeddableFactories.set(embeddableFactoryId, factory); + }; + + private getEmbeddableFactory = < + I extends EmbeddableInput = EmbeddableInput, + O extends EmbeddableOutput = EmbeddableOutput + >( + embeddableFactoryId: string + ) => { + const factory = this.embeddableFactories.get(embeddableFactoryId); + + if (!factory) { + throw new Error( + `Embeddable factory [embeddableFactoryId = ${embeddableFactoryId}] does not exist.` + ); + } + + return factory as EmbeddableFactory; + }; } diff --git a/src/plugins/embeddable/public/tests/apply_filter_action.test.ts b/src/plugins/embeddable/public/tests/apply_filter_action.test.ts index 0721acb1a1fba9..6beef35bbe1368 100644 --- a/src/plugins/embeddable/public/tests/apply_filter_action.test.ts +++ b/src/plugins/embeddable/public/tests/apply_filter_action.test.ts @@ -35,14 +35,14 @@ import { inspectorPluginMock } from 'src/plugins/inspector/public/mocks'; import { esFilters } from '../../../../plugins/data/public'; test('ApplyFilterAction applies the filter to the root of the container tree', async () => { - const { doStart } = testPlugin(); + const { doStart, setup } = testPlugin(); const api = doStart(); const factory1 = new FilterableContainerFactory(api.getEmbeddableFactory); const factory2 = new FilterableEmbeddableFactory(); - api.registerEmbeddableFactory(factory1.type, factory1); - api.registerEmbeddableFactory(factory2.type, factory2); + setup.registerEmbeddableFactory(factory1.type, factory1); + setup.registerEmbeddableFactory(factory2.type, factory2); const applyFilterAction = createFilterAction(); @@ -93,7 +93,7 @@ test('ApplyFilterAction applies the filter to the root of the container tree', a }); test('ApplyFilterAction is incompatible if the root container does not accept a filter as input', async () => { - const { doStart, coreStart } = testPlugin(); + const { doStart, coreStart, setup } = testPlugin(); const api = doStart(); const inspector = inspectorPluginMock.createStartContract(); @@ -112,7 +112,7 @@ test('ApplyFilterAction is incompatible if the root container does not accept a ); const factory = new FilterableEmbeddableFactory(); - api.registerEmbeddableFactory(factory.type, factory); + setup.registerEmbeddableFactory(factory.type, factory); const embeddable = await parent.addNewEmbeddable< FilterableContainerInput, @@ -129,12 +129,12 @@ test('ApplyFilterAction is incompatible if the root container does not accept a }); test('trying to execute on incompatible context throws an error ', async () => { - const { doStart, coreStart } = testPlugin(); + const { doStart, coreStart, setup } = testPlugin(); const api = doStart(); const inspector = inspectorPluginMock.createStartContract(); const factory = new FilterableEmbeddableFactory(); - api.registerEmbeddableFactory(factory.type, factory); + setup.registerEmbeddableFactory(factory.type, factory); const applyFilterAction = createFilterAction(); const parent = new HelloWorldContainer( diff --git a/src/plugins/embeddable/public/tests/container.test.ts b/src/plugins/embeddable/public/tests/container.test.ts index be19ac206999d3..1ee52f47491352 100644 --- a/src/plugins/embeddable/public/tests/container.test.ts +++ b/src/plugins/embeddable/public/tests/container.test.ts @@ -562,7 +562,7 @@ test('Panel added to input state', async () => { test('Container changes made directly after adding a new embeddable are propagated', async done => { const coreSetup = coreMock.createSetup(); const coreStart = coreMock.createStart(); - const { doStart, uiActions } = testPlugin(coreSetup, coreStart); + const { setup, doStart, uiActions } = testPlugin(coreSetup, coreStart); const start = doStart(); const container = new HelloWorldContainer( @@ -586,7 +586,7 @@ test('Container changes made directly after adding a new embeddable are propagat loadTickCount: 3, execAction: uiActions.executeTriggerActions, }); - start.registerEmbeddableFactory(factory.type, factory); + setup.registerEmbeddableFactory(factory.type, factory); const subscription = Rx.merge(container.getOutput$(), container.getInput$()) .pipe(skip(2)) @@ -755,7 +755,7 @@ test('untilEmbeddableLoaded() resolves if child is loaded in the container', asy }); test('untilEmbeddableLoaded resolves with undefined if child is subsequently removed', async done => { - const { doStart, coreStart, uiActions } = testPlugin( + const { doStart, setup, coreStart, uiActions } = testPlugin( coreMock.createSetup(), coreMock.createStart() ); @@ -764,7 +764,7 @@ test('untilEmbeddableLoaded resolves with undefined if child is subsequently rem loadTickCount: 3, execAction: uiActions.executeTriggerActions, }); - start.registerEmbeddableFactory(factory.type, factory); + setup.registerEmbeddableFactory(factory.type, factory); const container = new HelloWorldContainer( { id: 'hello', @@ -795,7 +795,7 @@ test('untilEmbeddableLoaded resolves with undefined if child is subsequently rem }); test('adding a panel then subsequently removing it before its loaded removes the panel', async done => { - const { doStart, coreStart, uiActions } = testPlugin( + const { doStart, coreStart, uiActions, setup } = testPlugin( coreMock.createSetup(), coreMock.createStart() ); @@ -804,7 +804,7 @@ test('adding a panel then subsequently removing it before its loaded removes the loadTickCount: 1, execAction: uiActions.executeTriggerActions, }); - start.registerEmbeddableFactory(factory.type, factory); + setup.registerEmbeddableFactory(factory.type, factory); const container = new HelloWorldContainer( { id: 'hello', diff --git a/src/plugins/embeddable/public/tests/customize_panel_modal.test.tsx b/src/plugins/embeddable/public/tests/customize_panel_modal.test.tsx index 70d7c99d3fb9d0..99d5a7c747d15b 100644 --- a/src/plugins/embeddable/public/tests/customize_panel_modal.test.tsx +++ b/src/plugins/embeddable/public/tests/customize_panel_modal.test.tsx @@ -34,16 +34,16 @@ import { HelloWorldContainer } from '../lib/test_samples/embeddables/hello_world // eslint-disable-next-line import { coreMock } from '../../../../core/public/mocks'; import { testPlugin } from './test_plugin'; -import { EmbeddableApi } from '../api'; import { CustomizePanelModal } from '../lib/panel/panel_header/panel_actions/customize_title/customize_panel_modal'; import { mount } from 'enzyme'; +import { EmbeddableStart } from '../plugin'; -let api: EmbeddableApi; +let api: EmbeddableStart; let container: Container; let embeddable: ContactCardEmbeddable; beforeEach(async () => { - const { doStart, coreStart, uiActions } = testPlugin( + const { doStart, coreStart, uiActions, setup } = testPlugin( coreMock.createSetup(), coreMock.createStart() ); @@ -54,7 +54,7 @@ beforeEach(async () => { uiActions.executeTriggerActions, {} as any ); - api.registerEmbeddableFactory(contactCardFactory.type, contactCardFactory); + setup.registerEmbeddableFactory(contactCardFactory.type, contactCardFactory); container = new HelloWorldContainer( { id: '123', panels: {} }, diff --git a/src/plugins/embeddable/public/tests/test_plugin.ts b/src/plugins/embeddable/public/tests/test_plugin.ts index 1edc3327803365..e199ef193aa1cc 100644 --- a/src/plugins/embeddable/public/tests/test_plugin.ts +++ b/src/plugins/embeddable/public/tests/test_plugin.ts @@ -22,14 +22,14 @@ import { CoreSetup, CoreStart } from 'src/core/public'; import { uiActionsPluginMock } from 'src/plugins/ui_actions/public/mocks'; import { UiActionsStart } from 'src/plugins/ui_actions/public'; import { coreMock } from '../../../../core/public/mocks'; -import { EmbeddablePublicPlugin, IEmbeddableSetup, IEmbeddableStart } from '../plugin'; +import { EmbeddablePublicPlugin, EmbeddableSetup, EmbeddableStart } from '../plugin'; export interface TestPluginReturn { plugin: EmbeddablePublicPlugin; coreSetup: CoreSetup; coreStart: CoreStart; - setup: IEmbeddableSetup; - doStart: (anotherCoreStart?: CoreStart) => IEmbeddableStart; + setup: EmbeddableSetup; + doStart: (anotherCoreStart?: CoreStart) => EmbeddableStart; uiActions: UiActionsStart; } diff --git a/src/plugins/expressions/public/index.ts b/src/plugins/expressions/public/index.ts index 06dd951cd54109..c57db6029ec2e3 100644 --- a/src/plugins/expressions/public/index.ts +++ b/src/plugins/expressions/public/index.ts @@ -94,6 +94,7 @@ export { KibanaContext, KibanaDatatable, KibanaDatatableColumn, + KibanaDatatableColumnMeta, KibanaDatatableRow, KnownTypeToString, Overflow, diff --git a/src/plugins/expressions/server/index.ts b/src/plugins/expressions/server/index.ts index 7894f55fad4f0c..e41135b6939221 100644 --- a/src/plugins/expressions/server/index.ts +++ b/src/plugins/expressions/server/index.ts @@ -85,6 +85,7 @@ export { KibanaContext, KibanaDatatable, KibanaDatatableColumn, + KibanaDatatableColumnMeta, KibanaDatatableRow, KnownTypeToString, Overflow, diff --git a/src/plugins/kibana_legacy/public/angular/index.ts b/src/plugins/kibana_legacy/public/angular/index.ts index 0b234b70428508..5fc37ac39612a4 100644 --- a/src/plugins/kibana_legacy/public/angular/index.ts +++ b/src/plugins/kibana_legacy/public/angular/index.ts @@ -24,3 +24,4 @@ export * from './angular_config'; export { ensureDefaultIndexPattern } from './ensure_default_index_pattern'; // @ts-ignore export { createTopNavDirective, createTopNavHelper, loadKbnTopNavDirectives } from './kbn_top_nav'; +export { subscribeWithScope } from './subscribe_with_scope'; diff --git a/src/legacy/ui/public/utils/subscribe_with_scope.test.ts b/src/plugins/kibana_legacy/public/angular/subscribe_with_scope.test.ts similarity index 75% rename from src/legacy/ui/public/utils/subscribe_with_scope.test.ts rename to src/plugins/kibana_legacy/public/angular/subscribe_with_scope.test.ts index c392d416112c83..a8565b11a7dfd0 100644 --- a/src/legacy/ui/public/utils/subscribe_with_scope.test.ts +++ b/src/plugins/kibana_legacy/public/angular/subscribe_with_scope.test.ts @@ -16,8 +16,6 @@ * specific language governing permissions and limitations * under the License. */ -import { mockFatalError } from './subscribe_with_scope.test.mocks'; - import * as Rx from 'rxjs'; import { subscribeWithScope } from './subscribe_with_scope'; @@ -73,14 +71,20 @@ it('calls observer.next() if already in a digest cycle, wraps in $scope.$apply i }); it('reports fatalError if observer.next() throws', () => { + const fatalError = jest.fn(); const $scope = new Scope(); - subscribeWithScope($scope as any, Rx.of(undefined), { - next() { - throw new Error('foo bar'); + subscribeWithScope( + $scope as any, + Rx.of(undefined), + { + next() { + throw new Error('foo bar'); + }, }, - }); + fatalError + ); - expect(mockFatalError.mock.calls).toMatchInlineSnapshot(` + expect(fatalError.mock.calls).toMatchInlineSnapshot(` Array [ Array [ [Error: foo bar], @@ -90,12 +94,13 @@ Array [ }); it('reports fatal error if observer.error is not defined and observable errors', () => { + const fatalError = jest.fn(); const $scope = new Scope(); const error = new Error('foo'); error.stack = `${error.message}\n---stack trace ---`; - subscribeWithScope($scope as any, Rx.throwError(error)); + subscribeWithScope($scope as any, Rx.throwError(error), undefined, fatalError); - expect(mockFatalError.mock.calls).toMatchInlineSnapshot(` + expect(fatalError.mock.calls).toMatchInlineSnapshot(` Array [ Array [ [Error: Uncaught error in subscribeWithScope(): foo @@ -106,14 +111,20 @@ Array [ }); it('reports fatal error if observer.error throws', () => { + const fatalError = jest.fn(); const $scope = new Scope(); - subscribeWithScope($scope as any, Rx.throwError(new Error('foo')), { - error: () => { - throw new Error('foo'); + subscribeWithScope( + $scope as any, + Rx.throwError(new Error('foo')), + { + error: () => { + throw new Error('foo'); + }, }, - }); + fatalError + ); - expect(mockFatalError.mock.calls).toMatchInlineSnapshot(` + expect(fatalError.mock.calls).toMatchInlineSnapshot(` Array [ Array [ [Error: foo], @@ -123,25 +134,37 @@ Array [ }); it('does not report fatal error if observer.error handles the error', () => { + const fatalError = jest.fn(); const $scope = new Scope(); - subscribeWithScope($scope as any, Rx.throwError(new Error('foo')), { - error: () => { - // noop, swallow error + subscribeWithScope( + $scope as any, + Rx.throwError(new Error('foo')), + { + error: () => { + // noop, swallow error + }, }, - }); + fatalError + ); - expect(mockFatalError.mock.calls).toEqual([]); + expect(fatalError.mock.calls).toEqual([]); }); it('reports fatal error if observer.complete throws', () => { + const fatalError = jest.fn(); const $scope = new Scope(); - subscribeWithScope($scope as any, Rx.EMPTY, { - complete: () => { - throw new Error('foo'); + subscribeWithScope( + $scope as any, + Rx.EMPTY, + { + complete: () => { + throw new Error('foo'); + }, }, - }); + fatalError + ); - expect(mockFatalError.mock.calls).toMatchInlineSnapshot(` + expect(fatalError.mock.calls).toMatchInlineSnapshot(` Array [ Array [ [Error: foo], diff --git a/src/legacy/ui/public/utils/subscribe_with_scope.ts b/src/plugins/kibana_legacy/public/angular/subscribe_with_scope.ts similarity index 67% rename from src/legacy/ui/public/utils/subscribe_with_scope.ts rename to src/plugins/kibana_legacy/public/angular/subscribe_with_scope.ts index f4f158cbbd1a81..519291d39797ce 100644 --- a/src/legacy/ui/public/utils/subscribe_with_scope.ts +++ b/src/plugins/kibana_legacy/public/angular/subscribe_with_scope.ts @@ -19,9 +19,11 @@ import { IScope } from 'angular'; import * as Rx from 'rxjs'; -import { fatalError } from 'ui/notify/fatal_error'; +import { AngularHttpError } from '../notify/lib'; -function callInDigest($scope: IScope, fn: () => void) { +type FatalErrorFn = (error: AngularHttpError | Error | string, location?: string) => void; + +function callInDigest($scope: IScope, fn: () => void, fatalError?: FatalErrorFn) { try { // this is terrible, but necessary to synchronously deliver subscription values // to angular scopes. This is required by some APIs, like the `config` service, @@ -35,7 +37,9 @@ function callInDigest($scope: IScope, fn: () => void) { $scope.$apply(() => fn()); } } catch (error) { - fatalError(error); + if (fatalError) { + fatalError(error); + } } } @@ -46,30 +50,35 @@ function callInDigest($scope: IScope, fn: () => void) { export function subscribeWithScope( $scope: IScope, observable: Rx.Observable, - observer?: Rx.PartialObserver + observer?: Rx.PartialObserver, + fatalError?: FatalErrorFn ) { return observable.subscribe({ next(value) { if (observer && observer.next) { - callInDigest($scope, () => observer.next!(value)); + callInDigest($scope, () => observer.next!(value), fatalError); } }, error(error) { - callInDigest($scope, () => { - if (observer && observer.error) { - observer.error(error); - } else { - throw new Error( - `Uncaught error in subscribeWithScope(): ${ - error ? error.stack || error.message : error - }` - ); - } - }); + callInDigest( + $scope, + () => { + if (observer && observer.error) { + observer.error(error); + } else { + throw new Error( + `Uncaught error in subscribeWithScope(): ${ + error ? error.stack || error.message : error + }` + ); + } + }, + fatalError + ); }, complete() { if (observer && observer.complete) { - callInDigest($scope, () => observer.complete!()); + callInDigest($scope, () => observer.complete!(), fatalError); } }, }); diff --git a/src/plugins/embeddable/public/api/register_embeddable_factory.ts b/src/plugins/kibana_legacy/public/notify/lib/add_fatal_error.ts similarity index 62% rename from src/plugins/embeddable/public/api/register_embeddable_factory.ts rename to src/plugins/kibana_legacy/public/notify/lib/add_fatal_error.ts index 8b7bcdee5911fe..928d59d71fbdf7 100644 --- a/src/plugins/embeddable/public/api/register_embeddable_factory.ts +++ b/src/plugins/kibana_legacy/public/notify/lib/add_fatal_error.ts @@ -16,17 +16,22 @@ * specific language governing permissions and limitations * under the License. */ +import { FatalErrorsSetup } from '../../../../../core/public'; +import { + AngularHttpError, + formatAngularHttpError, + isAngularHttpError, +} from './format_angular_http_error'; -import { EmbeddableApiPure } from './types'; - -export const registerEmbeddableFactory: EmbeddableApiPure['registerEmbeddableFactory'] = ({ - embeddableFactories, -}) => (embeddableFactoryId, factory) => { - if (embeddableFactories.has(embeddableFactoryId)) { - throw new Error( - `Embeddable factory [embeddableFactoryId = ${embeddableFactoryId}] already registered in Embeddables API.` - ); +export function addFatalError( + fatalErrors: FatalErrorsSetup, + error: AngularHttpError | Error | string, + location?: string +) { + // add support for angular http errors to newPlatformFatalErrors + if (isAngularHttpError(error)) { + error = formatAngularHttpError(error); } - embeddableFactories.set(embeddableFactoryId, factory); -}; + fatalErrors.add(error, location); +} diff --git a/src/plugins/kibana_legacy/public/notify/lib/index.ts b/src/plugins/kibana_legacy/public/notify/lib/index.ts index c374b5926b64f0..f43ba91b102e45 100644 --- a/src/plugins/kibana_legacy/public/notify/lib/index.ts +++ b/src/plugins/kibana_legacy/public/notify/lib/index.ts @@ -25,3 +25,4 @@ export { formatAngularHttpError, AngularHttpError, } from './format_angular_http_error'; +export { addFatalError } from './add_fatal_error'; diff --git a/src/plugins/kibana_react/public/index.ts b/src/plugins/kibana_react/public/index.ts index f04c6f1f19c338..e88ca7178cde39 100644 --- a/src/plugins/kibana_react/public/index.ts +++ b/src/plugins/kibana_react/public/index.ts @@ -25,6 +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 { Markdown, MarkdownSimple } from './markdown'; export { reactToUiComponent, uiToReactComponent } from './adapters'; export { useUrlTracker } from './use_url_tracker'; diff --git a/src/legacy/ui/public/validated_range/index.js b/src/plugins/kibana_react/public/validated_range/index.ts similarity index 100% rename from src/legacy/ui/public/validated_range/index.js rename to src/plugins/kibana_react/public/validated_range/index.ts diff --git a/src/legacy/ui/public/validated_range/is_range_valid.test.js b/src/plugins/kibana_react/public/validated_range/is_range_valid.test.ts similarity index 100% rename from src/legacy/ui/public/validated_range/is_range_valid.test.js rename to src/plugins/kibana_react/public/validated_range/is_range_valid.test.ts diff --git a/src/legacy/ui/public/validated_range/is_range_valid.js b/src/plugins/kibana_react/public/validated_range/is_range_valid.ts similarity index 74% rename from src/legacy/ui/public/validated_range/is_range_valid.js rename to src/plugins/kibana_react/public/validated_range/is_range_valid.ts index 9b733815a66ba8..1f822c0cb94b96 100644 --- a/src/legacy/ui/public/validated_range/is_range_valid.js +++ b/src/plugins/kibana_react/public/validated_range/is_range_valid.ts @@ -18,14 +18,24 @@ */ import { i18n } from '@kbn/i18n'; +import { ValueMember, Value } from './validated_dual_range'; const LOWER_VALUE_INDEX = 0; const UPPER_VALUE_INDEX = 1; -export function isRangeValid(value, min, max, allowEmptyRange) { - allowEmptyRange = typeof allowEmptyRange === 'boolean' ? allowEmptyRange : true; //cannot use default props since that uses falsy check - let lowerValue = isNaN(value[LOWER_VALUE_INDEX]) ? '' : value[LOWER_VALUE_INDEX]; - let upperValue = isNaN(value[UPPER_VALUE_INDEX]) ? '' : value[UPPER_VALUE_INDEX]; +export function isRangeValid( + value: Value = [0, 0], + min: ValueMember = 0, + max: ValueMember = 0, + allowEmptyRange?: boolean +) { + allowEmptyRange = typeof allowEmptyRange === 'boolean' ? allowEmptyRange : true; // cannot use default props since that uses falsy check + let lowerValue: ValueMember = isNaN(value[LOWER_VALUE_INDEX] as number) + ? '' + : `${value[LOWER_VALUE_INDEX]}`; + let upperValue: ValueMember = isNaN(value[UPPER_VALUE_INDEX] as number) + ? '' + : `${value[UPPER_VALUE_INDEX]}`; const isLowerValueValid = lowerValue.toString() !== ''; const isUpperValueValid = upperValue.toString() !== ''; @@ -39,7 +49,7 @@ export function isRangeValid(value, min, max, allowEmptyRange) { let errorMessage = ''; const bothMustBeSetErrorMessage = i18n.translate( - 'common.ui.dualRangeControl.mustSetBothErrorMessage', + 'kibana-react.dualRangeControl.mustSetBothErrorMessage', { defaultMessage: 'Both lower and upper values must be set', } @@ -55,13 +65,13 @@ export function isRangeValid(value, min, max, allowEmptyRange) { errorMessage = bothMustBeSetErrorMessage; } else if ((isLowerValueValid && lowerValue < min) || (isUpperValueValid && upperValue > max)) { isValid = false; - errorMessage = i18n.translate('common.ui.dualRangeControl.outsideOfRangeErrorMessage', { + errorMessage = i18n.translate('kibana-react.dualRangeControl.outsideOfRangeErrorMessage', { defaultMessage: 'Values must be on or between {min} and {max}', values: { min, max }, }); } else if (isLowerValueValid && isUpperValueValid && upperValue < lowerValue) { isValid = false; - errorMessage = i18n.translate('common.ui.dualRangeControl.upperValidErrorMessage', { + errorMessage = i18n.translate('kibana-react.dualRangeControl.upperValidErrorMessage', { defaultMessage: 'Upper value must be greater or equal to lower value', }); } diff --git a/src/legacy/ui/public/validated_range/validated_dual_range.js b/src/plugins/kibana_react/public/validated_range/validated_dual_range.tsx similarity index 67% rename from src/legacy/ui/public/validated_range/validated_dual_range.js rename to src/plugins/kibana_react/public/validated_range/validated_dual_range.tsx index 3b0efba11afccc..e7392eeba3830f 100644 --- a/src/legacy/ui/public/validated_range/validated_dual_range.js +++ b/src/plugins/kibana_react/public/validated_range/validated_dual_range.tsx @@ -18,17 +18,38 @@ */ import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { isRangeValid } from './is_range_valid'; - import { EuiFormRow, EuiDualRange } from '@elastic/eui'; +import { EuiFormRowDisplayKeys } from '@elastic/eui/src/components/form/form_row/form_row'; +import { EuiDualRangeProps } from '@elastic/eui/src/components/form/range/dual_range'; +import { isRangeValid } from './is_range_valid'; // Wrapper around EuiDualRange that ensures onChange callback is only called when range value // is valid and within min/max -export class ValidatedDualRange extends Component { - state = {}; - static getDerivedStateFromProps(nextProps, prevState) { +export type Value = EuiDualRangeProps['value']; +export type ValueMember = EuiDualRangeProps['value'][0]; + +interface Props extends Omit { + value?: Value; + allowEmptyRange?: boolean; + label?: string; + formRowDisplay?: EuiFormRowDisplayKeys; + onChange?: (val: [string, string]) => void; + min?: ValueMember; + max?: ValueMember; +} + +interface State { + isValid?: boolean; + errorMessage?: string; + value: [ValueMember, ValueMember]; + prevValue?: Value; +} + +export class ValidatedDualRange extends Component { + static defaultProps: { fullWidth: boolean; allowEmptyRange: boolean; compressed: boolean }; + + static getDerivedStateFromProps(nextProps: Props, prevState: State) { if (nextProps.value !== prevState.prevValue) { const { isValid, errorMessage } = isRangeValid( nextProps.value, @@ -47,7 +68,10 @@ export class ValidatedDualRange extends Component { return null; } - _onChange = value => { + // @ts-ignore state populated by getDerivedStateFromProps + state: State = {}; + + _onChange = (value: Value) => { const { isValid, errorMessage } = isRangeValid( value, this.props.min, @@ -61,8 +85,8 @@ export class ValidatedDualRange extends Component { errorMessage, }); - if (isValid) { - this.props.onChange(value); + if (this.props.onChange && isValid) { + this.props.onChange([value[0] as string, value[1] as string]); } }; @@ -75,7 +99,8 @@ export class ValidatedDualRange extends Component { value, // eslint-disable-line no-unused-vars onChange, // eslint-disable-line no-unused-vars allowEmptyRange, // eslint-disable-line no-unused-vars - ...rest + // @ts-ignore + ...rest // TODO: Consider alternatives for spread operator in component } = this.props; return ( @@ -92,6 +117,7 @@ export class ValidatedDualRange extends Component { fullWidth={fullWidth} value={this.state.value} onChange={this._onChange} + // @ts-ignore focusable={false} // remove when #59039 is fixed {...rest} /> @@ -100,14 +126,6 @@ export class ValidatedDualRange extends Component { } } -ValidatedDualRange.propTypes = { - allowEmptyRange: PropTypes.bool, - fullWidth: PropTypes.bool, - compressed: PropTypes.bool, - label: PropTypes.node, - formRowDisplay: PropTypes.string, -}; - ValidatedDualRange.defaultProps = { allowEmptyRange: true, fullWidth: false, diff --git a/src/plugins/kibana_utils/public/index.ts b/src/plugins/kibana_utils/public/index.ts index 6971d96e471bdb..ee38d5e8111c92 100644 --- a/src/plugins/kibana_utils/public/index.ts +++ b/src/plugins/kibana_utils/public/index.ts @@ -18,18 +18,19 @@ */ export { + calculateObjectHash, + createGetterSetter, defer, Defer, - of, - createGetterSetter, Get, + JsonArray, + JsonObject, + JsonValue, + of, Set, UiComponent, UiComponentInstance, url, - JsonValue, - JsonObject, - JsonArray, } from '../common'; export * from './core'; export * from './errors'; diff --git a/src/plugins/ui_actions/public/index.ts b/src/plugins/ui_actions/public/index.ts index 79b8e1474f6c20..49b6bd5e176995 100644 --- a/src/plugins/ui_actions/public/index.ts +++ b/src/plugins/ui_actions/public/index.ts @@ -28,6 +28,15 @@ export { UiActionsSetup, UiActionsStart } from './plugin'; export { UiActionsServiceParams, UiActionsService } from './service'; export { Action, createAction, IncompatibleActionError } from './actions'; export { buildContextMenuForActions } from './context_menu'; -export { Trigger, TriggerContext } from './triggers'; +export { + Trigger, + TriggerContext, + SELECT_RANGE_TRIGGER, + selectRangeTrigger, + VALUE_CLICK_TRIGGER, + valueClickTrigger, + APPLY_FILTER_TRIGGER, + applyFilterTrigger, +} from './triggers'; export { TriggerContextMapping, TriggerId, ActionContextMapping, ActionType } from './types'; export { ActionByType } from './actions'; diff --git a/src/plugins/ui_actions/public/plugin.ts b/src/plugins/ui_actions/public/plugin.ts index 0874803db7d373..928e57937a9b5a 100644 --- a/src/plugins/ui_actions/public/plugin.ts +++ b/src/plugins/ui_actions/public/plugin.ts @@ -19,6 +19,7 @@ import { CoreStart, CoreSetup, Plugin, PluginInitializerContext } from 'src/core/public'; import { UiActionsService } from './service'; +import { selectRangeTrigger, valueClickTrigger, applyFilterTrigger } from './triggers'; export type UiActionsSetup = Pick< UiActionsService, @@ -33,6 +34,9 @@ export class UiActionsPlugin implements Plugin { constructor(initializerContext: PluginInitializerContext) {} public setup(core: CoreSetup): UiActionsSetup { + this.service.registerTrigger(selectRangeTrigger); + this.service.registerTrigger(valueClickTrigger); + this.service.registerTrigger(applyFilterTrigger); return this.service; } diff --git a/src/legacy/ui/public/validated_range/index.d.ts b/src/plugins/ui_actions/public/triggers/apply_filter_trigger.ts similarity index 74% rename from src/legacy/ui/public/validated_range/index.d.ts rename to src/plugins/ui_actions/public/triggers/apply_filter_trigger.ts index 50cacbc517be8b..7a95709ac28ba5 100644 --- a/src/legacy/ui/public/validated_range/index.d.ts +++ b/src/plugins/ui_actions/public/triggers/apply_filter_trigger.ts @@ -17,9 +17,11 @@ * under the License. */ -import React from 'react'; -import { EuiRangeProps } from '@elastic/eui'; +import { Trigger } from '.'; -export class ValidatedDualRange extends React.Component { - allowEmptyRange?: boolean; -} +export const APPLY_FILTER_TRIGGER = 'FILTER_TRIGGER'; +export const applyFilterTrigger: Trigger<'FILTER_TRIGGER'> = { + id: APPLY_FILTER_TRIGGER, + title: 'Filter click', + description: 'Triggered when user applies filter to an embeddable.', +}; diff --git a/src/plugins/ui_actions/public/triggers/index.ts b/src/plugins/ui_actions/public/triggers/index.ts index 1ae2a19c4001f9..a5bf9e1822941d 100644 --- a/src/plugins/ui_actions/public/triggers/index.ts +++ b/src/plugins/ui_actions/public/triggers/index.ts @@ -20,3 +20,6 @@ export * from './trigger'; export * from './trigger_contract'; export * from './trigger_internal'; +export * from './select_range_trigger'; +export * from './value_click_trigger'; +export * from './apply_filter_trigger'; diff --git a/src/plugins/embeddable/public/api/get_embeddable_factories.ts b/src/plugins/ui_actions/public/triggers/select_range_trigger.ts similarity index 76% rename from src/plugins/embeddable/public/api/get_embeddable_factories.ts rename to src/plugins/ui_actions/public/triggers/select_range_trigger.ts index c12d1283905f5a..c638db0ce9dab8 100644 --- a/src/plugins/embeddable/public/api/get_embeddable_factories.ts +++ b/src/plugins/ui_actions/public/triggers/select_range_trigger.ts @@ -17,10 +17,11 @@ * under the License. */ -import { EmbeddableApiPure } from './types'; +import { Trigger } from '.'; -export const getEmbeddableFactories: EmbeddableApiPure['getEmbeddableFactories'] = ({ - embeddableFactories, -}) => () => { - return embeddableFactories.values(); +export const SELECT_RANGE_TRIGGER = 'SELECT_RANGE_TRIGGER'; +export const selectRangeTrigger: Trigger<'SELECT_RANGE_TRIGGER'> = { + id: SELECT_RANGE_TRIGGER, + title: 'Select range', + description: 'Applies a range filter', }; diff --git a/src/plugins/embeddable/public/api/tests/helpers.ts b/src/plugins/ui_actions/public/triggers/value_click_trigger.ts similarity index 76% rename from src/plugins/embeddable/public/api/tests/helpers.ts rename to src/plugins/ui_actions/public/triggers/value_click_trigger.ts index be8e9a0dec3c27..ad32bdc1b564e1 100644 --- a/src/plugins/embeddable/public/api/tests/helpers.ts +++ b/src/plugins/ui_actions/public/triggers/value_click_trigger.ts @@ -17,11 +17,11 @@ * under the License. */ -import { EmbeddableDependencies } from '../types'; +import { Trigger } from '.'; -export const createDeps = (): EmbeddableDependencies => { - const deps: EmbeddableDependencies = { - embeddableFactories: new Map(), - }; - return deps; +export const VALUE_CLICK_TRIGGER = 'VALUE_CLICK_TRIGGER'; +export const valueClickTrigger: Trigger<'VALUE_CLICK_TRIGGER'> = { + id: VALUE_CLICK_TRIGGER, + title: 'Value clicked', + description: 'Value was clicked', }; diff --git a/src/plugins/ui_actions/public/types.ts b/src/plugins/ui_actions/public/types.ts index d443ce0e592cb9..c7e6d61e15f317 100644 --- a/src/plugins/ui_actions/public/types.ts +++ b/src/plugins/ui_actions/public/types.ts @@ -19,6 +19,9 @@ import { ActionByType } from './actions/action'; import { TriggerInternal } from './triggers/trigger_internal'; +import { EmbeddableVisTriggerContext, IEmbeddable } from '../../embeddable/public'; +import { Filter } from '../../data/public'; +import { SELECT_RANGE_TRIGGER, VALUE_CLICK_TRIGGER, APPLY_FILTER_TRIGGER } from './triggers'; export type TriggerRegistry = Map>; export type ActionRegistry = Map>; @@ -33,6 +36,12 @@ export type TriggerContext = BaseContext; export interface TriggerContextMapping { [DEFAULT_TRIGGER]: TriggerContext; + [SELECT_RANGE_TRIGGER]: EmbeddableVisTriggerContext; + [VALUE_CLICK_TRIGGER]: EmbeddableVisTriggerContext; + [APPLY_FILTER_TRIGGER]: { + embeddable: IEmbeddable; + filters: Filter[]; + }; } const DEFAULT_ACTION = ''; diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/date_histogram.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/date_histogram.js index 995790c590e424..283f2c115d4f55 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/date_histogram.js +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/annotations/date_histogram.js @@ -18,9 +18,10 @@ */ import _ from 'lodash'; -import { dateHistogramInterval } from '../../../../../../../legacy/core_plugins/data/server'; import { getBucketSize } from '../../helpers/get_bucket_size'; import { getTimerange } from '../../helpers/get_timerange'; +import { search } from '../../../../../../../plugins/data/server'; +const { dateHistogramInterval } = search.aggs; export function dateHistogram( req, diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/date_histogram.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/date_histogram.js index 48da5ac19aa3ae..df63a14ea5ee45 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/date_histogram.js +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/series/date_histogram.js @@ -18,11 +18,12 @@ */ import { set } from 'lodash'; -import { dateHistogramInterval } from '../../../../../../../legacy/core_plugins/data/server'; import { getBucketSize } from '../../helpers/get_bucket_size'; import { offsetTime } from '../../offset_time'; import { getIntervalAndTimefield } from '../../get_interval_and_timefield'; import { isLastValueTimerangeMode } from '../../helpers/get_timerange_mode'; +import { search } from '../../../../../../../plugins/data/server'; +const { dateHistogramInterval } = search.aggs; export function dateHistogram(req, panel, series, esQueryConfig, indexPatternObject, capabilities) { return next => doc => { diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/date_histogram.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/date_histogram.js index f33ce145aa2309..6afa434a550854 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/date_histogram.js +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/request_processors/table/date_histogram.js @@ -18,12 +18,13 @@ */ import { set } from 'lodash'; -import { dateHistogramInterval } from '../../../../../../../legacy/core_plugins/data/server'; import { getBucketSize } from '../../helpers/get_bucket_size'; import { isLastValueTimerangeMode } from '../../helpers/get_timerange_mode'; import { getIntervalAndTimefield } from '../../get_interval_and_timefield'; import { getTimerange } from '../../helpers/get_timerange'; import { calculateAggRoot } from './calculate_agg_root'; +import { search } from '../../../../../../../plugins/data/server'; +const { dateHistogramInterval } = search.aggs; export function dateHistogram(req, panel, esQueryConfig, indexPatternObject, capabilities) { return next => doc => { diff --git a/src/plugins/visualizations/kibana.json b/src/plugins/visualizations/kibana.json index cf79ce17293d61..8e63ea78333270 100644 --- a/src/plugins/visualizations/kibana.json +++ b/src/plugins/visualizations/kibana.json @@ -1,7 +1,7 @@ { "id": "visualizations", "version": "kibana", - "server": false, + "server": true, "ui": true, "requiredPlugins": [ "expressions" diff --git a/src/plugins/embeddable/public/api/get_embeddable_factory.ts b/src/plugins/visualizations/server/index.ts similarity index 65% rename from src/plugins/embeddable/public/api/get_embeddable_factory.ts rename to src/plugins/visualizations/server/index.ts index 8e98da287c5ea6..80c10c3945d4c7 100644 --- a/src/plugins/embeddable/public/api/get_embeddable_factory.ts +++ b/src/plugins/visualizations/server/index.ts @@ -17,18 +17,14 @@ * under the License. */ -import { EmbeddableApiPure } from './types'; +import { PluginInitializerContext } from '../../../core/server'; +import { VisualizationsPlugin } from './plugin'; -export const getEmbeddableFactory: EmbeddableApiPure['getEmbeddableFactory'] = ({ - embeddableFactories, -}) => embeddableFactoryId => { - const factory = embeddableFactories.get(embeddableFactoryId); +// This exports static code and TypeScript types, +// as well as, Kibana Platform `plugin()` initializer. - if (!factory) { - throw new Error( - `Embeddable factory [embeddableFactoryId = ${embeddableFactoryId}] does not exist.` - ); - } +export function plugin(initializerContext: PluginInitializerContext) { + return new VisualizationsPlugin(initializerContext); +} - return factory; -}; +export { VisualizationsPluginSetup, VisualizationsPluginStart } from './types'; diff --git a/src/plugins/visualizations/server/plugin.ts b/src/plugins/visualizations/server/plugin.ts new file mode 100644 index 00000000000000..79cce6b5867a1a --- /dev/null +++ b/src/plugins/visualizations/server/plugin.ts @@ -0,0 +1,54 @@ +/* + * 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 { + PluginInitializerContext, + CoreSetup, + CoreStart, + Plugin, + Logger, +} from '../../../core/server'; + +import { visualizationSavedObjectType } from './saved_objects'; + +import { VisualizationsPluginSetup, VisualizationsPluginStart } from './types'; + +export class VisualizationsPlugin + implements Plugin { + private readonly logger: Logger; + + constructor(initializerContext: PluginInitializerContext) { + this.logger = initializerContext.logger.get(); + } + + public setup(core: CoreSetup) { + this.logger.debug('visualizations: Setup'); + + core.savedObjects.registerType(visualizationSavedObjectType); + + return {}; + } + + public start(core: CoreStart) { + this.logger.debug('visualizations: Started'); + return {}; + } + + public stop() {} +} diff --git a/src/legacy/core_plugins/data/public/search/types.ts b/src/plugins/visualizations/server/saved_objects/index.ts similarity index 92% rename from src/legacy/core_plugins/data/public/search/types.ts rename to src/plugins/visualizations/server/saved_objects/index.ts index 47ea1d168f379f..be75f635824500 100644 --- a/src/legacy/core_plugins/data/public/search/types.ts +++ b/src/plugins/visualizations/server/saved_objects/index.ts @@ -17,5 +17,4 @@ * under the License. */ -export * from './aggs/types'; -export * from './utils/types'; +export { visualizationSavedObjectType } from './visualization'; diff --git a/src/plugins/visualizations/server/saved_objects/visualization.ts b/src/plugins/visualizations/server/saved_objects/visualization.ts new file mode 100644 index 00000000000000..9f4782f3ec7308 --- /dev/null +++ b/src/plugins/visualizations/server/saved_objects/visualization.ts @@ -0,0 +1,56 @@ +/* + * 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 { SavedObjectsType } from 'kibana/server'; +import { visualizationSavedObjectTypeMigrations } from './visualization_migrations'; + +export const visualizationSavedObjectType: SavedObjectsType = { + name: 'visualization', + hidden: false, + namespaceAgnostic: false, + management: { + icon: 'visualizeApp', + defaultSearchField: 'title', + importableAndExportable: true, + getTitle(obj) { + return obj.attributes.title; + }, + getEditUrl(obj) { + return `/management/kibana/objects/savedVisualizations/${encodeURIComponent(obj.id)}`; + }, + getInAppUrl(obj) { + return { + path: `/app/kibana#/visualize/edit/${encodeURIComponent(obj.id)}`, + uiCapabilitiesPath: 'visualize.show', + }; + }, + }, + mappings: { + properties: { + description: { type: 'text' }, + kibanaSavedObjectMeta: { properties: { searchSourceJSON: { type: 'text' } } }, + savedSearchRefName: { type: 'keyword' }, + title: { type: 'text' }, + uiStateJSON: { type: 'text' }, + version: { type: 'integer' }, + visState: { type: 'text' }, + }, + }, + migrations: visualizationSavedObjectTypeMigrations, +}; diff --git a/src/plugins/visualizations/server/saved_objects/visualization_migrations.test.ts b/src/plugins/visualizations/server/saved_objects/visualization_migrations.test.ts new file mode 100644 index 00000000000000..02c114bad4e725 --- /dev/null +++ b/src/plugins/visualizations/server/saved_objects/visualization_migrations.test.ts @@ -0,0 +1,1356 @@ +/* + * 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 { visualizationSavedObjectTypeMigrations } from './visualization_migrations'; +import { SavedObjectMigrationContext, SavedObjectMigrationFn } from 'kibana/server'; + +const savedObjectMigrationContext = (null as unknown) as SavedObjectMigrationContext; + +describe('migration visualization', () => { + describe('6.7.2', () => { + const migrate = (doc: any) => + visualizationSavedObjectTypeMigrations['6.7.2']( + doc as Parameters[0], + savedObjectMigrationContext + ); + let doc: any; + + describe('date histogram time zone removal', () => { + beforeEach(() => { + doc = { + attributes: { + visState: JSON.stringify({ + aggs: [ + { + enabled: true, + id: '1', + params: { + // Doesn't make much sense but we want to test it's not removing it from anything else + time_zone: 'Europe/Berlin', + }, + schema: 'metric', + type: 'count', + }, + { + enabled: true, + id: '2', + params: { + customInterval: '2h', + drop_partials: false, + extended_bounds: {}, + field: 'timestamp', + time_zone: 'Europe/Berlin', + interval: 'auto', + min_doc_count: 1, + useNormalizedEsInterval: true, + }, + schema: 'segment', + type: 'date_histogram', + }, + { + enabled: true, + id: '4', + params: { + customInterval: '2h', + drop_partials: false, + extended_bounds: {}, + field: 'timestamp', + interval: 'auto', + min_doc_count: 1, + useNormalizedEsInterval: true, + }, + schema: 'segment', + type: 'date_histogram', + }, + { + enabled: true, + id: '3', + params: { + customBucket: { + enabled: true, + id: '1-bucket', + params: { + customInterval: '2h', + drop_partials: false, + extended_bounds: {}, + field: 'timestamp', + interval: 'auto', + min_doc_count: 1, + time_zone: 'Europe/Berlin', + useNormalizedEsInterval: true, + }, + type: 'date_histogram', + }, + customMetric: { + enabled: true, + id: '1-metric', + params: {}, + type: 'count', + }, + }, + schema: 'metric', + type: 'max_bucket', + }, + ], + }), + }, + } as Parameters[0]; + }); + + it('should remove time_zone from date_histogram aggregations', () => { + const migratedDoc = migrate(doc); + const aggs = JSON.parse(migratedDoc.attributes.visState).aggs; + + expect(aggs[1]).not.toHaveProperty('params.time_zone'); + }); + + it('should not remove time_zone from non date_histogram aggregations', () => { + const migratedDoc = migrate(doc); + const aggs = JSON.parse(migratedDoc.attributes.visState).aggs; + + expect(aggs[0]).toHaveProperty('params.time_zone'); + }); + + it('should remove time_zone from nested aggregations', () => { + const migratedDoc = migrate(doc); + const aggs = JSON.parse(migratedDoc.attributes.visState).aggs; + + expect(aggs[3]).not.toHaveProperty('params.customBucket.params.time_zone'); + }); + + it('should not fail on date histograms without a time_zone', () => { + const migratedDoc = migrate(doc); + const aggs = JSON.parse(migratedDoc.attributes.visState).aggs; + + expect(aggs[2]).not.toHaveProperty('params.time_zone'); + }); + + it('should be able to apply the migration twice, since we need it for 6.7.2 and 7.0.1', () => { + const migratedDoc = migrate(doc); + const aggs = JSON.parse(migratedDoc.attributes.visState).aggs; + + expect(aggs[1]).not.toHaveProperty('params.time_zone'); + expect(aggs[0]).toHaveProperty('params.time_zone'); + expect(aggs[3]).not.toHaveProperty('params.customBucket.params.time_zone'); + expect(aggs[2]).not.toHaveProperty('params.time_zone'); + }); + }); + }); + + describe('7.0.0', () => { + const migrate = (doc: any) => + visualizationSavedObjectTypeMigrations['7.0.0']( + doc as Parameters[0], + savedObjectMigrationContext + ); + + const generateDoc = (type: any, aggs: any) => ({ + attributes: { + title: 'My Vis', + description: 'This is my super cool vis.', + visState: JSON.stringify({ type, aggs }), + uiStateJSON: '{}', + version: 1, + kibanaSavedObjectMeta: { + searchSourceJSON: '{}', + }, + }, + references: [], + }); + + it('does not throw error on empty object', () => { + const migratedDoc = migrate({ + attributes: { + visState: '{}', + }, + }); + expect(migratedDoc).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "visState": "{}", + }, + "references": Array [], +} +`); + }); + + it('skips errors when searchSourceJSON is null', () => { + const doc = { + id: '1', + type: 'visualization', + attributes: { + visState: '{}', + kibanaSavedObjectMeta: { + searchSourceJSON: null, + }, + savedSearchId: '123', + }, + }; + const migratedDoc = migrate(doc); + + expect(migratedDoc).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "kibanaSavedObjectMeta": Object { + "searchSourceJSON": null, + }, + "savedSearchRefName": "search_0", + "visState": "{}", + }, + "id": "1", + "references": Array [ + Object { + "id": "123", + "name": "search_0", + "type": "search", + }, + ], + "type": "visualization", +} +`); + }); + + it('skips errors when searchSourceJSON is undefined', () => { + const doc = { + id: '1', + type: 'visualization', + attributes: { + visState: '{}', + kibanaSavedObjectMeta: { + searchSourceJSON: undefined, + }, + savedSearchId: '123', + }, + }; + const migratedDoc = migrate(doc); + + expect(migratedDoc).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "kibanaSavedObjectMeta": Object { + "searchSourceJSON": undefined, + }, + "savedSearchRefName": "search_0", + "visState": "{}", + }, + "id": "1", + "references": Array [ + Object { + "id": "123", + "name": "search_0", + "type": "search", + }, + ], + "type": "visualization", +} +`); + }); + + it('skips error when searchSourceJSON is not a string', () => { + const doc = { + id: '1', + type: 'visualization', + attributes: { + visState: '{}', + kibanaSavedObjectMeta: { + searchSourceJSON: 123, + }, + savedSearchId: '123', + }, + }; + + expect(migrate(doc)).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "kibanaSavedObjectMeta": Object { + "searchSourceJSON": 123, + }, + "savedSearchRefName": "search_0", + "visState": "{}", + }, + "id": "1", + "references": Array [ + Object { + "id": "123", + "name": "search_0", + "type": "search", + }, + ], + "type": "visualization", +} +`); + }); + + it('skips error when searchSourceJSON is invalid json', () => { + const doc = { + id: '1', + type: 'visualization', + attributes: { + visState: '{}', + kibanaSavedObjectMeta: { + searchSourceJSON: '{abc123}', + }, + savedSearchId: '123', + }, + }; + + expect(migrate(doc)).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "kibanaSavedObjectMeta": Object { + "searchSourceJSON": "{abc123}", + }, + "savedSearchRefName": "search_0", + "visState": "{}", + }, + "id": "1", + "references": Array [ + Object { + "id": "123", + "name": "search_0", + "type": "search", + }, + ], + "type": "visualization", +} +`); + }); + + it('skips error when "index" and "filter" is missing from searchSourceJSON', () => { + const doc = { + id: '1', + type: 'visualization', + attributes: { + visState: '{}', + kibanaSavedObjectMeta: { + searchSourceJSON: JSON.stringify({ bar: true }), + }, + savedSearchId: '123', + }, + }; + const migratedDoc = migrate(doc); + + expect(migratedDoc).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "kibanaSavedObjectMeta": Object { + "searchSourceJSON": "{\\"bar\\":true}", + }, + "savedSearchRefName": "search_0", + "visState": "{}", + }, + "id": "1", + "references": Array [ + Object { + "id": "123", + "name": "search_0", + "type": "search", + }, + ], + "type": "visualization", +} +`); + }); + + it('extracts "index" attribute from doc', () => { + const doc = { + id: '1', + type: 'visualization', + attributes: { + visState: '{}', + kibanaSavedObjectMeta: { + searchSourceJSON: JSON.stringify({ bar: true, index: 'pattern*' }), + }, + savedSearchId: '123', + }, + }; + const migratedDoc = migrate(doc); + + expect(migratedDoc).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "kibanaSavedObjectMeta": Object { + "searchSourceJSON": "{\\"bar\\":true,\\"indexRefName\\":\\"kibanaSavedObjectMeta.searchSourceJSON.index\\"}", + }, + "savedSearchRefName": "search_0", + "visState": "{}", + }, + "id": "1", + "references": Array [ + Object { + "id": "pattern*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern", + }, + Object { + "id": "123", + "name": "search_0", + "type": "search", + }, + ], + "type": "visualization", +} +`); + }); + + it('extracts index patterns from the filter', () => { + const doc = { + id: '1', + type: 'visualization', + attributes: { + visState: '{}', + kibanaSavedObjectMeta: { + searchSourceJSON: JSON.stringify({ + bar: true, + filter: [ + { + meta: { index: 'my-index', foo: true }, + }, + ], + }), + }, + savedSearchId: '123', + }, + }; + const migratedDoc = migrate(doc); + + expect(migratedDoc).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "kibanaSavedObjectMeta": Object { + "searchSourceJSON": "{\\"bar\\":true,\\"filter\\":[{\\"meta\\":{\\"foo\\":true,\\"indexRefName\\":\\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\\"}}]}", + }, + "savedSearchRefName": "search_0", + "visState": "{}", + }, + "id": "1", + "references": Array [ + Object { + "id": "my-index", + "name": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index", + "type": "index-pattern", + }, + Object { + "id": "123", + "name": "search_0", + "type": "search", + }, + ], + "type": "visualization", +} +`); + }); + + it('extracts index patterns from controls', () => { + const doc = { + id: '1', + type: 'visualization', + attributes: { + foo: true, + visState: JSON.stringify({ + bar: false, + params: { + controls: [ + { + bar: true, + indexPattern: 'pattern*', + }, + { + foo: true, + }, + ], + }, + }), + }, + }; + const migratedDoc = migrate(doc); + + expect(migratedDoc).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "foo": true, + "visState": "{\\"bar\\":false,\\"params\\":{\\"controls\\":[{\\"bar\\":true,\\"indexPatternRefName\\":\\"control_0_index_pattern\\"},{\\"foo\\":true}]}}", + }, + "id": "1", + "references": Array [ + Object { + "id": "pattern*", + "name": "control_0_index_pattern", + "type": "index-pattern", + }, + ], + "type": "visualization", +} +`); + }); + + it('skips extracting savedSearchId when missing', () => { + const doc = { + id: '1', + attributes: { + visState: '{}', + kibanaSavedObjectMeta: { + searchSourceJSON: '{}', + }, + }, + }; + const migratedDoc = migrate(doc); + + expect(migratedDoc).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "kibanaSavedObjectMeta": Object { + "searchSourceJSON": "{}", + }, + "visState": "{}", + }, + "id": "1", + "references": Array [], +} +`); + }); + + it('extract savedSearchId from doc', () => { + const doc = { + id: '1', + attributes: { + visState: '{}', + kibanaSavedObjectMeta: { + searchSourceJSON: '{}', + }, + savedSearchId: '123', + }, + }; + const migratedDoc = migrate(doc); + + expect(migratedDoc).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "kibanaSavedObjectMeta": Object { + "searchSourceJSON": "{}", + }, + "savedSearchRefName": "search_0", + "visState": "{}", + }, + "id": "1", + "references": Array [ + Object { + "id": "123", + "name": "search_0", + "type": "search", + }, + ], +} +`); + }); + + it('delete savedSearchId when empty string in doc', () => { + const doc = { + id: '1', + attributes: { + visState: '{}', + kibanaSavedObjectMeta: { + searchSourceJSON: '{}', + }, + savedSearchId: '', + }, + }; + const migratedDoc = migrate(doc); + + expect(migratedDoc).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "kibanaSavedObjectMeta": Object { + "searchSourceJSON": "{}", + }, + "visState": "{}", + }, + "id": "1", + "references": Array [], +} +`); + }); + + it('should return a new object if vis is table and has multiple split aggs', () => { + const aggs = [ + { + id: '1', + schema: 'metric', + params: {}, + }, + { + id: '2', + schema: 'split', + params: { foo: 'bar', row: true }, + }, + { + id: '3', + schema: 'split', + params: { hey: 'ya', row: false }, + }, + ]; + const tableDoc = generateDoc('table', aggs); + const expected = tableDoc; + const actual = migrate(tableDoc); + + expect(actual).not.toEqual(expected); + }); + + it('should not touch any vis that is not table', () => { + const pieDoc = generateDoc('pie', []); + const expected = pieDoc; + const actual = migrate(pieDoc); + + expect(actual).toEqual(expected); + }); + + it('should not change values in any vis that is not table', () => { + const aggs = [ + { + id: '1', + schema: 'metric', + params: {}, + }, + { + id: '2', + schema: 'split', + params: { foo: 'bar', row: true }, + }, + { + id: '3', + schema: 'segment', + params: { hey: 'ya' }, + }, + ]; + const pieDoc = generateDoc('pie', aggs); + const expected = pieDoc; + const actual = migrate(pieDoc); + + expect(actual).toEqual(expected); + }); + + it('should not touch table vis if there are not multiple split aggs', () => { + const aggs = [ + { + id: '1', + schema: 'metric', + params: {}, + }, + { + id: '2', + schema: 'split', + params: { foo: 'bar', row: true }, + }, + ]; + const tableDoc = generateDoc('table', aggs); + const expected = tableDoc; + const actual = migrate(tableDoc); + + expect(actual).toEqual(expected); + }); + + it('should change all split aggs to `bucket` except the first', () => { + const aggs = [ + { + id: '1', + schema: 'metric', + params: {}, + }, + { + id: '2', + schema: 'split', + params: { foo: 'bar', row: true }, + }, + { + id: '3', + schema: 'split', + params: { hey: 'ya', row: false }, + }, + { + id: '4', + schema: 'bucket', + params: { heyyy: 'yaaa' }, + }, + ]; + const expected = ['metric', 'split', 'bucket', 'bucket']; + const migrated = migrate(generateDoc('table', aggs)); + const actual = JSON.parse(migrated.attributes.visState); + + expect(actual.aggs.map((agg: any) => agg.schema)).toEqual(expected); + }); + + it('should remove `rows` param from any aggs that are not `split`', () => { + const aggs = [ + { + id: '1', + schema: 'metric', + params: {}, + }, + { + id: '2', + schema: 'split', + params: { foo: 'bar', row: true }, + }, + { + id: '3', + schema: 'split', + params: { hey: 'ya', row: false }, + }, + ]; + const expected = [{}, { foo: 'bar', row: true }, { hey: 'ya' }]; + const migrated = migrate(generateDoc('table', aggs)); + const actual = JSON.parse(migrated.attributes.visState); + + expect(actual.aggs.map((agg: any) => agg.params)).toEqual(expected); + }); + + it('should throw with a reference to the doc name if something goes wrong', () => { + const doc = { + attributes: { + title: 'My Vis', + description: 'This is my super cool vis.', + visState: '!/// Intentionally malformed JSON ///!', + uiStateJSON: '{}', + version: 1, + kibanaSavedObjectMeta: { + searchSourceJSON: '{}', + }, + }, + }; + expect(() => migrate(doc)).toThrowError(/My Vis/); + }); + }); + + describe('7.2.0', () => { + describe('date histogram custom interval removal', () => { + const migrate = (doc: any) => + visualizationSavedObjectTypeMigrations['7.2.0']( + doc as Parameters[0], + savedObjectMigrationContext + ); + let doc: any; + + beforeEach(() => { + doc = { + attributes: { + visState: JSON.stringify({ + aggs: [ + { + enabled: true, + id: '1', + params: { + customInterval: '1h', + }, + schema: 'metric', + type: 'count', + }, + { + enabled: true, + id: '2', + params: { + customInterval: '2h', + drop_partials: false, + extended_bounds: {}, + field: 'timestamp', + interval: 'auto', + min_doc_count: 1, + useNormalizedEsInterval: true, + }, + schema: 'segment', + type: 'date_histogram', + }, + { + enabled: true, + id: '4', + params: { + customInterval: '2h', + drop_partials: false, + extended_bounds: {}, + field: 'timestamp', + interval: 'custom', + min_doc_count: 1, + useNormalizedEsInterval: true, + }, + schema: 'segment', + type: 'date_histogram', + }, + { + enabled: true, + id: '3', + params: { + customBucket: { + enabled: true, + id: '1-bucket', + params: { + customInterval: '2h', + drop_partials: false, + extended_bounds: {}, + field: 'timestamp', + interval: 'custom', + min_doc_count: 1, + useNormalizedEsInterval: true, + }, + type: 'date_histogram', + }, + customMetric: { + enabled: true, + id: '1-metric', + params: {}, + type: 'count', + }, + }, + schema: 'metric', + type: 'max_bucket', + }, + ], + }), + }, + }; + }); + + it('should remove customInterval from date_histogram aggregations', () => { + const migratedDoc = migrate(doc); + const { aggs } = JSON.parse(migratedDoc.attributes.visState); + + expect(aggs[1]).not.toHaveProperty('params.customInterval'); + }); + + it('should not change interval from date_histogram aggregations', () => { + const migratedDoc = migrate(doc); + const { aggs } = JSON.parse(migratedDoc.attributes.visState); + + expect(aggs[1].params.interval).toBe( + JSON.parse(doc.attributes.visState).aggs[1].params.interval + ); + }); + + it('should not remove customInterval from non date_histogram aggregations', () => { + const migratedDoc = migrate(doc); + const { aggs } = JSON.parse(migratedDoc.attributes.visState); + + expect(aggs[0]).toHaveProperty('params.customInterval'); + }); + + it('should set interval with customInterval value and remove customInterval when interval equals "custom"', () => { + const migratedDoc = migrate(doc); + const { aggs } = JSON.parse(migratedDoc.attributes.visState); + + expect(aggs[2].params.interval).toBe( + JSON.parse(doc.attributes.visState).aggs[2].params.customInterval + ); + expect(aggs[2]).not.toHaveProperty('params.customInterval'); + }); + + it('should remove customInterval from nested aggregations', () => { + const migratedDoc = migrate(doc); + const { aggs } = JSON.parse(migratedDoc.attributes.visState); + + expect(aggs[3]).not.toHaveProperty('params.customBucket.params.customInterval'); + }); + + it('should remove customInterval from nested aggregations and set interval with customInterval value', () => { + const migratedDoc = migrate(doc); + const { aggs } = JSON.parse(migratedDoc.attributes.visState); + + expect(aggs[3].params.customBucket.params.interval).toBe( + JSON.parse(doc.attributes.visState).aggs[3].params.customBucket.params.customInterval + ); + expect(aggs[3]).not.toHaveProperty('params.customBucket.params.customInterval'); + }); + + it('should not fail on date histograms without a customInterval', () => { + const migratedDoc = migrate(doc); + const { aggs } = JSON.parse(migratedDoc.attributes.visState); + + expect(aggs[3]).not.toHaveProperty('params.customInterval'); + }); + }); + }); + + describe('7.3.0', () => { + const logMsgArr: string[] = []; + const logger = ({ + log: { + warn: (msg: string) => logMsgArr.push(msg), + }, + } as unknown) as SavedObjectMigrationContext; + + const migrate = (doc: any) => + visualizationSavedObjectTypeMigrations['7.3.0']( + doc as Parameters[0], + logger + ); + + it('migrates type = gauge verticalSplit: false to alignment: vertical', () => { + const migratedDoc = migrate({ + attributes: { + visState: JSON.stringify({ type: 'gauge', params: { gauge: { verticalSplit: false } } }), + }, + }); + expect(migratedDoc).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "visState": "{\\"type\\":\\"gauge\\",\\"params\\":{\\"gauge\\":{\\"alignment\\":\\"horizontal\\"}}}", + }, +} +`); + }); + + it('migrates type = gauge verticalSplit: false to alignment: horizontal', () => { + const migratedDoc = migrate({ + attributes: { + visState: JSON.stringify({ type: 'gauge', params: { gauge: { verticalSplit: true } } }), + }, + }); + + expect(migratedDoc).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "visState": "{\\"type\\":\\"gauge\\",\\"params\\":{\\"gauge\\":{\\"alignment\\":\\"vertical\\"}}}", + }, +} +`); + }); + + it('doesnt migrate type = gauge containing invalid visState object, adds message to log', () => { + const migratedDoc = migrate({ + attributes: { + visState: JSON.stringify({ type: 'gauge' }), + }, + }); + + expect(migratedDoc).toMatchInlineSnapshot(` +Object { + "attributes": Object { + "visState": "{\\"type\\":\\"gauge\\"}", + }, +} +`); + expect(logMsgArr).toMatchInlineSnapshot(` +Array [ + "Exception @ migrateGaugeVerticalSplitToAlignment! TypeError: Cannot read property 'gauge' of undefined", + "Exception @ migrateGaugeVerticalSplitToAlignment! Payload: {\\"type\\":\\"gauge\\"}", +] +`); + }); + + describe('filters agg query migration', () => { + const doc = { + attributes: { + visState: JSON.stringify({ + aggs: [ + { + type: 'filters', + params: { + filters: [ + { + input: { + query: 'response:200', + }, + label: '', + }, + { + input: { + query: 'response:404', + }, + label: 'bad response', + }, + { + input: { + query: { + exists: { + field: 'phpmemory', + }, + }, + }, + label: '', + }, + ], + }, + }, + ], + }), + }, + }; + + it('should add language property to filters without one, assuming lucene', () => { + const migrationResult = migrate(doc); + + expect(migrationResult).toEqual({ + attributes: { + visState: JSON.stringify({ + aggs: [ + { + type: 'filters', + params: { + filters: [ + { + input: { + query: 'response:200', + language: 'lucene', + }, + label: '', + }, + { + input: { + query: 'response:404', + language: 'lucene', + }, + label: 'bad response', + }, + { + input: { + query: { + exists: { + field: 'phpmemory', + }, + }, + language: 'lucene', + }, + label: '', + }, + ], + }, + }, + ], + }), + }, + }); + }); + }); + + describe('replaceMovAvgToMovFn()', () => { + let doc: any; + + beforeEach(() => { + doc = { + attributes: { + title: 'VIS', + visState: `{"title":"VIS","type":"metrics","params":{"id":"61ca57f0-469d-11e7-af02-69e470af7417", + "type":"timeseries","series":[{"id":"61ca57f1-469d-11e7-af02-69e470af7417","color":"rgba(0,156,224,1)", + "split_mode":"terms","metrics":[{"id":"61ca57f2-469d-11e7-af02-69e470af7417","type":"count", + "numerator":"FlightDelay:true"},{"settings":"","minimize":0,"window":5,"model": + "holt_winters","id":"23054fe0-8915-11e9-9b86-d3f94982620f","type":"moving_average","field": + "61ca57f2-469d-11e7-af02-69e470af7417","predict":1}],"separate_axis":0,"axis_position":"right", + "formatter":"number","chart_type":"line","line_width":"2","point_size":"0","fill":0.5,"stacked":"none", + "label":"Percent Delays","terms_size":"2","terms_field":"OriginCityName"}],"time_field":"timestamp", + "index_pattern":"kibana_sample_data_flights","interval":">=12h","axis_position":"left","axis_formatter": + "number","show_legend":1,"show_grid":1,"annotations":[{"fields":"FlightDelay,Cancelled,Carrier", + "template":"{{Carrier}}: Flight Delayed and Cancelled!","index_pattern":"kibana_sample_data_flights", + "query_string":"FlightDelay:true AND Cancelled:true","id":"53b7dff0-4c89-11e8-a66a-6989ad5a0a39", + "color":"rgba(0,98,177,1)","time_field":"timestamp","icon":"fa-exclamation-triangle", + "ignore_global_filters":1,"ignore_panel_filters":1,"hidden":true}],"legend_position":"bottom", + "axis_scale":"normal","default_index_pattern":"kibana_sample_data_flights","default_timefield":"timestamp"}, + "aggs":[]}`, + }, + migrationVersion: { + visualization: '7.2.0', + }, + type: 'visualization', + }; + }); + + test('should add some necessary moving_fn fields', () => { + const migratedDoc = migrate(doc); + const visState = JSON.parse(migratedDoc.attributes.visState); + const metric = visState.params.series[0].metrics[1]; + + expect(metric).toHaveProperty('model_type'); + expect(metric).toHaveProperty('alpha'); + expect(metric).toHaveProperty('beta'); + expect(metric).toHaveProperty('gamma'); + expect(metric).toHaveProperty('period'); + expect(metric).toHaveProperty('multiplicative'); + }); + }); + }); + + describe('7.3.0 tsvb', () => { + const migrate = (doc: any) => + visualizationSavedObjectTypeMigrations['7.3.0']( + doc as Parameters[0], + savedObjectMigrationContext + ); + + const generateDoc = (params: any) => ({ + attributes: { + title: 'My Vis', + description: 'This is my super cool vis.', + visState: JSON.stringify({ params }), + uiStateJSON: '{}', + version: 1, + kibanaSavedObjectMeta: { + searchSourceJSON: '{}', + }, + }, + }); + it('should change series item filters from a string into an object', () => { + const params = { type: 'metric', series: [{ filter: 'Filter Bytes Test:>1000' }] }; + const testDoc1 = generateDoc(params); + const migratedTestDoc1 = migrate(testDoc1); + const series = JSON.parse(migratedTestDoc1.attributes.visState).params.series; + + expect(series[0].filter).toHaveProperty('query'); + expect(series[0].filter).toHaveProperty('language'); + }); + it('should not change a series item filter string in the object after migration', () => { + const markdownParams = { + type: 'markdown', + series: [ + { + filter: 'Filter Bytes Test:>1000', + split_filters: [{ filter: 'bytes:>1000' }], + }, + ], + }; + const markdownDoc = generateDoc(markdownParams); + const migratedMarkdownDoc = migrate(markdownDoc); + const markdownSeries = JSON.parse(migratedMarkdownDoc.attributes.visState).params.series; + + expect(markdownSeries[0].filter.query).toBe( + JSON.parse(markdownDoc.attributes.visState).params.series[0].filter + ); + expect(markdownSeries[0].split_filters[0].filter.query).toBe( + JSON.parse(markdownDoc.attributes.visState).params.series[0].split_filters[0].filter + ); + }); + + it('should change series item filters from a string into an object for all filters', () => { + const params = { + type: 'timeseries', + filter: 'bytes:>1000', + series: [ + { + filter: 'Filter Bytes Test:>1000', + split_filters: [{ filter: 'bytes:>1000' }], + }, + ], + annotations: [{ query_string: 'bytes:>1000' }], + }; + const timeSeriesDoc = generateDoc(params); + const migratedtimeSeriesDoc = migrate(timeSeriesDoc); + const timeSeriesParams = JSON.parse(migratedtimeSeriesDoc.attributes.visState).params; + + expect(Object.keys(timeSeriesParams.series[0].filter)).toEqual( + expect.arrayContaining(['query', 'language']) + ); + expect(Object.keys(timeSeriesParams.series[0].split_filters[0].filter)).toEqual( + expect.arrayContaining(['query', 'language']) + ); + expect(Object.keys(timeSeriesParams.annotations[0].query_string)).toEqual( + expect.arrayContaining(['query', 'language']) + ); + }); + + it('should not fail on a metric visualization without a filter in a series item', () => { + const params = { type: 'metric', series: [{}, {}, {}] }; + const testDoc1 = generateDoc(params); + const migratedTestDoc1 = migrate(testDoc1); + const series = JSON.parse(migratedTestDoc1.attributes.visState).params.series; + + expect(series[2]).not.toHaveProperty('filter.query'); + }); + + it('should not migrate a visualization of unknown type', () => { + const params = { type: 'unknown', series: [{ filter: 'foo:bar' }] }; + const doc = generateDoc(params); + const migratedDoc = migrate(doc); + const series = JSON.parse(migratedDoc.attributes.visState).params.series; + + expect(series[0].filter).toEqual(params.series[0].filter); + }); + }); + + describe('7.3.1', () => { + const migrate = (doc: any) => + visualizationSavedObjectTypeMigrations['7.3.1']( + doc as Parameters[0], + savedObjectMigrationContext + ); + + it('should migrate filters agg query string queries', () => { + const state = { + aggs: [ + { type: 'count', params: {} }, + { + type: 'filters', + params: { + filters: [ + { + input: { + query: { + query_string: { query: 'machine.os.keyword:"win 8"' }, + }, + }, + }, + ], + }, + }, + ], + }; + const expected = { + aggs: [ + { type: 'count', params: {} }, + { + type: 'filters', + params: { + filters: [{ input: { query: 'machine.os.keyword:"win 8"' } }], + }, + }, + ], + }; + const migratedDoc = migrate({ attributes: { visState: JSON.stringify(state) } }); + + expect(migratedDoc).toEqual({ attributes: { visState: JSON.stringify(expected) } }); + }); + }); + + describe('7.4.2 tsvb split_filters migration', () => { + const migrate = (doc: any) => + visualizationSavedObjectTypeMigrations['7.4.2']( + doc as Parameters[0], + savedObjectMigrationContext + ); + const generateDoc = (params: any) => ({ + attributes: { + title: 'My Vis', + description: 'This is my super cool vis.', + visState: JSON.stringify({ params }), + uiStateJSON: '{}', + version: 1, + kibanaSavedObjectMeta: { + searchSourceJSON: '{}', + }, + }, + }); + + it('should change series item filters from a string into an object for all filters', () => { + const params = { + type: 'timeseries', + filter: { + query: 'bytes:>1000', + language: 'lucene', + }, + series: [ + { + split_filters: [{ filter: 'bytes:>1000' }], + }, + ], + }; + const timeSeriesDoc = generateDoc(params); + const migratedtimeSeriesDoc = migrate(timeSeriesDoc); + const timeSeriesParams = JSON.parse(migratedtimeSeriesDoc.attributes.visState).params; + + expect(Object.keys(timeSeriesParams.filter)).toEqual( + expect.arrayContaining(['query', 'language']) + ); + expect(timeSeriesParams.series[0].split_filters[0].filter).toEqual({ + query: 'bytes:>1000', + language: 'lucene', + }); + }); + + it('should change series item split filters when there is no filter item', () => { + const params = { + type: 'timeseries', + filter: { + query: 'bytes:>1000', + language: 'lucene', + }, + series: [ + { + split_filters: [{ filter: 'bytes:>1000' }], + }, + ], + annotations: [ + { + query_string: { + query: 'bytes:>1000', + language: 'lucene', + }, + }, + ], + }; + const timeSeriesDoc = generateDoc(params); + const migratedtimeSeriesDoc = migrate(timeSeriesDoc); + const timeSeriesParams = JSON.parse(migratedtimeSeriesDoc.attributes.visState).params; + + expect(timeSeriesParams.series[0].split_filters[0].filter).toEqual({ + query: 'bytes:>1000', + language: 'lucene', + }); + }); + + it('should not convert split_filters to objects if there are no split filter filters', () => { + const params = { + type: 'timeseries', + filter: { + query: 'bytes:>1000', + language: 'lucene', + }, + series: [ + { + split_filters: [], + }, + ], + }; + const timeSeriesDoc = generateDoc(params); + const migratedtimeSeriesDoc = migrate(timeSeriesDoc); + const timeSeriesParams = JSON.parse(migratedtimeSeriesDoc.attributes.visState).params; + + expect(timeSeriesParams.series[0].split_filters).not.toHaveProperty('query'); + }); + + it('should do nothing if a split_filter is already a query:language object', () => { + const params = { + type: 'timeseries', + filter: { + query: 'bytes:>1000', + language: 'lucene', + }, + series: [ + { + split_filters: [ + { + filter: { + query: 'bytes:>1000', + language: 'lucene', + }, + }, + ], + }, + ], + annotations: [ + { + query_string: { + query: 'bytes:>1000', + language: 'lucene', + }, + }, + ], + }; + const timeSeriesDoc = generateDoc(params); + const migratedtimeSeriesDoc = migrate(timeSeriesDoc); + const timeSeriesParams = JSON.parse(migratedtimeSeriesDoc.attributes.visState).params; + + expect(timeSeriesParams.series[0].split_filters[0].filter.query).toEqual('bytes:>1000'); + expect(timeSeriesParams.series[0].split_filters[0].filter.language).toEqual('lucene'); + }); + }); +}); diff --git a/src/plugins/visualizations/server/saved_objects/visualization_migrations.ts b/src/plugins/visualizations/server/saved_objects/visualization_migrations.ts new file mode 100644 index 00000000000000..9ee355cbb23cfe --- /dev/null +++ b/src/plugins/visualizations/server/saved_objects/visualization_migrations.ts @@ -0,0 +1,574 @@ +/* + * 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 { SavedObjectMigrationFn } from 'kibana/server'; +import { cloneDeep, get, omit, has, flow } from 'lodash'; + +const migrateIndexPattern: SavedObjectMigrationFn = doc => { + const searchSourceJSON = get(doc, 'attributes.kibanaSavedObjectMeta.searchSourceJSON'); + if (typeof searchSourceJSON !== 'string') { + return doc; + } + let searchSource; + try { + searchSource = JSON.parse(searchSourceJSON); + } catch (e) { + // Let it go, the data is invalid and we'll leave it as is + return doc; + } + + if (searchSource.index && Array.isArray(doc.references)) { + searchSource.indexRefName = 'kibanaSavedObjectMeta.searchSourceJSON.index'; + doc.references.push({ + name: searchSource.indexRefName, + type: 'index-pattern', + id: searchSource.index, + }); + delete searchSource.index; + } + if (searchSource.filter) { + searchSource.filter.forEach((filterRow: any, i: number) => { + if (!filterRow.meta || !filterRow.meta.index || !Array.isArray(doc.references)) { + return; + } + filterRow.meta.indexRefName = `kibanaSavedObjectMeta.searchSourceJSON.filter[${i}].meta.index`; + doc.references.push({ + name: filterRow.meta.indexRefName, + type: 'index-pattern', + id: filterRow.meta.index, + }); + delete filterRow.meta.index; + }); + } + + doc.attributes.kibanaSavedObjectMeta.searchSourceJSON = JSON.stringify(searchSource); + + return doc; +}; + +// [TSVB] Migrate percentile-rank aggregation (value -> values) +const migratePercentileRankAggregation: 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 => { + (part.metrics || []).forEach((metric: any) => { + if (metric.type === 'percentile_rank' && has(metric, 'value')) { + metric.values = [metric.value]; + + delete metric.value; + } + }); + }); + + return { + ...doc, + attributes: { + ...doc.attributes, + visState: JSON.stringify(visState), + }, + }; + } + } + return doc; +}; + +// Migrate date histogram aggregation (remove customInterval) +const migrateDateHistogramAggregation: 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.aggs) { + visState.aggs.forEach((agg: any) => { + if (agg.type === 'date_histogram' && agg.params) { + if (agg.params.interval === 'custom') { + agg.params.interval = agg.params.customInterval; + } + delete agg.params.customInterval; + } + + if ( + get(agg, 'params.customBucket.type', null) === 'date_histogram' && + agg.params.customBucket.params + ) { + if (agg.params.customBucket.params.interval === 'custom') { + agg.params.customBucket.params.interval = agg.params.customBucket.params.customInterval; + } + delete agg.params.customBucket.params.customInterval; + } + }); + return { + ...doc, + attributes: { + ...doc.attributes, + visState: JSON.stringify(visState), + }, + }; + } + } + return doc; +}; + +const removeDateHistogramTimeZones: SavedObjectMigrationFn = doc => { + const visStateJSON = get(doc, 'attributes.visState'); + if (visStateJSON) { + let visState; + try { + visState = JSON.parse(visStateJSON); + } catch (e) { + // Let it go, the data is invalid and we'll leave it as is + } + if (visState && visState.aggs) { + visState.aggs.forEach((agg: any) => { + // We're checking always for the existance of agg.params here. This should always exist, but better + // be safe then sorry during migrations. + if (agg.type === 'date_histogram' && agg.params) { + delete agg.params.time_zone; + } + + if ( + get(agg, 'params.customBucket.type', null) === 'date_histogram' && + agg.params.customBucket.params + ) { + delete agg.params.customBucket.params.time_zone; + } + }); + doc.attributes.visState = JSON.stringify(visState); + } + } + return doc; +}; + +// migrate gauge verticalSplit to alignment +// https://github.com/elastic/kibana/issues/34636 +const migrateGaugeVerticalSplitToAlignment: SavedObjectMigrationFn = (doc, logger) => { + const visStateJSON = get(doc, 'attributes.visState'); + + if (visStateJSON) { + try { + const visState = JSON.parse(visStateJSON); + if (visState && visState.type === 'gauge' && !visState.params.gauge.alignment) { + visState.params.gauge.alignment = visState.params.gauge.verticalSplit + ? 'vertical' + : 'horizontal'; + delete visState.params.gauge.verticalSplit; + return { + ...doc, + attributes: { + ...doc.attributes, + visState: JSON.stringify(visState), + }, + }; + } + } catch (e) { + logger.log.warn(`Exception @ migrateGaugeVerticalSplitToAlignment! ${e}`); + logger.log.warn(`Exception @ migrateGaugeVerticalSplitToAlignment! Payload: ${visStateJSON}`); + } + } + return doc; +}; +// Migrate filters (string -> { query: string, language: lucene }) +/* + Enabling KQL in TSVB causes problems with savedObject visualizations when these are saved with filters. + In a visualisation type of saved object, if the visState param is of type metric, the filter is saved as a string that is not interpretted correctly as a lucene query in the visualization itself. + We need to transform the filter string into an object containing the original string as a query and specify the query language as lucene. + For Metrics visualizations (param.type === "metric"), filters can be applied to each series object in the series array within the SavedObject.visState.params object. + Path to the series array is thus: + attributes.visState. +*/ +const transformFilterStringToQueryObject: SavedObjectMigrationFn = (doc, logger) => { + // Migrate filters + // If any filters exist and they are a string, we assume it to be lucene and transform the filter into an object accordingly + const newDoc = cloneDeep(doc); + const visStateJSON = get(doc, 'attributes.visState'); + if (visStateJSON) { + let visState; + try { + visState = JSON.parse(visStateJSON); + } catch (e) { + // let it go, the data is invalid and we'll leave it as is + } + if (visState) { + const visType = get(visState, 'params.type'); + const tsvbTypes = ['metric', 'markdown', 'top_n', 'gauge', 'table', 'timeseries']; + if (tsvbTypes.indexOf(visType) === -1) { + // skip + return doc; + } + // migrate the params fitler + const params: any = get(visState, 'params'); + if (params.filter && typeof params.filter === 'string') { + const paramsFilterObject = { + query: params.filter, + language: 'lucene', + }; + params.filter = paramsFilterObject; + } + + // migrate the annotations query string: + const annotations: any[] = get(visState, 'params.annotations') || []; + annotations.forEach(item => { + if (!item.query_string) { + // we don't need to transform anything if there isn't a filter at all + return; + } + if (typeof item.query_string === 'string') { + const itemQueryStringObject = { + query: item.query_string, + language: 'lucene', + }; + item.query_string = itemQueryStringObject; + } + }); + // migrate the series filters + const series: any[] = get(visState, 'params.series') || []; + + series.forEach(item => { + if (!item.filter) { + // we don't need to transform anything if there isn't a filter at all + return; + } + // series item filter + if (typeof item.filter === 'string') { + const itemfilterObject = { + query: item.filter, + language: 'lucene', + }; + item.filter = itemfilterObject; + } + // series item split filters filter + if (item.split_filters) { + const splitFilters: any[] = get(item, 'split_filters') || []; + splitFilters.forEach(filter => { + if (!filter.filter) { + // we don't need to transform anything if there isn't a filter at all + return; + } + if (typeof filter.filter === 'string') { + const filterfilterObject = { + query: filter.filter, + language: 'lucene', + }; + filter.filter = filterfilterObject; + } + }); + } + }); + newDoc.attributes.visState = JSON.stringify(visState); + } + } + return newDoc; +}; + +const transformSplitFiltersStringToQueryObject: SavedObjectMigrationFn = doc => { + // Migrate split_filters in TSVB objects that weren't migrated in 7.3 + // If any filters exist and they are a string, we assume them to be lucene syntax and transform the filter into an object accordingly + const newDoc = cloneDeep(doc); + const visStateJSON = get(doc, 'attributes.visState'); + if (visStateJSON) { + let visState; + try { + visState = JSON.parse(visStateJSON); + } catch (e) { + // let it go, the data is invalid and we'll leave it as is + } + if (visState) { + const visType = get(visState, 'params.type'); + const tsvbTypes = ['metric', 'markdown', 'top_n', 'gauge', 'table', 'timeseries']; + if (tsvbTypes.indexOf(visType) === -1) { + // skip + return doc; + } + // migrate the series split_filter filters + const series: any[] = get(visState, 'params.series') || []; + series.forEach(item => { + // series item split filters filter + if (item.split_filters) { + const splitFilters: any[] = get(item, 'split_filters') || []; + if (splitFilters.length > 0) { + // only transform split_filter filters if we have filters + splitFilters.forEach(filter => { + if (typeof filter.filter === 'string') { + const filterfilterObject = { + query: filter.filter, + language: 'lucene', + }; + filter.filter = filterfilterObject; + } + }); + } + } + }); + newDoc.attributes.visState = JSON.stringify(visState); + } + } + return newDoc; +}; + +const migrateFiltersAggQuery: SavedObjectMigrationFn = doc => { + const visStateJSON = get(doc, 'attributes.visState'); + + if (visStateJSON) { + try { + const visState = JSON.parse(visStateJSON); + + if (visState && visState.aggs) { + visState.aggs.forEach((agg: any) => { + if (agg.type !== 'filters') return; + + agg.params.filters.forEach((filter: any) => { + if (filter.input.language) return filter; + filter.input.language = 'lucene'; + }); + }); + + return { + ...doc, + attributes: { + ...doc.attributes, + visState: JSON.stringify(visState), + }, + }; + } + } catch (e) { + // Let it go, the data is invalid and we'll leave it as is + } + } + return doc; +}; + +const replaceMovAvgToMovFn: SavedObjectMigrationFn = (doc, logger) => { + const visStateJSON = get(doc, 'attributes.visState'); + let visState; + + if (visStateJSON) { + try { + visState = JSON.parse(visStateJSON); + + if (visState && visState.type === 'metrics') { + const series: any[] = get(visState, 'params.series', []); + + series.forEach(part => { + if (part.metrics && Array.isArray(part.metrics)) { + part.metrics.forEach((metric: any) => { + if (metric.type === 'moving_average') { + metric.model_type = metric.model; + metric.alpha = get(metric, 'settings.alpha', 0.3); + metric.beta = get(metric, 'settings.beta', 0.1); + metric.gamma = get(metric, 'settings.gamma', 0.3); + metric.period = get(metric, 'settings.period', 1); + metric.multiplicative = get(metric, 'settings.type') === 'mult'; + + delete metric.minimize; + delete metric.model; + delete metric.settings; + delete metric.predict; + } + }); + } + }); + + return { + ...doc, + attributes: { + ...doc.attributes, + visState: JSON.stringify(visState), + }, + }; + } + } catch (e) { + logger.log.warn(`Exception @ replaceMovAvgToMovFn! ${e}`); + logger.log.warn(`Exception @ replaceMovAvgToMovFn! Payload: ${visStateJSON}`); + } + } + + return doc; +}; + +const migrateFiltersAggQueryStringQueries: SavedObjectMigrationFn = (doc, logger) => { + const visStateJSON = get(doc, 'attributes.visState'); + + if (visStateJSON) { + try { + const visState = JSON.parse(visStateJSON); + + if (visState && visState.aggs) { + visState.aggs.forEach((agg: any) => { + if (agg.type !== 'filters') return doc; + + agg.params.filters.forEach((filter: any) => { + if (filter.input.query.query_string) { + filter.input.query = filter.input.query.query_string.query; + } + }); + }); + + return { + ...doc, + attributes: { + ...doc.attributes, + visState: JSON.stringify(visState), + }, + }; + } + } catch (e) { + // Let it go, the data is invalid and we'll leave it as is + } + } + return doc; +}; + +const addDocReferences: SavedObjectMigrationFn = doc => ({ + ...doc, + references: doc.references || [], +}); + +const migrateSavedSearch: SavedObjectMigrationFn = doc => { + const savedSearchId = get(doc, 'attributes.savedSearchId'); + + if (savedSearchId && doc.references) { + doc.references.push({ + type: 'search', + name: 'search_0', + id: savedSearchId, + }); + doc.attributes.savedSearchRefName = 'search_0'; + } + + delete doc.attributes.savedSearchId; + + return doc; +}; + +const migrateControls: SavedObjectMigrationFn = doc => { + const visStateJSON = get(doc, 'attributes.visState'); + + if (visStateJSON) { + let visState; + try { + visState = JSON.parse(visStateJSON); + } catch (e) { + // Let it go, the data is invalid and we'll leave it as is + } + if (visState) { + const controls: any[] = get(visState, 'params.controls') || []; + controls.forEach((control, i) => { + if (!control.indexPattern || !doc.references) { + return; + } + control.indexPatternRefName = `control_${i}_index_pattern`; + doc.references.push({ + name: control.indexPatternRefName, + type: 'index-pattern', + id: control.indexPattern, + }); + delete control.indexPattern; + }); + doc.attributes.visState = JSON.stringify(visState); + } + } + + return doc; +}; + +const migrateTableSplits: SavedObjectMigrationFn = doc => { + try { + const visState = JSON.parse(doc.attributes.visState); + if (get(visState, 'type') !== 'table') { + return doc; // do nothing; we only want to touch tables + } + + let splitCount = 0; + visState.aggs = visState.aggs.map((agg: any) => { + if (agg.schema !== 'split') { + return agg; + } + + splitCount++; + if (splitCount === 1) { + return agg; // leave the first split agg unchanged + } + agg.schema = 'bucket'; + // the `row` param is exclusively used by split aggs, so we remove it + agg.params = omit(agg.params, ['row']); + return agg; + }); + + if (splitCount <= 1) { + return doc; // do nothing; we only want to touch tables with multiple split aggs + } + + const newDoc = cloneDeep(doc); + newDoc.attributes.visState = JSON.stringify(visState); + + return newDoc; + } catch (e) { + throw new Error(`Failure attempting to migrate saved object '${doc.attributes.title}' - ${e}`); + } +}; + +export const visualizationSavedObjectTypeMigrations = { + /** + * We need to have this migration twice, once with a version prior to 7.0.0 once with a version + * after it. The reason for that is, that this migration has been introduced once 7.0.0 was already + * released. Thus a user who already had 7.0.0 installed already got the 7.0.0 migrations below running, + * so we need a version higher than that. But this fix was backported to the 6.7 release, meaning if we + * would only have the 7.0.1 migration in here a user on the 6.7 release will migrate their saved objects + * to the 7.0.1 state, and thus when updating their Kibana to 7.0, will never run the 7.0.0 migrations introduced + * in that version. So we apply this twice, once with 6.7.2 and once with 7.0.1 while the backport to 6.7 + * only contained the 6.7.2 migration and not the 7.0.1 migration. + */ + '6.7.2': flow(removeDateHistogramTimeZones), + '7.0.0': flow( + addDocReferences, + migrateIndexPattern, + migrateSavedSearch, + migrateControls, + migrateTableSplits + ), + '7.0.1': flow(removeDateHistogramTimeZones), + '7.2.0': flow( + migratePercentileRankAggregation, + migrateDateHistogramAggregation + ), + '7.3.0': flow( + migrateGaugeVerticalSplitToAlignment, + transformFilterStringToQueryObject, + migrateFiltersAggQuery, + replaceMovAvgToMovFn + ), + '7.3.1': flow(migrateFiltersAggQueryStringQueries), + '7.4.2': flow(transformSplitFiltersStringToQueryObject), +}; diff --git a/src/legacy/core_plugins/data/public/search/expressions/boot.ts b/src/plugins/visualizations/server/types.ts similarity index 78% rename from src/legacy/core_plugins/data/public/search/expressions/boot.ts rename to src/plugins/visualizations/server/types.ts index 29348383ce6fe3..6924edb29627d9 100644 --- a/src/legacy/core_plugins/data/public/search/expressions/boot.ts +++ b/src/plugins/visualizations/server/types.ts @@ -17,7 +17,7 @@ * under the License. */ -import { npSetup } from 'ui/new_platform'; -import { esaggs } from './esaggs'; - -npSetup.plugins.expressions.registerFunction(esaggs); +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface VisualizationsPluginSetup {} +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface VisualizationsPluginStart {} diff --git a/src/test_utils/kbn_server.ts b/src/test_utils/kbn_server.ts index e1b4a823e7e871..12f7eb5a0a0431 100644 --- a/src/test_utils/kbn_server.ts +++ b/src/test_utils/kbn_server.ts @@ -50,6 +50,7 @@ const DEFAULTS_SETTINGS = { logging: { silent: true }, plugins: {}, optimize: { enabled: false }, + migrations: { skip: true }, }; const DEFAULT_SETTINGS_WITH_CORE_PLUGINS = { @@ -252,7 +253,7 @@ export function createTestServers({ return { startES: async () => { - await es.start(); + await es.start(get(settings, 'es.esArgs', [])); if (['gold', 'trial'].includes(license)) { await setupUsers({ diff --git a/tasks/test.js b/tasks/test.js index 504247f5b53551..5618ebba4e6ebe 100644 --- a/tasks/test.js +++ b/tasks/test.js @@ -61,7 +61,7 @@ module.exports = function(grunt) { 'run:apiIntegrationTests', ]); - grunt.registerTask('test:karmaDebug', ['checkPlugins', 'run:karmaDebugServer', 'karma:dev']); + grunt.registerTask('test:karmaDebug', ['checkPlugins', 'run:karmaTestDebugServer', 'karma:dev']); grunt.registerTask('test:mochaCoverage', ['run:mochaCoverage']); grunt.registerTask('test', subTask => { diff --git a/test/accessibility/apps/management.ts b/test/accessibility/apps/management.ts index 99afb21632ffac..ac2921ed063f50 100644 --- a/test/accessibility/apps/management.ts +++ b/test/accessibility/apps/management.ts @@ -21,13 +21,28 @@ import { FtrProviderContext } from '../ftr_provider_context'; export default function({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'settings']); - + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const testSubjects = getService('testSubjects'); const a11y = getService('a11y'); + // describe('Management', () => { + // before(async () => { + // await esArchiver.loadIfNeeded('logstash_functional'); + // await kibanaServer.uiSettings.update({ + // defaultIndex: 'logstash-*', + // }); + // await PageObjects.common.navigateToApp('settings'); + // }); + describe('Management', () => { before(async () => { - await PageObjects.common.navigateToApp('settings'); + await esArchiver.load('discover'); + await esArchiver.loadIfNeeded('logstash_functional'); + await kibanaServer.uiSettings.update({ + defaultIndex: 'logstash-*', + }); + await PageObjects.settings.navigateTo(); }); it('main view', async () => { @@ -50,8 +65,16 @@ export default function({ getService, getPageObjects }: FtrProviderContext) { await a11y.testAppSnapshot(); }); - it('Saved objects view', async () => { - await PageObjects.settings.clickKibanaSavedObjects(); + // index patterns page + it('Navigate back to logstash index page', async () => { + await PageObjects.settings.clickKibanaIndexPatterns(); + await PageObjects.settings.clickIndexPatternLogstash(); + await a11y.testAppSnapshot(); + }); + + // Issue: https://github.com/elastic/kibana/issues/60030 + it.skip('Edit field type', async () => { + await PageObjects.settings.clickEditFieldFormat(); await a11y.testAppSnapshot(); }); diff --git a/test/api_integration/apis/index.js b/test/api_integration/apis/index.js index 8cdbbf8e74a3de..57e9120773f33c 100644 --- a/test/api_integration/apis/index.js +++ b/test/api_integration/apis/index.js @@ -33,6 +33,5 @@ export default function({ loadTestFile }) { loadTestFile(require.resolve('./status')); loadTestFile(require.resolve('./stats')); loadTestFile(require.resolve('./ui_metric')); - loadTestFile(require.resolve('./core')); }); } diff --git a/test/functional/apps/dashboard/dashboard_state.js b/test/functional/apps/dashboard/dashboard_state.js index b9172990c501dc..a643a9ee40aa2c 100644 --- a/test/functional/apps/dashboard/dashboard_state.js +++ b/test/functional/apps/dashboard/dashboard_state.js @@ -24,7 +24,7 @@ import { PIE_CHART_VIS_NAME, AREA_CHART_VIS_NAME } from '../../page_objects/dash // eslint-disable-next-line import { DEFAULT_PANEL_WIDTH -} from '../../../../src/plugins/dashboard_embeddable_container/public/embeddable/dashboard_constants'; +} from '../../../../src/plugins/dashboard/public/embeddable/dashboard_constants'; export default function({ getService, getPageObjects }) { const PageObjects = getPageObjects([ diff --git a/test/functional/apps/management/_scripted_fields.js b/test/functional/apps/management/_scripted_fields.js index b1a14cd18f5571..65291c3c4772c5 100644 --- a/test/functional/apps/management/_scripted_fields.js +++ b/test/functional/apps/management/_scripted_fields.js @@ -53,7 +53,7 @@ export default function({ getService, getPageObjects }) { ]); describe('scripted fields', function() { - this.tags(['skipFirefox', 'skipCoverage']); + this.tags(['skipFirefox']); before(async function() { await browser.setWindowSize(1200, 800); diff --git a/test/functional/apps/visualize/index.ts b/test/functional/apps/visualize/index.ts index 68285971e5c4a0..06d560530c28a5 100644 --- a/test/functional/apps/visualize/index.ts +++ b/test/functional/apps/visualize/index.ts @@ -20,11 +20,13 @@ import { FtrProviderContext } from '../../ftr_provider_context.d'; // eslint-disable-next-line @typescript-eslint/no-namespace, import/no-default-export -export default function({ getService, loadTestFile }: FtrProviderContext) { +export default function({ getService, getPageObjects, loadTestFile }: FtrProviderContext) { const browser = getService('browser'); const log = getService('log'); const esArchiver = getService('esArchiver'); const kibanaServer = getService('kibanaServer'); + const PageObjects = getPageObjects(['common']); + let isOss = true; describe('visualize app', () => { before(async () => { @@ -37,6 +39,7 @@ export default function({ getService, loadTestFile }: FtrProviderContext) { defaultIndex: 'logstash-*', 'format:bytes:defaultPattern': '0,0.[000]b', }); + isOss = await PageObjects.common.isOss(); }); describe('', function() { @@ -67,20 +70,22 @@ export default function({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./_line_chart')); loadTestFile(require.resolve('./_pie_chart')); - loadTestFile(require.resolve('./_region_map')); loadTestFile(require.resolve('./_point_series_options')); loadTestFile(require.resolve('./_markdown_vis')); loadTestFile(require.resolve('./_shared_item')); loadTestFile(require.resolve('./_lab_mode')); loadTestFile(require.resolve('./_linked_saved_searches')); loadTestFile(require.resolve('./_visualize_listing')); + if (isOss) { + loadTestFile(require.resolve('./_tile_map')); + loadTestFile(require.resolve('./_region_map')); + } }); describe('', function() { this.tags('ciGroup12'); loadTestFile(require.resolve('./_tag_cloud')); - loadTestFile(require.resolve('./_tile_map')); loadTestFile(require.resolve('./_vertical_bar_chart')); loadTestFile(require.resolve('./_vertical_bar_chart_nontimeindex')); loadTestFile(require.resolve('./_tsvb_chart')); diff --git a/test/functional/page_objects/settings_page.ts b/test/functional/page_objects/settings_page.ts index a0f503eb27e682..c244deba5f17ea 100644 --- a/test/functional/page_objects/settings_page.ts +++ b/test/functional/page_objects/settings_page.ts @@ -657,6 +657,10 @@ export function SettingsPageProvider({ getService, getPageObjects }: FtrProvider await testSubjects.click('importSavedObjectsConfirmBtn'); } + async clickEditFieldFormat() { + await testSubjects.click('editFieldFormat'); + } + async associateIndexPattern(oldIndexPatternId: string, newIndexPatternTitle: string) { await find.clickByCssSelector( `select[data-test-subj="managementChangeIndexSelection-${oldIndexPatternId}"] > diff --git a/test/plugin_functional/plugins/core_plugin_a/server/plugin.ts b/test/plugin_functional/plugins/core_plugin_a/server/plugin.ts index e057e63c03f4a5..6535a54f6b7443 100644 --- a/test/plugin_functional/plugins/core_plugin_a/server/plugin.ts +++ b/test/plugin_functional/plugins/core_plugin_a/server/plugin.ts @@ -34,7 +34,7 @@ export class CorePluginAPlugin implements Plugin { core.http.registerRouteHandlerContext('pluginA', context => { return { ping: () => - context.core!.elasticsearch.adminClient.callAsInternalUser('ping') as Promise, + context.core.elasticsearch.adminClient.callAsInternalUser('ping') as Promise, }; }); } diff --git a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/index.ts b/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/index.ts index dfce45671483ff..99f54277be5d2e 100644 --- a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/index.ts +++ b/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/index.ts @@ -29,7 +29,6 @@ export default function(kibana: any) { order: 1, main: 'plugins/kbn_tp_embeddable_explorer/np_ready/public/legacy', }, - hacks: ['plugins/dashboard_embeddable_container/initialize'], }, init(server: Legacy.Server) { server.injectUiAppVars('kbn_tp_embeddable_explorer', async () => diff --git a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/app/app.tsx b/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/app/app.tsx index 144954800c91fd..54d13efe4d7909 100644 --- a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/app/app.tsx +++ b/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/app/app.tsx @@ -19,18 +19,15 @@ import { EuiTab } from '@elastic/eui'; import React, { Component } from 'react'; import { CoreStart } from 'src/core/public'; -import { - GetEmbeddableFactory, - GetEmbeddableFactories, -} from 'src/legacy/core_plugins/embeddable_api/public/np_ready/public'; +import { EmbeddableStart } from 'src/plugins/embeddable/public'; import { UiActionsService } from '../../../../../../../../src/plugins/ui_actions/public'; import { DashboardContainerExample } from './dashboard_container_example'; import { Start as InspectorStartContract } from '../../../../../../../../src/plugins/inspector/public'; export interface AppProps { getActions: UiActionsService['getTriggerCompatibleActions']; - getEmbeddableFactory: GetEmbeddableFactory; - getAllEmbeddableFactories: GetEmbeddableFactories; + getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory']; + getAllEmbeddableFactories: EmbeddableStart['getEmbeddableFactories']; overlays: CoreStart['overlays']; notifications: CoreStart['notifications']; inspector: InspectorStartContract; diff --git a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/app/dashboard_container_example.tsx b/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/app/dashboard_container_example.tsx index df0c00fb48b2eb..f8625e4490e511 100644 --- a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/app/dashboard_container_example.tsx +++ b/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/app/dashboard_container_example.tsx @@ -18,19 +18,20 @@ */ import React from 'react'; import { EuiButton, EuiLoadingChart } from '@elastic/eui'; +import { ContainerOutput } from 'src/plugins/embeddable/public'; import { ErrorEmbeddable, ViewMode, isErrorEmbeddable, EmbeddablePanel, - GetEmbeddableFactory, - GetEmbeddableFactories, + EmbeddableStart, } from '../embeddable_api'; import { DASHBOARD_CONTAINER_TYPE, DashboardContainer, DashboardContainerFactory, -} from '../../../../../../../../src/legacy/core_plugins/dashboard_embeddable_container/public/np_ready/public'; + DashboardContainerInput, +} from '../../../../../../../../src/plugins/dashboard/public'; import { CoreStart } from '../../../../../../../../src/core/public'; import { dashboardInput } from './dashboard_input'; @@ -39,8 +40,8 @@ import { UiActionsService } from '../../../../../../../../src/plugins/ui_actions interface Props { getActions: UiActionsService['getTriggerCompatibleActions']; - getEmbeddableFactory: GetEmbeddableFactory; - getAllEmbeddableFactories: GetEmbeddableFactories; + getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory']; + getAllEmbeddableFactories: EmbeddableStart['getEmbeddableFactories']; overlays: CoreStart['overlays']; notifications: CoreStart['notifications']; inspector: InspectorStartContract; @@ -67,9 +68,10 @@ export class DashboardContainerExample extends React.Component { public async componentDidMount() { this.mounted = true; - const dashboardFactory = this.props.getEmbeddableFactory( - DASHBOARD_CONTAINER_TYPE - ) as DashboardContainerFactory; + const dashboardFactory = this.props.getEmbeddableFactory< + DashboardContainerInput, + ContainerOutput + >(DASHBOARD_CONTAINER_TYPE) as DashboardContainerFactory; if (dashboardFactory) { this.container = await dashboardFactory.create(dashboardInput); if (this.mounted) { diff --git a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/app/dashboard_input.ts b/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/app/dashboard_input.ts index 3c8468a3d8ed37..bb8951680be350 100644 --- a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/app/dashboard_input.ts +++ b/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/app/dashboard_input.ts @@ -18,7 +18,7 @@ */ import { ViewMode, CONTACT_CARD_EMBEDDABLE, HELLO_WORLD_EMBEDDABLE } from '../embeddable_api'; -import { DashboardContainerInput } from '../../../../../../../../src/legacy/core_plugins/dashboard_embeddable_container/public/np_ready/public'; +import { DashboardContainerInput } from '../../../../../../../../src/plugins/dashboard/public'; export const dashboardInput: DashboardContainerInput = { panels: { diff --git a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/embeddables/hello_world_embeddable_factory.ts b/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/embeddables/hello_world_embeddable_factory.ts deleted file mode 100644 index 0c90cb3b85867a..00000000000000 --- a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/embeddables/hello_world_embeddable_factory.ts +++ /dev/null @@ -1,28 +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. - */ - -// eslint-disable-next-line -import { npSetup } from '../../../../../../../../src/legacy/ui/public/new_platform'; -// eslint-disable-next-line -import { HelloWorldEmbeddableFactory, HELLO_WORLD_EMBEDDABLE } from '../../../../../../../../examples/embeddable_examples/public'; - -npSetup.plugins.embeddable.registerEmbeddableFactory( - HELLO_WORLD_EMBEDDABLE, - new HelloWorldEmbeddableFactory() -); diff --git a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/plugin.tsx b/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/plugin.tsx index 25666dc0359d95..18ceec652392d1 100644 --- a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/plugin.tsx +++ b/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/public/np_ready/public/plugin.tsx @@ -31,21 +31,16 @@ import { CONTEXT_MENU_TRIGGER } from './embeddable_api'; const REACT_ROOT_ID = 'embeddableExplorerRoot'; -import { - SayHelloAction, - createSendMessageAction, - ContactCardEmbeddableFactory, -} from './embeddable_api'; +import { SayHelloAction, createSendMessageAction } from './embeddable_api'; import { App } from './app'; import { getSavedObjectFinder } from '../../../../../../../src/plugins/saved_objects/public'; -import { HelloWorldEmbeddableFactory } from '../../../../../../../examples/embeddable_examples/public'; import { - IEmbeddableStart, - IEmbeddableSetup, + EmbeddableStart, + EmbeddableSetup, } from '.../../../../../../../src/plugins/embeddable/public'; export interface SetupDependencies { - embeddable: IEmbeddableSetup; + embeddable: EmbeddableSetup; inspector: InspectorSetupContract; __LEGACY: { ExitFullScreenButton: React.ComponentType; @@ -53,7 +48,7 @@ export interface SetupDependencies { } interface StartDependencies { - embeddable: IEmbeddableStart; + embeddable: EmbeddableStart; uiActions: UiActionsStart; inspector: InspectorStartContract; __LEGACY: { @@ -74,12 +69,6 @@ export class EmbeddableExplorerPublicPlugin const helloWorldAction = createHelloWorldAction(core.overlays); const sayHelloAction = new SayHelloAction(alert); const sendMessageAction = createSendMessageAction(core.overlays); - const helloWorldEmbeddableFactory = new HelloWorldEmbeddableFactory(); - const contactCardEmbeddableFactory = new ContactCardEmbeddableFactory( - {}, - plugins.uiActions.executeTriggerActions, - core.overlays - ); plugins.uiActions.registerAction(helloWorldAction); plugins.uiActions.registerAction(sayHelloAction); @@ -87,15 +76,6 @@ export class EmbeddableExplorerPublicPlugin plugins.uiActions.attachAction(CONTEXT_MENU_TRIGGER, helloWorldAction); - plugins.embeddable.registerEmbeddableFactory( - helloWorldEmbeddableFactory.type, - helloWorldEmbeddableFactory - ); - plugins.embeddable.registerEmbeddableFactory( - contactCardEmbeddableFactory.type, - contactCardEmbeddableFactory - ); - plugins.__LEGACY.onRenderComplete(() => { const root = document.getElementById(REACT_ROOT_ID); ReactDOM.render( diff --git a/test/plugin_functional/plugins/ui_settings_plugin/server/plugin.ts b/test/plugin_functional/plugins/ui_settings_plugin/server/plugin.ts index c32e8a75d95da5..3801d3bbce055b 100644 --- a/test/plugin_functional/plugins/ui_settings_plugin/server/plugin.ts +++ b/test/plugin_functional/plugins/ui_settings_plugin/server/plugin.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import { schema } from '@kbn/config-schema'; import { Plugin, CoreSetup } from 'kibana/server'; export class UiSettingsPlugin implements Plugin { @@ -27,6 +27,7 @@ export class UiSettingsPlugin implements Plugin { description: 'just for testing', value: '2', category: ['any'], + schema: schema.string(), }, }); diff --git a/test/plugin_functional/test_suites/embeddable_explorer/dashboard_container.js b/test/plugin_functional/test_suites/embeddable_explorer/dashboard_container.js index 203378e547c8ab..4a1bcecc0d5a1e 100644 --- a/test/plugin_functional/test_suites/embeddable_explorer/dashboard_container.js +++ b/test/plugin_functional/test_suites/embeddable_explorer/dashboard_container.js @@ -17,11 +17,8 @@ * under the License. */ -import expect from '@kbn/expect'; - export default function({ getService }) { const testSubjects = getService('testSubjects'); - const retry = getService('retry'); const pieChart = getService('pieChart'); const dashboardExpect = getService('dashboardExpect'); @@ -30,17 +27,6 @@ export default function({ getService }) { await testSubjects.click('embedExplorerTab-dashboardContainer'); }); - it('hello world embeddable renders', async () => { - await retry.try(async () => { - const text = await testSubjects.getVisibleText('helloWorldEmbeddable'); - expect(text).to.be('HELLO WORLD!'); - }); - }); - - it('contact card embeddable renders', async () => { - await testSubjects.existOrFail('embeddablePanelHeading-HelloSue'); - }); - it('pie charts', async () => { await pieChart.expectPieSliceCount(5); }); diff --git a/test/typings/query_string.d.ts b/test/typings/query_string.d.ts new file mode 100644 index 00000000000000..3e4a8fa4da6a01 --- /dev/null +++ b/test/typings/query_string.d.ts @@ -0,0 +1,46 @@ +/* + * 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. + */ + +declare module 'query-string' { + type ArrayFormat = 'bracket' | 'index' | 'none'; + + export interface ParseOptions { + arrayFormat?: ArrayFormat; + sort: ((itemLeft: string, itemRight: string) => number) | false; + } + + export interface ParsedQuery { + [key: string]: T | T[] | null | undefined; + } + + export function parse(str: string, options?: ParseOptions): ParsedQuery; + + export function parseUrl(str: string, options?: ParseOptions): { url: string; query: any }; + + export interface StringifyOptions { + strict?: boolean; + encode?: boolean; + arrayFormat?: ArrayFormat; + sort: ((itemLeft: string, itemRight: string) => number) | false; + } + + export function stringify(obj: object, options?: StringifyOptions): string; + + export function extract(str: string): string; +} diff --git a/typings/query_string.d.ts b/typings/query_string.d.ts new file mode 100644 index 00000000000000..3e4a8fa4da6a01 --- /dev/null +++ b/typings/query_string.d.ts @@ -0,0 +1,46 @@ +/* + * 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. + */ + +declare module 'query-string' { + type ArrayFormat = 'bracket' | 'index' | 'none'; + + export interface ParseOptions { + arrayFormat?: ArrayFormat; + sort: ((itemLeft: string, itemRight: string) => number) | false; + } + + export interface ParsedQuery { + [key: string]: T | T[] | null | undefined; + } + + export function parse(str: string, options?: ParseOptions): ParsedQuery; + + export function parseUrl(str: string, options?: ParseOptions): { url: string; query: any }; + + export interface StringifyOptions { + strict?: boolean; + encode?: boolean; + arrayFormat?: ArrayFormat; + sort: ((itemLeft: string, itemRight: string) => number) | false; + } + + export function stringify(obj: object, options?: StringifyOptions): string; + + export function extract(str: string): string; +} diff --git a/x-pack/index.js b/x-pack/index.js index c917befb4b3ddb..ab31d40c5d7183 100644 --- a/x-pack/index.js +++ b/x-pack/index.js @@ -9,7 +9,6 @@ import { graph } from './legacy/plugins/graph'; import { monitoring } from './legacy/plugins/monitoring'; import { reporting } from './legacy/plugins/reporting'; import { security } from './legacy/plugins/security'; -import { ml } from './legacy/plugins/ml'; import { tilemap } from './legacy/plugins/tilemap'; import { grokdebugger } from './legacy/plugins/grokdebugger'; import { dashboardMode } from './legacy/plugins/dashboard_mode'; @@ -45,7 +44,6 @@ module.exports = function(kibana) { reporting(kibana), spaces(kibana), security(kibana), - ml(kibana), tilemap(kibana), grokdebugger(kibana), dashboardMode(kibana), diff --git a/x-pack/legacy/plugins/apm/index.ts b/x-pack/legacy/plugins/apm/index.ts index 2efa13a0bbc8db..0107997f233fe0 100644 --- a/x-pack/legacy/plugins/apm/index.ts +++ b/x-pack/legacy/plugins/apm/index.ts @@ -71,7 +71,7 @@ export const apm: LegacyPluginInitializer = kibana => { autocreateApmIndexPattern: Joi.boolean().default(true), // service map - serviceMapEnabled: Joi.boolean().default(false) + serviceMapEnabled: Joi.boolean().default(true) }).default(); }, diff --git a/x-pack/legacy/plugins/apm/public/components/app/Home/__snapshots__/Home.test.tsx.snap b/x-pack/legacy/plugins/apm/public/components/app/Home/__snapshots__/Home.test.tsx.snap index d5764001a7f180..88d9d7864576f8 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Home/__snapshots__/Home.test.tsx.snap +++ b/x-pack/legacy/plugins/apm/public/components/app/Home/__snapshots__/Home.test.tsx.snap @@ -6,7 +6,7 @@ exports[`Home component should render services 1`] = ` Object { "config": Object { "indexPatternTitle": "apm-*", - "serviceMapEnabled": false, + "serviceMapEnabled": true, "ui": Object { "enabled": false, }, @@ -46,7 +46,7 @@ exports[`Home component should render traces 1`] = ` Object { "config": Object { "indexPatternTitle": "apm-*", - "serviceMapEnabled": false, + "serviceMapEnabled": true, "ui": Object { "enabled": false, }, diff --git a/x-pack/legacy/plugins/apm/public/components/app/Home/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/Home/index.tsx index 5f8fa8bf5dc073..07d7ce1e5b48c8 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Home/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/Home/index.tsx @@ -27,7 +27,7 @@ import { ServiceOverview } from '../ServiceOverview'; import { TraceOverview } from '../TraceOverview'; function getHomeTabs({ - serviceMapEnabled = false + serviceMapEnabled = true }: { serviceMapEnabled: boolean; }) { diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Controls.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Controls.tsx index 38e86e4a0d1c93..a2e7b2c76031ec 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Controls.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Controls.tsx @@ -4,13 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiButtonIcon, EuiPanel } from '@elastic/eui'; +import { EuiButtonIcon, EuiPanel, EuiToolTip } from '@elastic/eui'; import theme from '@elastic/eui/dist/eui_theme_light.json'; import { i18n } from '@kbn/i18n'; import React, { useContext, useEffect, useState } from 'react'; import styled from 'styled-components'; import { CytoscapeContext } from './Cytoscape'; import { animationOptions, nodeHeight } from './cytoscapeOptions'; +import { getAPMHref } from '../../shared/Links/apm/APMLink'; +import { useUrlParams } from '../../../hooks/useUrlParams'; +import { APMQueryParams } from '../../shared/Links/url_helpers'; const ControlsContainer = styled('div')` left: ${theme.gutterTypes.gutterMedium}; @@ -28,7 +31,7 @@ const ZoomInButton = styled(Button)` margin-bottom: ${theme.paddingSizes.s}; `; -const ZoomPanel = styled(EuiPanel)` +const Panel = styled(EuiPanel)` margin-bottom: ${theme.paddingSizes.s}; `; @@ -47,7 +50,8 @@ function doZoom(cy: cytoscape.Core | undefined, increment: number) { export function Controls() { const cy = useContext(CytoscapeContext); - + const { urlParams } = useUrlParams(); + const currentSearch = urlParams.kuery ?? ''; const [zoom, setZoom] = useState((cy && cy.zoom()) || 1); useEffect(() => { @@ -86,45 +90,73 @@ export function Controls() { const minZoom = cy.minZoom(); const isMinZoom = zoom === minZoom; const increment = (maxZoom - minZoom) / steps; + + const centerLabel = i18n.translate('xpack.apm.serviceMap.center', { + defaultMessage: 'Center' + }); + const viewFullMapLabel = i18n.translate('xpack.apm.serviceMap.viewFullMap', { + defaultMessage: 'View full service map' + }); const zoomInLabel = i18n.translate('xpack.apm.serviceMap.zoomIn', { defaultMessage: 'Zoom in' }); const zoomOutLabel = i18n.translate('xpack.apm.serviceMap.zoomOut', { defaultMessage: 'Zoom out' }); - const centerLabel = i18n.translate('xpack.apm.serviceMap.center', { - defaultMessage: 'Center' - }); + + const showViewFullMapButton = cy.nodes('.primary').length > 0; return ( - - -