diff --git a/docs/canvas/canvas-elements.asciidoc b/docs/canvas/canvas-elements.asciidoc index 85f0ee1150ba0..163579d5763b2 100644 --- a/docs/canvas/canvas-elements.asciidoc +++ b/docs/canvas/canvas-elements.asciidoc @@ -23,7 +23,7 @@ By default, most of the elements you create use demo data until you change the d * *{es} SQL* — Access your data in {es} using SQL syntax. For information about SQL syntax, refer to {ref}/sql-spec.html[SQL language]. -* *{es} raw data* — Access your raw data in {es} without the use of aggregations. Use {es} raw data when you have low volume datasets, or to plot exact, non-aggregated values. +* *{es} documents* — Access your data in {es} without using aggregations. To use, select an index and fields, and optionally enter a query using the <>. Use the *{es} documents* data source when you have low volume datasets, to view raw documents, or to plot exact, non-aggregated values on a chart. * *Timelion* — Access your time series data using <> queries. To use Timelion queries, you can enter a query using the <>. diff --git a/examples/alerting_example/tsconfig.json b/examples/alerting_example/tsconfig.json index 078522b36cb12..fbcec9de439bd 100644 --- a/examples/alerting_example/tsconfig.json +++ b/examples/alerting_example/tsconfig.json @@ -1,9 +1,7 @@ { "extends": "../../tsconfig.json", "compilerOptions": { - "outDir": "./target", - "skipLibCheck": true, - "resolveJsonModule": true + "outDir": "./target" }, "include": [ "index.ts", diff --git a/package.json b/package.json index c2763f098b984..b56598624f515 100644 --- a/package.json +++ b/package.json @@ -119,7 +119,7 @@ "@babel/register": "^7.9.0", "@elastic/apm-rum": "^4.6.0", "@elastic/charts": "^18.1.1", - "@elastic/datemath": "5.0.2", + "@elastic/datemath": "5.0.3", "@elastic/ems-client": "7.7.1", "@elastic/eui": "21.0.1", "@elastic/filesaver": "1.1.2", diff --git a/packages/elastic-datemath/.npmignore b/packages/elastic-datemath/.npmignore index 915a694e9066c..a56a2f3ff793e 100644 --- a/packages/elastic-datemath/.npmignore +++ b/packages/elastic-datemath/.npmignore @@ -2,3 +2,5 @@ /test /tsconfig.json /.babelrc +/yarn.lock +/__tests__ diff --git a/packages/elastic-datemath/README.md b/packages/elastic-datemath/README.md new file mode 100644 index 0000000000000..a8dcd9f6721cb --- /dev/null +++ b/packages/elastic-datemath/README.md @@ -0,0 +1,5 @@ +# datemath + +Datemath string parser used in Kibana. This is published to NPM for use in a limited number of locations outside of Kibana, but is not regularly updated and may get seriously out of date. + +If you file an issue in elastic/kibana we can probably update it for you if needed, though you probably shouldn't depend on this package for anything important. diff --git a/packages/elastic-datemath/package.json b/packages/elastic-datemath/package.json index 8c7c93834adc6..331b5494581cd 100644 --- a/packages/elastic-datemath/package.json +++ b/packages/elastic-datemath/package.json @@ -1,6 +1,6 @@ { "name": "@elastic/datemath", - "version": "5.0.2", + "version": "5.0.3", "description": "elasticsearch datemath parser, used in kibana", "license": "Apache-2.0", "main": "target/index.js", diff --git a/packages/elastic-datemath/readme.md b/packages/elastic-datemath/readme.md deleted file mode 100644 index f7de9627e6d69..0000000000000 --- a/packages/elastic-datemath/readme.md +++ /dev/null @@ -1,3 +0,0 @@ -# datemath - -Datemath string parser used in Kibana diff --git a/packages/kbn-optimizer/package.json b/packages/kbn-optimizer/package.json index d32c7489641a0..b648004760d7c 100644 --- a/packages/kbn-optimizer/package.json +++ b/packages/kbn-optimizer/package.json @@ -14,9 +14,12 @@ "@kbn/babel-preset": "1.0.0", "@kbn/dev-utils": "1.0.0", "@kbn/ui-shared-deps": "1.0.0", + "@types/estree": "^0.0.44", "@types/loader-utils": "^1.1.3", "@types/watchpack": "^1.1.5", "@types/webpack": "^4.41.3", + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1", "autoprefixer": "^9.7.4", "babel-loader": "^8.0.6", "clean-webpack-plugin": "^3.0.0", diff --git a/packages/kbn-optimizer/src/worker/__snapshots__/parse_path.test.ts.snap b/packages/kbn-optimizer/src/common/__snapshots__/parse_path.test.ts.snap similarity index 64% rename from packages/kbn-optimizer/src/worker/__snapshots__/parse_path.test.ts.snap rename to packages/kbn-optimizer/src/common/__snapshots__/parse_path.test.ts.snap index 2973ac116d6bd..f537674c3fff7 100644 --- a/packages/kbn-optimizer/src/worker/__snapshots__/parse_path.test.ts.snap +++ b/packages/kbn-optimizer/src/common/__snapshots__/parse_path.test.ts.snap @@ -4,6 +4,7 @@ exports[`parseDirPath() parses / 1`] = ` Object { "dirs": Array [], "filename": undefined, + "query": undefined, "root": "/", } `; @@ -14,6 +15,7 @@ Object { "foo", ], "filename": undefined, + "query": undefined, "root": "/", } `; @@ -26,6 +28,7 @@ Object { "baz", ], "filename": undefined, + "query": undefined, "root": "/", } `; @@ -38,6 +41,7 @@ Object { "baz", ], "filename": undefined, + "query": undefined, "root": "/", } `; @@ -46,6 +50,7 @@ exports[`parseDirPath() parses c:\\ 1`] = ` Object { "dirs": Array [], "filename": undefined, + "query": undefined, "root": "c:", } `; @@ -56,6 +61,7 @@ Object { "foo", ], "filename": undefined, + "query": undefined, "root": "c:", } `; @@ -68,6 +74,7 @@ Object { "baz", ], "filename": undefined, + "query": undefined, "root": "c:", } `; @@ -80,6 +87,7 @@ Object { "baz", ], "filename": undefined, + "query": undefined, "root": "c:", } `; @@ -88,6 +96,7 @@ exports[`parseFilePath() parses /foo 1`] = ` Object { "dirs": Array [], "filename": "foo", + "query": undefined, "root": "/", } `; @@ -99,6 +108,7 @@ Object { "bar", ], "filename": "baz", + "query": undefined, "root": "/", } `; @@ -110,6 +120,36 @@ Object { "bar", ], "filename": "baz.json", + "query": undefined, + "root": "/", +} +`; + +exports[`parseFilePath() parses /foo/bar/baz.json?light 1`] = ` +Object { + "dirs": Array [ + "foo", + "bar", + ], + "filename": "baz.json", + "query": Object { + "light": "", + }, + "root": "/", +} +`; + +exports[`parseFilePath() parses /foo/bar/baz.json?light=true&dark=false 1`] = ` +Object { + "dirs": Array [ + "foo", + "bar", + ], + "filename": "baz.json", + "query": Object { + "dark": "false", + "light": "true", + }, "root": "/", } `; @@ -121,6 +161,7 @@ Object { "bar", ], "filename": "baz.json", + "query": undefined, "root": "c:", } `; @@ -129,6 +170,7 @@ exports[`parseFilePath() parses c:\\foo 1`] = ` Object { "dirs": Array [], "filename": "foo", + "query": undefined, "root": "c:", } `; @@ -140,6 +182,7 @@ Object { "bar", ], "filename": "baz", + "query": undefined, "root": "c:", } `; @@ -151,6 +194,36 @@ Object { "bar", ], "filename": "baz.json", + "query": undefined, + "root": "c:", +} +`; + +exports[`parseFilePath() parses c:\\foo\\bar\\baz.json?dark 1`] = ` +Object { + "dirs": Array [ + "foo", + "bar", + ], + "filename": "baz.json", + "query": Object { + "dark": "", + }, + "root": "c:", +} +`; + +exports[`parseFilePath() parses c:\\foo\\bar\\baz.json?dark=true&light=false 1`] = ` +Object { + "dirs": Array [ + "foo", + "bar", + ], + "filename": "baz.json", + "query": Object { + "dark": "true", + "light": "false", + }, "root": "c:", } `; diff --git a/packages/kbn-optimizer/src/common/disallowed_syntax_plugin/disallowed_syntax.ts b/packages/kbn-optimizer/src/common/disallowed_syntax_plugin/disallowed_syntax.ts new file mode 100644 index 0000000000000..ba19bdc9c3be7 --- /dev/null +++ b/packages/kbn-optimizer/src/common/disallowed_syntax_plugin/disallowed_syntax.ts @@ -0,0 +1,194 @@ +/* + * 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 estree from 'estree'; + +export interface DisallowedSyntaxCheck { + name: string; + nodeType: estree.Node['type'] | Array; + test?: (n: any) => boolean | void; +} + +export const checks: DisallowedSyntaxCheck[] = [ + /** + * es2015 + */ + // https://github.com/estree/estree/blob/master/es2015.md#functions + { + name: '[es2015] generator function', + nodeType: ['FunctionDeclaration', 'FunctionExpression'], + test: (n: estree.FunctionDeclaration | estree.FunctionExpression) => !!n.generator, + }, + // https://github.com/estree/estree/blob/master/es2015.md#forofstatement + { + name: '[es2015] for-of statement', + nodeType: 'ForOfStatement', + }, + // https://github.com/estree/estree/blob/master/es2015.md#variabledeclaration + { + name: '[es2015] let/const variable declaration', + nodeType: 'VariableDeclaration', + test: (n: estree.VariableDeclaration) => n.kind === 'let' || n.kind === 'const', + }, + // https://github.com/estree/estree/blob/master/es2015.md#expressions + { + name: '[es2015] `super`', + nodeType: 'Super', + }, + // https://github.com/estree/estree/blob/master/es2015.md#expressions + { + name: '[es2015] ...spread', + nodeType: 'SpreadElement', + }, + // https://github.com/estree/estree/blob/master/es2015.md#arrowfunctionexpression + { + name: '[es2015] arrow function expression', + nodeType: 'ArrowFunctionExpression', + }, + // https://github.com/estree/estree/blob/master/es2015.md#yieldexpression + { + name: '[es2015] `yield` expression', + nodeType: 'YieldExpression', + }, + // https://github.com/estree/estree/blob/master/es2015.md#templateliteral + { + name: '[es2015] template literal', + nodeType: 'TemplateLiteral', + }, + // https://github.com/estree/estree/blob/master/es2015.md#patterns + { + name: '[es2015] destructuring', + nodeType: ['ObjectPattern', 'ArrayPattern', 'AssignmentPattern'], + }, + // https://github.com/estree/estree/blob/master/es2015.md#classes + { + name: '[es2015] class', + nodeType: [ + 'ClassDeclaration', + 'ClassExpression', + 'ClassBody', + 'MethodDefinition', + 'MetaProperty', + ], + }, + + /** + * es2016 + */ + { + name: '[es2016] exponent operator', + nodeType: 'BinaryExpression', + test: (n: estree.BinaryExpression) => n.operator === '**', + }, + { + name: '[es2016] exponent assignment', + nodeType: 'AssignmentExpression', + test: (n: estree.AssignmentExpression) => n.operator === '**=', + }, + + /** + * es2017 + */ + // https://github.com/estree/estree/blob/master/es2017.md#function + { + name: '[es2017] async function', + nodeType: ['FunctionDeclaration', 'FunctionExpression'], + test: (n: estree.FunctionDeclaration | estree.FunctionExpression) => n.async, + }, + // https://github.com/estree/estree/blob/master/es2017.md#awaitexpression + { + name: '[es2017] await expression', + nodeType: 'AwaitExpression', + }, + + /** + * es2018 + */ + // https://github.com/estree/estree/blob/master/es2018.md#statements + { + name: '[es2018] for-await-of statements', + nodeType: 'ForOfStatement', + test: (n: estree.ForOfStatement) => n.await, + }, + // https://github.com/estree/estree/blob/master/es2018.md#expressions + { + name: '[es2018] object spread properties', + nodeType: 'ObjectExpression', + test: (n: estree.ObjectExpression) => n.properties.some(p => p.type === 'SpreadElement'), + }, + // https://github.com/estree/estree/blob/master/es2018.md#template-literals + { + name: '[es2018] tagged template literal with invalid escape', + nodeType: 'TemplateElement', + test: (n: estree.TemplateElement) => n.value.cooked === null, + }, + // https://github.com/estree/estree/blob/master/es2018.md#patterns + { + name: '[es2018] rest properties', + nodeType: 'ObjectPattern', + test: (n: estree.ObjectPattern) => n.properties.some(p => p.type === 'RestElement'), + }, + + /** + * es2019 + */ + // https://github.com/estree/estree/blob/master/es2019.md#catchclause + { + name: '[es2019] catch clause without a binding', + nodeType: 'CatchClause', + test: (n: estree.CatchClause) => !n.param, + }, + + /** + * es2020 + */ + // https://github.com/estree/estree/blob/master/es2020.md#bigintliteral + { + name: '[es2020] bigint literal', + nodeType: 'Literal', + test: (n: estree.Literal) => typeof n.value === 'bigint', + }, + + /** + * webpack transforms import/export in order to support tree shaking and async imports + * + * // https://github.com/estree/estree/blob/master/es2020.md#importexpression + * { + * name: '[es2020] import expression', + * nodeType: 'ImportExpression', + * }, + * // https://github.com/estree/estree/blob/master/es2020.md#exportalldeclaration + * { + * name: '[es2020] export all declaration', + * nodeType: 'ExportAllDeclaration', + * }, + * + */ +]; + +export const checksByNodeType = new Map(); +for (const check of checks) { + const nodeTypes = Array.isArray(check.nodeType) ? check.nodeType : [check.nodeType]; + for (const nodeType of nodeTypes) { + if (!checksByNodeType.has(nodeType)) { + checksByNodeType.set(nodeType, []); + } + checksByNodeType.get(nodeType)!.push(check); + } +} diff --git a/packages/kbn-optimizer/src/common/disallowed_syntax_plugin/disallowed_syntax_plugin.ts b/packages/kbn-optimizer/src/common/disallowed_syntax_plugin/disallowed_syntax_plugin.ts new file mode 100644 index 0000000000000..7377462eb267b --- /dev/null +++ b/packages/kbn-optimizer/src/common/disallowed_syntax_plugin/disallowed_syntax_plugin.ts @@ -0,0 +1,73 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import webpack from 'webpack'; +import acorn from 'acorn'; +import * as AcornWalk from 'acorn-walk'; + +import { checksByNodeType, DisallowedSyntaxCheck } from './disallowed_syntax'; +import { parseFilePath } from '../parse_path'; + +export class DisallowedSyntaxPlugin { + apply(compiler: webpack.Compiler) { + compiler.hooks.normalModuleFactory.tap(DisallowedSyntaxPlugin.name, factory => { + factory.hooks.parser.for('javascript/auto').tap(DisallowedSyntaxPlugin.name, parser => { + parser.hooks.program.tap(DisallowedSyntaxPlugin.name, (program: acorn.Node) => { + const module = parser.state?.current; + if (!module || !module.resource) { + return; + } + + const resource: string = module.resource; + const { dirs } = parseFilePath(resource); + + if (!dirs.includes('node_modules')) { + return; + } + + const failedChecks = new Set(); + + AcornWalk.full(program, node => { + const checks = checksByNodeType.get(node.type as any); + if (!checks) { + return; + } + + for (const check of checks) { + if (!check.test || check.test(node)) { + failedChecks.add(check); + } + } + }); + + if (!failedChecks.size) { + return; + } + + // throw an error to trigger a parse failure, causing this module to be reported as invalid + throw new Error( + `disallowed syntax found in file ${resource}:\n - ${Array.from(failedChecks) + .map(c => c.name) + .join('\n - ')}` + ); + }); + }); + }); + } +} diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/index.ts b/packages/kbn-optimizer/src/common/disallowed_syntax_plugin/index.ts similarity index 92% rename from src/legacy/core_plugins/embeddable_api/public/np_ready/public/index.ts rename to packages/kbn-optimizer/src/common/disallowed_syntax_plugin/index.ts index 4b69616a777e9..ca5ba1b90fe95 100644 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/index.ts +++ b/packages/kbn-optimizer/src/common/disallowed_syntax_plugin/index.ts @@ -17,4 +17,4 @@ * under the License. */ -export * from '../../../../../../plugins/embeddable/public'; +export * from './disallowed_syntax_plugin'; diff --git a/packages/kbn-optimizer/src/common/index.ts b/packages/kbn-optimizer/src/common/index.ts index ea0560f132153..c51905be04565 100644 --- a/packages/kbn-optimizer/src/common/index.ts +++ b/packages/kbn-optimizer/src/common/index.ts @@ -26,3 +26,5 @@ export * from './ts_helpers'; export * from './rxjs_helpers'; export * from './array_helpers'; export * from './event_stream_helpers'; +export * from './disallowed_syntax_plugin'; +export * from './parse_path'; diff --git a/packages/kbn-optimizer/src/worker/parse_path.test.ts b/packages/kbn-optimizer/src/common/parse_path.test.ts similarity index 83% rename from packages/kbn-optimizer/src/worker/parse_path.test.ts rename to packages/kbn-optimizer/src/common/parse_path.test.ts index 72197e8c8fb07..61be44348cfae 100644 --- a/packages/kbn-optimizer/src/worker/parse_path.test.ts +++ b/packages/kbn-optimizer/src/common/parse_path.test.ts @@ -21,7 +21,15 @@ import { parseFilePath, parseDirPath } from './parse_path'; const DIRS = ['/', '/foo/bar/baz/', 'c:\\', 'c:\\foo\\bar\\baz\\']; const AMBIGUOUS = ['/foo', '/foo/bar/baz', 'c:\\foo', 'c:\\foo\\bar\\baz']; -const FILES = ['/foo/bar/baz.json', 'c:/foo/bar/baz.json', 'c:\\foo\\bar\\baz.json']; +const FILES = [ + '/foo/bar/baz.json', + 'c:/foo/bar/baz.json', + 'c:\\foo\\bar\\baz.json', + '/foo/bar/baz.json?light', + '/foo/bar/baz.json?light=true&dark=false', + 'c:\\foo\\bar\\baz.json?dark', + 'c:\\foo\\bar\\baz.json?dark=true&light=false', +]; describe('parseFilePath()', () => { it.each([...FILES, ...AMBIGUOUS])('parses %s', path => { diff --git a/packages/kbn-optimizer/src/worker/parse_path.ts b/packages/kbn-optimizer/src/common/parse_path.ts similarity index 83% rename from packages/kbn-optimizer/src/worker/parse_path.ts rename to packages/kbn-optimizer/src/common/parse_path.ts index 88152df55b84f..4c96417800252 100644 --- a/packages/kbn-optimizer/src/worker/parse_path.ts +++ b/packages/kbn-optimizer/src/common/parse_path.ts @@ -18,6 +18,7 @@ */ import normalizePath from 'normalize-path'; +import Qs from 'querystring'; /** * Parse an absolute path, supporting normalized paths from webpack, @@ -33,11 +34,19 @@ export function parseDirPath(path: string) { } export function parseFilePath(path: string) { - const normalized = normalizePath(path); + let normalized = normalizePath(path); + let query; + const queryIndex = normalized.indexOf('?'); + if (queryIndex !== -1) { + query = Qs.parse(normalized.slice(queryIndex + 1)); + normalized = normalized.slice(0, queryIndex); + } + const [root, ...others] = normalized.split('/'); return { root: root === '' ? '/' : root, dirs: others.slice(0, -1), + query, filename: others[others.length - 1] || undefined, }; } diff --git a/packages/kbn-optimizer/src/index.ts b/packages/kbn-optimizer/src/index.ts index 48777f1d54aaf..8026cf39db73d 100644 --- a/packages/kbn-optimizer/src/index.ts +++ b/packages/kbn-optimizer/src/index.ts @@ -20,3 +20,4 @@ export { OptimizerConfig } from './optimizer'; export * from './run_optimizer'; export * from './log_optimizer_state'; +export * from './common/disallowed_syntax_plugin'; diff --git a/packages/kbn-optimizer/src/worker/run_compilers.ts b/packages/kbn-optimizer/src/worker/run_compilers.ts index e87ddc7d0185c..0dfce4b5addba 100644 --- a/packages/kbn-optimizer/src/worker/run_compilers.ts +++ b/packages/kbn-optimizer/src/worker/run_compilers.ts @@ -27,10 +27,17 @@ import webpack, { Stats } from 'webpack'; import * as Rx from 'rxjs'; import { mergeMap, map, mapTo, takeUntil } from 'rxjs/operators'; -import { CompilerMsgs, CompilerMsg, maybeMap, Bundle, WorkerConfig, ascending } from '../common'; +import { + CompilerMsgs, + CompilerMsg, + maybeMap, + Bundle, + WorkerConfig, + ascending, + parseFilePath, +} from '../common'; import { getWebpackConfig } from './webpack.config'; import { isFailureStats, failedStatsToErrorMessage } from './webpack_helpers'; -import { parseFilePath } from './parse_path'; import { isExternalModule, isNormalModule, diff --git a/packages/kbn-optimizer/src/worker/webpack.config.ts b/packages/kbn-optimizer/src/worker/webpack.config.ts index dabfed7f9725c..9337daf419bfa 100644 --- a/packages/kbn-optimizer/src/worker/webpack.config.ts +++ b/packages/kbn-optimizer/src/worker/webpack.config.ts @@ -29,8 +29,7 @@ import webpackMerge from 'webpack-merge'; import { CleanWebpackPlugin } from 'clean-webpack-plugin'; import * as SharedDeps from '@kbn/ui-shared-deps'; -import { Bundle, WorkerConfig } from '../common'; -import { parseDirPath } from './parse_path'; +import { Bundle, WorkerConfig, parseDirPath, DisallowedSyntaxPlugin } from '../common'; const IS_CODE_COVERAGE = !!process.env.CODE_COVERAGE; const ISTANBUL_PRESET_PATH = require.resolve('@kbn/babel-preset/istanbul_preset'); @@ -77,7 +76,7 @@ export function getWebpackConfig(bundle: Bundle, worker: WorkerConfig) { ...SharedDeps.externals, }, - plugins: [new CleanWebpackPlugin()], + plugins: [new CleanWebpackPlugin(), new DisallowedSyntaxPlugin()], module: { // no parse rules for a few known large packages which have no require() statements diff --git a/packages/kbn-optimizer/src/worker/webpack_helpers.ts b/packages/kbn-optimizer/src/worker/webpack_helpers.ts index a11c85c64198e..e30920b960144 100644 --- a/packages/kbn-optimizer/src/worker/webpack_helpers.ts +++ b/packages/kbn-optimizer/src/worker/webpack_helpers.ts @@ -18,7 +18,6 @@ */ import webpack from 'webpack'; -import { defaults } from 'lodash'; // @ts-ignore import Stats from 'webpack/lib/Stats'; @@ -55,12 +54,14 @@ const STATS_WARNINGS_FILTER = new RegExp( ); export function failedStatsToErrorMessage(stats: webpack.Stats) { - const details = stats.toString( - defaults( - { colors: true, warningsFilter: STATS_WARNINGS_FILTER }, - Stats.presetToOptions('minimal') - ) - ); + const details = stats.toString({ + ...Stats.presetToOptions('minimal'), + colors: true, + warningsFilter: STATS_WARNINGS_FILTER, + errors: true, + errorDetails: true, + moduleTrace: true, + }); return `Optimizations failure.\n${details.split('\n').join('\n ')}`; } diff --git a/renovate.json5 b/renovate.json5 index 57f175d1afc8e..ffa006264873d 100644 --- a/renovate.json5 +++ b/renovate.json5 @@ -265,6 +265,14 @@ '(\\b|_)eslint(\\b|_)', ], }, + { + groupSlug: 'estree', + groupName: 'estree related packages', + packageNames: [ + 'estree', + '@types/estree', + ], + }, { groupSlug: 'fancy-log', groupName: 'fancy-log related packages', diff --git a/src/dev/ci_setup/setup.sh b/src/dev/ci_setup/setup.sh index 104a818f72a20..dc91d1cf23a37 100755 --- a/src/dev/ci_setup/setup.sh +++ b/src/dev/ci_setup/setup.sh @@ -16,6 +16,14 @@ echo " -- TEST_ES_SNAPSHOT_VERSION='$TEST_ES_SNAPSHOT_VERSION'" echo " -- installing node.js dependencies" yarn kbn bootstrap --prefer-offline +### +### Download es snapshots +### +echo " -- downloading es snapshot" +node scripts/es snapshot --download-only; +node scripts/es snapshot --license=oss --download-only; + + ### ### verify no git modifications ### diff --git a/src/legacy/core_plugins/embeddable_api/README.md b/src/legacy/core_plugins/embeddable_api/README.md deleted file mode 100644 index c2f67572df873..0000000000000 --- a/src/legacy/core_plugins/embeddable_api/README.md +++ /dev/null @@ -1,2 +0,0 @@ -- Embeddables have been moved to `/src/plugins/embeddable` NP plugin. -- This legacy plugin is still there to make necessary CSS working, but soon will be completely deleted. diff --git a/src/legacy/core_plugins/embeddable_api/package.json b/src/legacy/core_plugins/embeddable_api/package.json deleted file mode 100644 index f625408fe4c6c..0000000000000 --- a/src/legacy/core_plugins/embeddable_api/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "embeddable_api", - "version": "kibana" -} diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/mocks.ts b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/mocks.ts deleted file mode 100644 index 10510bff0c97e..0000000000000 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/mocks.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. - */ - -// eslint-disable-next-line -export * from '../../../../../../plugins/embeddable/public/mocks'; 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 55e1475fcb03a..86bce5997cdd2 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,6 @@ */ export { npSetup, npStart } from 'ui/new_platform'; -export { absoluteToParsedUrl } from 'ui/url/absolute_to_parsed_url'; export { configureAppAngularModule, migrateLegacyQuery, diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app.tsx b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app.tsx index e21033ffe10ec..cc7299b884890 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app.tsx +++ b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/dashboard_app.tsx @@ -21,7 +21,7 @@ import moment from 'moment'; import { Subscription } from 'rxjs'; import { History } from 'history'; -import { ViewMode } from '../../../../embeddable_api/public/np_ready/public'; +import { ViewMode } from '../../../../../../plugins/embeddable/public'; import { SavedObjectDashboard } from '../../../../../../plugins/dashboard/public'; import { DashboardAppState, SavedDashboardPanel } from './types'; import { 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 0c6686c993371..a39266ecd8db3 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 @@ -58,7 +58,7 @@ import { isErrorEmbeddable, openAddPanelFlyout, ViewMode, -} from '../../../../embeddable_api/public/np_ready/public'; +} from '../../../../../../plugins/embeddable/public'; import { NavAction, SavedDashboardPanel } from './types'; import { showOptionsPopover } from './top_nav/show_options_popover'; 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 b2a2f43b9152d..d3c3dc46c7057 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 @@ -24,7 +24,7 @@ import { } from './embeddable_saved_object_converters'; import { SavedDashboardPanel } from '../types'; import { DashboardPanelState } from 'src/plugins/dashboard/public'; -import { EmbeddableInput } from 'src/legacy/core_plugins/embeddable_api/public/np_ready/public'; +import { EmbeddableInput } from 'src/plugins/embeddable/public'; interface CustomInput extends EmbeddableInput { something: string; diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/url_helper.test.ts b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/url_helper.test.ts deleted file mode 100644 index 60ca1b39d29d6..0000000000000 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/url_helper.test.ts +++ /dev/null @@ -1,118 +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('../', () => ({ - DashboardConstants: { - ADD_EMBEDDABLE_ID: 'addEmbeddableId', - ADD_EMBEDDABLE_TYPE: 'addEmbeddableType', - }, -})); - -jest.mock('../legacy_imports', () => { - return { - absoluteToParsedUrl: jest.fn(() => { - return { - basePath: '/pep', - appId: 'kibana', - appPath: '/dashboard?addEmbeddableType=lens&addEmbeddableId=123eb456cd&x=1&y=2&z=3', - hostname: 'localhost', - port: 5601, - protocol: 'http:', - addQueryParameter: () => {}, - getAbsoluteUrl: () => { - return 'http://localhost:5601/pep/app/kibana#/dashboard?addEmbeddableType=lens&addEmbeddableId=123eb456cd&x=1&y=2&z=3'; - }, - }; - }), - }; -}); - -import { - addEmbeddableToDashboardUrl, - getLensUrlFromDashboardAbsoluteUrl, - getUrlVars, -} from './url_helper'; - -describe('Dashboard URL Helper', () => { - beforeEach(() => { - jest.resetModules(); - }); - - it('addEmbeddableToDashboardUrl', () => { - const id = '123eb456cd'; - const type = 'lens'; - const urlVars = { - x: '1', - y: '2', - z: '3', - }; - const basePath = '/pep'; - const url = - "http://localhost:5601/pep/app/kibana#/dashboard?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))&_a=(description:'',filters:!()"; - expect(addEmbeddableToDashboardUrl(url, basePath, id, urlVars, type)).toEqual( - `http://localhost:5601/pep/app/kibana#/dashboard?addEmbeddableType=${type}&addEmbeddableId=${id}&x=1&y=2&z=3` - ); - }); - - it('getUrlVars', () => { - let url = - "http://localhost:5601/app/kibana#/dashboard?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))&_a=(description:'',filters:!()"; - expect(getUrlVars(url)).toEqual({ - _g: '(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))', - _a: "(description:'',filters:!()", - }); - url = 'http://mybusiness.mydomain.com/app/kibana#/dashboard?x=y&y=z'; - expect(getUrlVars(url)).toEqual({ - x: 'y', - y: 'z', - }); - url = 'http://localhost:5601/app/kibana#/dashboard/777182'; - expect(getUrlVars(url)).toEqual({}); - url = - 'http://localhost:5601/app/kibana#/dashboard/777182?title=Some%20Dashboard%20With%20Spaces'; - expect(getUrlVars(url)).toEqual({ title: 'Some Dashboard With Spaces' }); - }); - - it('getLensUrlFromDashboardAbsoluteUrl', () => { - const id = '1244'; - const basePath = '/wev'; - let url = - "http://localhost:5601/wev/app/kibana#/dashboard?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))&_a=(description:'',filters:!()"; - expect(getLensUrlFromDashboardAbsoluteUrl(url, basePath, id)).toEqual( - 'http://localhost:5601/wev/app/kibana#/lens/edit/1244' - ); - - url = - "http://localhost:5601/wev/app/kibana#/dashboard/625357282?_a=(description:'',filters:!()&_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))"; - expect(getLensUrlFromDashboardAbsoluteUrl(url, basePath, id)).toEqual( - 'http://localhost:5601/wev/app/kibana#/lens/edit/1244' - ); - - url = 'http://myserver.mydomain.com:5601/wev/app/kibana#/dashboard/777182'; - expect(getLensUrlFromDashboardAbsoluteUrl(url, basePath, id)).toEqual( - 'http://myserver.mydomain.com:5601/wev/app/kibana#/lens/edit/1244' - ); - - url = - "http://localhost:5601/app/kibana#/dashboard?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))&_a=(description:'',filters:!()"; - expect(getLensUrlFromDashboardAbsoluteUrl(url, '', id)).toEqual( - 'http://localhost:5601/app/kibana#/lens/edit/1244' - ); - }); -}); diff --git a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/url_helper.ts b/src/legacy/core_plugins/kibana/public/dashboard/np_ready/url_helper.ts deleted file mode 100644 index 73383f2ff3f68..0000000000000 --- a/src/legacy/core_plugins/kibana/public/dashboard/np_ready/url_helper.ts +++ /dev/null @@ -1,100 +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 { parse } from 'url'; -import { absoluteToParsedUrl } from '../legacy_imports'; -import { DashboardConstants } from './dashboard_constants'; -/** - * Return query params from URL - * @param url given url - */ -export function getUrlVars(url: string): Record { - const vars: Record = {}; - for (const [, key, value] of url.matchAll(/[?&]+([^=&]+)=([^&]*)/gi)) { - vars[key] = decodeURIComponent(value); - } - return vars; -} - -/** * - * Returns dashboard URL with added embeddableType and embeddableId query params - * eg. - * input: url: http://localhost:5601/lib/app/kibana#/dashboard?_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now)), embeddableId: 12345, embeddableType: 'lens' - * output: http://localhost:5601/lib/app/kibana#dashboard?addEmbeddableType=lens&addEmbeddableId=12345&_g=(refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now)) - * @param url dasbhoard absolute url - * @param embeddableId id of the saved visualization - * @param basePath current base path - * @param urlVars url query params (optional) - * @param embeddableType 'lens' or 'visualization' (optional, default is 'lens') - */ -export function addEmbeddableToDashboardUrl( - url: string | undefined, - basePath: string, - embeddableId: string, - urlVars?: Record, - embeddableType?: string -): string | null { - if (!url) { - return null; - } - const dashboardUrl = getUrlWithoutQueryParams(url); - const dashboardParsedUrl = absoluteToParsedUrl(dashboardUrl, basePath); - if (urlVars) { - const keys = Object.keys(urlVars).sort(); - keys.forEach(key => { - dashboardParsedUrl.addQueryParameter(key, urlVars[key]); - }); - } - dashboardParsedUrl.addQueryParameter( - DashboardConstants.ADD_EMBEDDABLE_TYPE, - embeddableType || 'lens' - ); - dashboardParsedUrl.addQueryParameter(DashboardConstants.ADD_EMBEDDABLE_ID, embeddableId); - return dashboardParsedUrl.getAbsoluteUrl(); -} - -/** - * Return Lens URL from dashboard absolute URL - * @param dashboardAbsoluteUrl - * @param basePath current base path - * @param id Lens id - */ -export function getLensUrlFromDashboardAbsoluteUrl( - dashboardAbsoluteUrl: string | undefined | null, - basePath: string | null | undefined, - id: string -): string | null { - if (!dashboardAbsoluteUrl || basePath === null || basePath === undefined) { - return null; - } - const { host, protocol } = parse(dashboardAbsoluteUrl); - return `${protocol}//${host}${basePath}/app/kibana#/lens/edit/${id}`; -} - -/** - * Returns the portion of the URL without query params - * eg. - * input: http://localhost:5601/lib/app/kibana#/dashboard?param1=x¶m2=y¶m3=z - * output:http://localhost:5601/lib/app/kibana#/dashboard - * input: http://localhost:5601/lib/app/kibana#/dashboard/39292992?param1=x¶m2=y¶m3=z - * output: http://localhost:5601/lib/app/kibana#/dashboard/39292992 - * @param url url to parse - */ -function getUrlWithoutQueryParams(url: string): string { - return url.split('?')[0]; -} diff --git a/src/legacy/core_plugins/kibana/public/discover/__tests__/directives/css_truncate.js b/src/legacy/core_plugins/kibana/public/discover/__tests__/directives/css_truncate.js deleted file mode 100644 index 8dea9c61475db..0000000000000 --- a/src/legacy/core_plugins/kibana/public/discover/__tests__/directives/css_truncate.js +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import angular from 'angular'; -import expect from '@kbn/expect'; -import ngMock from 'ng_mock'; -import { pluginInstance } from 'plugins/kibana/discover/legacy'; - -let $parentScope; - -let $scope; - -let $elem; - -const init = function(expandable) { - // Load the application - pluginInstance.initializeServices(); - pluginInstance.initializeInnerAngular(); - ngMock.module('app/discover'); - - // Create the scope - ngMock.inject(function($rootScope, $compile) { - // Give us a scope - $parentScope = $rootScope; - - // Create the element - $elem = angular.element( - 'this isnt important' - ); - - // And compile it - $compile($elem)($parentScope); - - // Fire a digest cycle - $elem.scope().$digest(); - - // Grab the isolate scope so we can test it - $scope = $elem.isolateScope(); - }); -}; - -describe('cssTruncate directive', function() { - describe('expandable', function() { - beforeEach(function() { - init(true); - }); - - it('should set text-overflow to ellipsis and whitespace to nowrap', function(done) { - expect($elem.css('text-overflow')).to.be('ellipsis'); - expect($elem.css('white-space')).to.be('nowrap'); - done(); - }); - - it('should set white-space to normal when clicked, and back to nowrap when clicked again', function(done) { - $scope.toggle(); - expect($elem.css('white-space')).to.be('normal'); - - $scope.toggle(); - expect($elem.css('white-space')).to.be('nowrap'); - done(); - }); - }); -}); diff --git a/src/legacy/core_plugins/kibana/public/discover/__tests__/directives/discover_field.js b/src/legacy/core_plugins/kibana/public/discover/__tests__/directives/discover_field.js deleted file mode 100644 index 6ffda87ac2be8..0000000000000 --- a/src/legacy/core_plugins/kibana/public/discover/__tests__/directives/discover_field.js +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import angular from 'angular'; -import _ from 'lodash'; -import sinon from 'sinon'; -import ngMock from 'ng_mock'; -import expect from '@kbn/expect'; -import { pluginInstance } from 'plugins/kibana/discover/legacy'; -import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; - -// Load the kibana app dependencies. - -describe('discoverField', function() { - let $scope; - let indexPattern; - let $elem; - beforeEach(() => pluginInstance.initializeServices()); - beforeEach(() => pluginInstance.initializeInnerAngular()); - beforeEach(ngMock.module('app/discover')); - beforeEach( - ngMock.inject(function(Private, $rootScope, $compile) { - $elem = angular.element(` - - `); - indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider); - - _.assign($rootScope, { - field: indexPattern.fields.getByName('extension'), - addField: sinon.spy(() => ($rootScope.field.display = true)), - removeField: sinon.spy(() => ($rootScope.field.display = false)), - showDetails: sinon.spy(() => ($rootScope.field.details = { exists: true })), - }); - - $compile($elem)($rootScope); - - $scope = $elem.isolateScope(); - $scope.$digest(); - sinon.spy($scope, 'toggleDetails'); - }) - ); - - afterEach(function() { - $scope.toggleDetails.restore(); - $scope.$destroy(); - }); - - describe('toggleDisplay', function() { - it('should exist', function() { - expect($scope.toggleDisplay).to.be.a(Function); - }); - - it('should call onAddField or onRemoveField depending on the display state', function() { - $scope.toggleDisplay($scope.field); - expect($scope.onAddField.callCount).to.be(1); - expect($scope.onAddField.firstCall.args).to.eql([$scope.field.name]); - - $scope.toggleDisplay($scope.field); - expect($scope.onRemoveField.callCount).to.be(1); - expect($scope.onRemoveField.firstCall.args).to.eql([$scope.field.name]); - }); - - it('should call toggleDetails when currently showing the details', function() { - $scope.toggleDetails($scope.field); - $scope.toggleDisplay($scope.field); - expect($scope.toggleDetails.callCount).to.be(2); - }); - }); - - describe('toggleDetails', function() { - it('should notify the parent when showing the details', function() { - $scope.toggleDetails($scope.field); - expect($scope.onShowDetails.callCount).to.be(1); - }); - }); -}); diff --git a/src/legacy/core_plugins/kibana/public/discover/__tests__/directives/field_chooser.js b/src/legacy/core_plugins/kibana/public/discover/__tests__/directives/field_chooser.js deleted file mode 100644 index 47392c541890e..0000000000000 --- a/src/legacy/core_plugins/kibana/public/discover/__tests__/directives/field_chooser.js +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import angular from 'angular'; -import ngMock from 'ng_mock'; -import _ from 'lodash'; -import sinon from 'sinon'; -import expect from '@kbn/expect'; -import $ from 'jquery'; -import { pluginInstance } from 'plugins/kibana/discover/legacy'; -import FixturesHitsProvider from 'fixtures/hits'; -import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; -import { SimpleSavedObject } from '../../../../../../../core/public'; - -// Load the kibana app dependencies. - -let $parentScope; -let $scope; -let hits; -let indexPattern; -let indexPatternList; - -// Sets up the directive, take an element, and a list of properties to attach to the parent scope. -const init = function($elem, props) { - ngMock.inject(function($rootScope, $compile, $timeout) { - $parentScope = $rootScope; - _.assign($parentScope, props); - $compile($elem)($parentScope); - - // Required for test to run solo. Sigh - $timeout(() => $elem.scope().$digest(), 0); - - $scope = $elem.isolateScope(); - }); -}; - -const destroy = function() { - $scope.$destroy(); - $parentScope.$destroy(); -}; - -describe('discover field chooser directives', function() { - const $elem = angular.element(` - - `); - beforeEach(() => pluginInstance.initializeServices()); - beforeEach(() => pluginInstance.initializeInnerAngular()); - - beforeEach(ngMock.module('app/discover')); - - beforeEach( - ngMock.inject(function(Private) { - hits = Private(FixturesHitsProvider); - indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider); - indexPatternList = [ - new SimpleSavedObject(undefined, { id: '0', attributes: { title: 'b' } }), - new SimpleSavedObject(undefined, { id: '1', attributes: { title: 'a' } }), - new SimpleSavedObject(undefined, { id: '2', attributes: { title: 'c' } }), - ]; - - const fieldCounts = _.transform( - hits, - function(counts, hit) { - _.keys(indexPattern.flattenHit(hit)).forEach(function(key) { - counts[key] = (counts[key] || 0) + 1; - }); - }, - {} - ); - - init($elem, { - columns: [], - toggle: sinon.spy(), - hits: hits, - fieldCounts: fieldCounts, - addField: sinon.spy(), - addFilter: sinon.spy(), - indexPattern: indexPattern, - indexPatternList: indexPatternList, - removeField: sinon.spy(), - }); - - $scope.$digest(); - }) - ); - - afterEach(() => destroy()); - - const getSections = function(ctx) { - return { - selected: $('.dscFieldList--selected', ctx), - popular: $('.dscFieldList--popular', ctx), - unpopular: $('.dscFieldList--unpopular', ctx), - }; - }; - - describe('Field listing', function() { - it('should have Selected Fields, Fields and Popular Fields sections', function() { - const headers = $elem.find('.sidebar-list-header'); - expect(headers.length).to.be(3); - }); - - it('should have 2 popular fields, 1 unpopular field and no selected fields', function() { - const section = getSections($elem); - const popular = find('popular'); - const unpopular = find('unpopular'); - - expect(section.selected.find('li').length).to.be(0); - - expect(popular).to.contain('ssl'); - expect(popular).to.contain('@timestamp'); - expect(popular).to.not.contain('ip\n'); - - expect(unpopular).to.contain('extension'); - expect(unpopular).to.contain('machine.os'); - expect(unpopular).to.not.contain('ssl'); - - function find(popularity) { - return section[popularity] - .find('.dscFieldName') - .map((i, el) => $(el).text()) - .toArray(); - } - }); - - it('should show the popular fields header if there are popular fields', function() { - const section = getSections($elem); - expect(section.popular.hasClass('ng-hide')).to.be(false); - expect(section.popular.find('li:not(.sidebar-list-header)').length).to.be.above(0); - }); - - it('should not show the popular fields if there are not any', function() { - // Re-init - destroy(); - - _.each(indexPattern.fields, function(field) { - field.$$spec.count = 0; - }); // Reset the popular fields - init($elem, { - columns: [], - toggle: sinon.spy(), - hits: require('fixtures/hits'), - filter: sinon.spy(), - indexPattern: indexPattern, - }); - - const section = getSections($elem); - - $scope.$digest(); - expect(section.popular.hasClass('ng-hide')).to.be(true); - expect(section.popular.find('li:not(.sidebar-list-header)').length).to.be(0); - }); - - it('should move the field into selected when it is added to the columns array', function() { - const section = getSections($elem); - $scope.columns.push('bytes'); - $scope.$digest(); - - expect(section.selected.text()).to.contain('bytes'); - expect(section.popular.text()).to.not.contain('bytes'); - - $scope.columns.push('ip'); - $scope.$digest(); - expect(section.selected.text()).to.contain('ip\n'); - expect(section.unpopular.text()).to.not.contain('ip\n'); - - expect(section.popular.text()).to.contain('ssl'); - }); - }); - - describe('details processing', function() { - let field; - function getField() { - return _.find($scope.fields, { name: 'bytes' }); - } - - beforeEach(function() { - field = getField(); - }); - - it('should have a computeDetails function', function() { - expect($scope.computeDetails).to.be.a(Function); - }); - - it('should increase the field popularity when called', function() { - indexPattern.popularizeField = sinon.spy(); - $scope.computeDetails(field); - expect(indexPattern.popularizeField.called).to.be(true); - }); - - it('should append a details object to the field', function() { - $scope.computeDetails(field); - expect(field.details).to.not.be(undefined); - }); - - it('should delete the field details if they already exist', function() { - $scope.computeDetails(field); - expect(field.details).to.not.be(undefined); - $scope.computeDetails(field); - expect(field.details).to.be(undefined); - }); - - it('... unless recompute is true', function() { - $scope.computeDetails(field); - expect(field.details).to.not.be(undefined); - $scope.computeDetails(field, true); - expect(field.details).to.not.be(undefined); - }); - - it('should create buckets with formatted and raw values', function() { - $scope.computeDetails(field); - expect(field.details.buckets).to.not.be(undefined); - expect(field.details.buckets[0].value).to.be(40.141592); - }); - - it('should recalculate the details on open fields if the hits change', function() { - $scope.hits = [{ _source: { bytes: 1024 } }]; - $scope.$apply(); - - field = getField(); - $scope.computeDetails(field); - expect(getField().details.total).to.be(1); - - $scope.hits = [{ _source: { notbytes: 1024 } }]; - $scope.$apply(); - field = getField(); - expect(field.details).to.not.have.property('total'); - }); - }); -}); diff --git a/src/legacy/core_plugins/kibana/public/discover/__tests__/doc_table/doc_table.js b/src/legacy/core_plugins/kibana/public/discover/__tests__/doc_table/doc_table.js index 6b97da79fc589..9e74df08233da 100644 --- a/src/legacy/core_plugins/kibana/public/discover/__tests__/doc_table/doc_table.js +++ b/src/legacy/core_plugins/kibana/public/discover/__tests__/doc_table/doc_table.js @@ -61,6 +61,7 @@ const destroy = function() { describe('docTable', function() { let $elem; beforeEach(() => pluginInstance.initializeInnerAngular()); + beforeEach(() => pluginInstance.initializeServices()); beforeEach(ngMock.module('app/discover')); beforeEach(function() { $elem = angular.element(` diff --git a/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts b/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts index 031e10e99289f..607d79b81618e 100644 --- a/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts +++ b/src/legacy/core_plugins/kibana/public/discover/get_inner_angular.ts @@ -27,7 +27,7 @@ import { CoreStart, LegacyCoreStart } from 'kibana/public'; import { DataPublicPluginStart } from '../../../../../plugins/data/public'; import { Storage } from '../../../../../plugins/kibana_utils/public'; import { NavigationPublicPluginStart as NavigationStart } from '../../../../../plugins/navigation/public'; -import { createDocTableDirective } from './np_ready/angular/doc_table/doc_table'; +import { createDocTableDirective } from './np_ready/angular/doc_table'; import { createTableHeaderDirective } from './np_ready/angular/doc_table/components/table_header'; import { createToolBarPagerButtonsDirective, @@ -37,18 +37,8 @@ import { createTableRowDirective } from './np_ready/angular/doc_table/components import { createPagerFactory } from './np_ready/angular/doc_table/lib/pager/pager_factory'; import { createInfiniteScrollDirective } from './np_ready/angular/doc_table/infinite_scroll'; import { createDocViewerDirective } from './np_ready/angular/doc_viewer'; -import { createFieldSearchDirective } from './np_ready/components/field_chooser/discover_field_search_directive'; -import { createIndexPatternSelectDirective } from './np_ready/components/field_chooser/discover_index_pattern_directive'; -import { createStringFieldProgressBarDirective } from './np_ready/components/field_chooser/string_progress_bar'; -// @ts-ignore -import { FieldNameDirectiveProvider } from './np_ready/angular/directives/field_name'; -// @ts-ignore -import { createFieldChooserDirective } from './np_ready/components/field_chooser/field_chooser'; -// @ts-ignore -import { createDiscoverFieldDirective } from './np_ready/components/field_chooser/discover_field'; import { CollapsibleSidebarProvider } from './np_ready/angular/directives/collapsible_sidebar/collapsible_sidebar'; import { DiscoverStartPlugins } from './plugin'; -import { createCssTruncateDirective } from './np_ready/angular/directives/css_truncate'; // @ts-ignore import { FixedScrollProvider } from './np_ready/angular/directives/fixed_scroll'; // @ts-ignore @@ -65,6 +55,7 @@ import { createTopNavDirective, createTopNavHelper, } from '../../../../../plugins/kibana_legacy/public'; +import { createDiscoverSidebarDirective } from './np_ready/components/sidebar'; /** * returns the main inner angular module, it contains all the parts of Angular Discover @@ -125,7 +116,6 @@ export function initializeInnerAngularModule( ]) .config(watchMultiDecorator) .directive('icon', reactDirective => reactDirective(EuiIcon)) - .directive('fieldName', FieldNameDirectiveProvider) .directive('renderComplete', createRenderCompleteDirective) .service('debounce', ['$timeout', DebounceProviderTimeout]); } @@ -149,16 +139,10 @@ export function initializeInnerAngularModule( .run(registerListenEventListener) .directive('icon', reactDirective => reactDirective(EuiIcon)) .directive('kbnAccessibleClick', KbnAccessibleClickProvider) - .directive('fieldName', FieldNameDirectiveProvider) .directive('collapsibleSidebar', CollapsibleSidebarProvider) - .directive('cssTruncate', createCssTruncateDirective) .directive('fixedScroll', FixedScrollProvider) .directive('renderComplete', createRenderCompleteDirective) - .directive('discoverFieldSearch', createFieldSearchDirective) - .directive('discoverIndexPatternSelect', createIndexPatternSelectDirective) - .directive('stringFieldProgressBar', createStringFieldProgressBarDirective) - .directive('discoverField', createDiscoverFieldDirective) - .directive('discFieldChooser', createFieldChooserDirective) + .directive('discoverSidebar', createDiscoverSidebarDirective) .service('debounce', ['$timeout', DebounceProviderTimeout]); } 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 2ceb06f325a9e..55f369eaecd2c 100644 --- a/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts +++ b/src/legacy/core_plugins/kibana/public/discover/kibana_services.ts @@ -16,7 +16,6 @@ * specific language governing permissions and limitations * under the License. */ -import angular from 'angular'; // just used in embeddables and discover controller import { DiscoverServices } from './build_services'; let angularModule: any = null; @@ -52,7 +51,6 @@ export const [getUrlTracker, setUrlTracker] = createGetterSetter<{ }>('urlTracker'); // EXPORT legacy static dependencies, should be migrated when available in a new version; -export { angular }; export { wrapInI18nContext } from 'ui/i18n'; import { search } from '../../../../../plugins/data/public'; import { createGetterSetter } from '../../../../../plugins/kibana_utils/common'; diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/_discover.scss b/src/legacy/core_plugins/kibana/public/discover/np_ready/_discover.scss index 62e7a96ed80cf..8eaa66cf58624 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/_discover.scss +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/_discover.scss @@ -1,9 +1,5 @@ discover-app { flex-grow: 1; - - .sidebar-container { - background-color: transparent; - } } .dscHistogram { @@ -12,22 +8,6 @@ discover-app { padding: $euiSizeS; } -// SASSTODO: replace the margin-top value with a variable -.dscSidebar__listHeader { - margin-top: 5px; -} - -.dscFieldList--popular { - padding-top: $euiSizeS; -} - -.dscFieldList--selected, -.dscFieldList--unpopular, -.dscFieldList--popular { - padding-left: $euiSizeS; - padding-right: $euiSizeS; -} - // SASSTODO: replace the z-index value with a variable .dscWrapper { padding-right: $euiSizeS; @@ -109,107 +89,6 @@ discover-app { text-align: center; } -/** - * 1. Override sidebar-item-title styles. - */ -.dscSidebarItem { - position: relative; - display: flex; - align-items: center; - justify-content: space-between; - padding-top: 0 !important; /* 1 */ - padding-bottom: 0 !important; /* 1 */ - height: $euiSizeXL; - - &:hover, - &:focus { - .dscSidebarItem__action { - opacity: 1; - } - } -} - -.dscSidebarItem--active { - background: shade($euiColorLightestShade, 5%); - color: $euiColorFullShade; - font-weight: bold; -} - -/** - * 1. Truncate long text so it doesn't push the actions outside of the container. - */ -.dscSidebarItem__label { - overflow: hidden; /* 1 */ - text-overflow: ellipsis; /* 1 */ -} - -/** - * 1. Only visually hide the action, so that it's still accessible to screen readers. - * 2. When tabbed to, this element needs to be visible for keyboard accessibility. - */ -.dscSidebarItem__action { - opacity: 0; /* 1 */ - - &:focus { - opacity: 1; /* 2 */ - } -} - -.dscFieldSearch { - padding: $euiSizeS; -} - -.dscFieldFilter { - margin-top: $euiSizeS; -} - -.dscFieldDetails { - padding: $euiSizeS; - background-color: $euiColorLightestShade; - color: $euiTextColor; -} - -// SASSTODO: replace the padding and margin values with variables -.dscFieldDetails__progress { - background-color: $euiColorEmptyShade; - color: $euiColorDarkShade; - padding: $euiSizeXS; -} - -// SASSTODO: replace the margin-top value with a variable -.dscFieldDetailsItem { - margin-top: 5px; -} - -.dscFieldDetails__filter { - cursor: pointer; -} - -.dscFieldDetailsItem__title { - line-height: 1.5; - display: flex; - align-items: center; - justify-content: space-between; -} - -/** - * 1. If the field name is very long, don't let it squash the buttons. - */ -.dscFieldDetailsItem__buttonGroup { - flex: 0 0 auto; /* 1 */ -} - -.dscFieldDetailsItem__button { - appearance: none; - border: none; - padding: 0; - background-color: transparent; -} - -.dscFieldName--noResults { - color: $euiColorDarkShade; -} - .dscResults { h3 { margin: -20px 0 10px 0; diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/css_truncate.ts b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/css_truncate.ts deleted file mode 100644 index 6aa645ea9368e..0000000000000 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/css_truncate.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 function createCssTruncateDirective() { - return { - restrict: 'A', - scope: {}, - link: ($scope: any, $elem: any, attrs: any) => { - $elem.css({ - overflow: 'hidden', - 'white-space': 'nowrap', - 'text-overflow': 'ellipsis', - 'word-break': 'break-all', - }); - - if (attrs.cssTruncateExpandable != null) { - $scope.$watch( - function() { - return $elem.html(); - }, - function() { - if ($elem[0].offsetWidth < $elem[0].scrollWidth) { - $elem.css({ cursor: 'pointer' }); - $elem.bind('click', function() { - $scope.toggle(); - }); - } - } - ); - } - - $scope.toggle = function() { - if ($elem.css('white-space') !== 'normal') { - $elem.css({ 'white-space': 'normal' }); - } else { - $elem.css({ 'white-space': 'nowrap' }); - } - }; - - $scope.$on('$destroy', function() { - $elem.unbind('click'); - $elem.unbind('mouseenter'); - }); - }, - }; -} diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name.js b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name.js deleted file mode 100644 index 47e50f3cc3d4b..0000000000000 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/field_name.js +++ /dev/null @@ -1,35 +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 { FieldName } from '../../../../../../../../plugins/discover/public'; -import { getServices, wrapInI18nContext } from '../../../kibana_services'; - -export function FieldNameDirectiveProvider(reactDirective) { - return reactDirective( - wrapInI18nContext(FieldName), - [ - ['field', { watchDepth: 'collection' }], - ['fieldName', { watchDepth: 'reference' }], - ['fieldType', { watchDepth: 'reference' }], - ], - { restrict: 'AE' }, - { - useShortDots: getServices().uiSettings.get('shortDots:enable'), - } - ); -} diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.html b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.html index e9338b8bd57cc..fb38f3e7d4c49 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.html +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.html @@ -20,20 +20,21 @@

{{screenTitle}}

-