diff --git a/dev_docs/contributing/how_we_use_github.mdx b/dev_docs/contributing/how_we_use_github.mdx new file mode 100644 index 0000000000000..f18bcbcf556f5 --- /dev/null +++ b/dev_docs/contributing/how_we_use_github.mdx @@ -0,0 +1,155 @@ +--- +id: kibGitHub +slug: /kibana-dev-docs/github +title: How we use Github +summary: Forking, branching, committing and using labels in the Kibana GitHub repo +date: 2021-09-16 +tags: ['contributor', 'dev', 'github', 'getting started', 'onboarding', 'kibana'] +--- + +## Forking + +We follow the [GitHub forking model](https://help.github.com/articles/fork-a-repo/) for collaborating on Kibana code. This model assumes that you have a remote called upstream which points to the official Kibana repo, which we’ll refer to in later code snippets. + +## Branching + +At Elastic, all products in the stack, including Kibana, are released at the same time with the same version number. Most of these projects have the following branching strategy: + +- master is the next major version. +- `.x` is the next minor version. +- `.` is the next release of a minor version, including patch releases. + +As an example, let’s assume that the 7.x branch is currently a not-yet-released 7.6.0. Once 7.6.0 has reached feature freeze, it will be branched to 7.6 and 7.x will be updated to reflect 7.7.0. The release of 7.6.0 and subsequent patch releases will be cut from the 7.6 branch. At any time, you can verify the current version of a branch by inspecting the version attribute in the package.json file within the Kibana source. + +Pull requests are made into the master branch and then backported when it is safe and appropriate. + +- Breaking changes do not get backported and only go into master. +- All non-breaking changes can be backported to the `.x` branch. +- Features should not be backported to a `.` branch. +- Bug fixes can be backported to a `.` branch if the changes are safe and appropriate. Safety is a judgment call you make based on factors like the bug’s severity, test coverage, confidence in the changes, etc. Your reasoning should be included in the pull request description. +- Documentation changes can be backported to any branch at any time. + +## Commits and Merging + +- Feel free to make as many commits as you want, while working on a branch. +- When submitting a PR for review, please perform an interactive rebase to present a logical history that’s easy for the reviewers to follow. +- Please use your commit messages to include helpful information on your changes, e.g. changes to APIs, UX changes, bugs fixed, and an explanation of why you made the changes that you did. +- Resolve merge conflicts by rebasing the target branch over your feature branch, and force-pushing (see below for instructions). +- When merging, we’ll squash your commits into a single commit. + +### Rebasing and fixing merge conflicts + +Rebasing can be tricky, and fixing merge conflicts can be even trickier because it involves force pushing. This is all compounded by the fact that attempting to push a rebased branch remotely will be rejected by git, and you’ll be prompted to do a pull, which is not at all what you should do (this will really mess up your branch’s history). + +Here’s how you should rebase master onto your branch, and how to fix merge conflicts when they arise. + +First, make sure master is up-to-date. + +```bash +git checkout master +git fetch upstream +git rebase upstream/master +``` + +Then, check out your branch and rebase master on top of it, which will apply all of the new commits on master to your branch, and then apply all of your branch’s new commits after that. + +```bash +git checkout name-of-your-branch +git rebase master +``` + +You want to make sure there are no merge conflicts. If there are merge conflicts, git will pause the rebase and allow you to fix the conflicts before continuing. + +You can use git status to see which files contain conflicts. They’ll be the ones that aren’t staged for commit. Open those files, and look for where git has marked the conflicts. Resolve the conflicts so that the changes you want to make to the code have been incorporated in a way that doesn’t destroy work that’s been done in master. Refer to master’s commit history on GitHub if you need to gain a better understanding of how code is conflicting and how best to resolve it. + +Once you’ve resolved all of the merge conflicts, use git add -A to stage them to be committed, and then use git rebase --continue to tell git to continue the rebase. + +When the rebase has completed, you will need to force push your branch because the history is now completely different than what’s on the remote. This is potentially dangerous because it will completely overwrite what you have on the remote, so you need to be sure that you haven’t lost any work when resolving merge conflicts. (If there weren’t any merge conflicts, then you can force push without having to worry about this.) + +```bash +git push origin name-of-your-branch --force +``` + +This will overwrite the remote branch with what you have locally. You’re done! + +**Note that you should not run git pull**, for example in response to a push rejection like this: + +```bash +! [rejected] name-of-your-branch -> name-of-your-branch (non-fast-forward) +error: failed to push some refs to 'https://github.com/YourGitHubHandle/kibana.git' +hint: Updates were rejected because the tip of your current branch is behind +hint: its remote counterpart. Integrate the remote changes (e.g. +hint: 'git pull ...') before pushing again. +hint: See the 'Note about fast-forwards' in 'git push --help' for details. +``` + +Assuming you’ve successfully rebased and you’re happy with the code, you should force push instead. + +## Creating a pull request + +See [Submitting a pull request](https://www.elastic.co/guide/en/kibana/master/development-pull-request.html) for the next steps on getting your code changes merged into Kibana. + +## Labels + +The following information notes how we use GitHub labels in Kibana. Note that only internal Elasticians are able to create and assign labels to issues, but for searching purposes, the information is likely useful for external developers as well. + +Many of our labels follow the pattern of `{key}:{value}`. + + +Use PascalCase when creating new labels. + +Teams can create labels at their own discretion, but we have over 600 labels at the time of this writing. +Consider using an existing convention before creating a new one. If you think a new label or convention +would be useful to all teams, talk to your team or tech lead about getting it added here. + + + +### Team labels + +Examples: `Team:Security`, `Team:Operations`. + +These labels map the issue to the team that owns the particular area. Part of the responsibilities of +(todo) is to ensure every issue has at least a team or a project +label. + + + View our org chart [here](https://wiki.elastic.co/display/DEV/Kibana+Team+Organization) to view + all our teams and appropriate contacts. + + +### Feature labels + +Examples: `Feature:Lens`, `Feature:TSVB`, `Feature:Vega`. + +Feature labels break down architectural domains that are owned by a given team. + +### Project labels + +Examples: `Project:RuntimeFields`, `Project:MakeItSlow`. + +Sometimes issues span multiple teams, that is often when Project labels are more appropriate. To avoid too much noise, +these should be used for high visibility projects. Try not to use project labels for small, single team projects, where a team +and feature label would be applicable. Use your best judgement when determining whether to add a new project label. + +### Needed For labels (`NeededFor:{Team}`) + +Examples: `NeededFor:APM`, `NeededFor:AppServices`. + +We use these labels to help us organize internal dependencies. An issue with the labels +`NeededFor:APM` and `Team:AppServices` means APM has a dependency on the App services team. The owning team +can filter on these labels during roadmap prioritization, and the dependent team can use these labels to +search and view the status of its dependencies. To avoid noise, use these labels for high priority requests that +need to be taken into account in roadmap planning. A low priority item that can be prioritized along with +other community requests does not need this label, as part of its usefulness is helping teams wade through the noise +of external feature requests. + +### Version labels + +Examples: `v7.9.2`, `v8.0` + +We use version labels on PRs to indicate which versions a PR will be merged into. For issues, +teams use these labels inconsistently. On a bug, it might mean the version the bug was found in, or +it might mean the version the team is tentatively planning to merge a fix. + +Consult the owning team if you have a question about how a version label is meant +to be used on an issue. diff --git a/packages/kbn-test/src/functional_test_runner/functional_test_runner.ts b/packages/kbn-test/src/functional_test_runner/functional_test_runner.ts index 0a2dba60742ad..b5d379d3426e7 100644 --- a/packages/kbn-test/src/functional_test_runner/functional_test_runner.ts +++ b/packages/kbn-test/src/functional_test_runner/functional_test_runner.ts @@ -5,7 +5,6 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import { relative } from 'path'; import { ToolingLog } from '@kbn/dev-utils'; @@ -121,9 +120,6 @@ export class FunctionalTestRunner { throw new Error('No tests defined.'); } - // eslint-disable-next-line - console.log(`--- Running ${relative(process.cwd(), this.configFile)}`); - const dockerServers = new DockerServersService( config.get('dockerServers'), this.log, diff --git a/packages/kbn-test/src/functional_tests/tasks.ts b/packages/kbn-test/src/functional_tests/tasks.ts index 76443293be75c..d45f8656ed728 100644 --- a/packages/kbn-test/src/functional_tests/tasks.ts +++ b/packages/kbn-test/src/functional_tests/tasks.ts @@ -9,7 +9,7 @@ import { relative } from 'path'; import * as Rx from 'rxjs'; import { startWith, switchMap, take } from 'rxjs/operators'; -import { withProcRunner, ToolingLog } from '@kbn/dev-utils'; +import { withProcRunner, ToolingLog, REPO_ROOT } from '@kbn/dev-utils'; import dedent from 'dedent'; import { @@ -72,37 +72,49 @@ export async function runTests(options: RunTestsParams) { log.warning('❗️❗️❗️'); } - for (const configPath of options.configs) { - const log = options.createLogger(); - const opts = { - ...options, - log, - }; - - log.info('Running', configPath); - log.indent(2); + const log = options.createLogger(); - if (options.assertNoneExcluded) { - await assertNoneExcluded({ configPath, options: opts }); + if (options.assertNoneExcluded) { + log.write('--- asserting that all tests belong to a ciGroup'); + for (const configPath of options.configs) { + log.info('loading', configPath); + log.indent(4); + try { + await assertNoneExcluded({ configPath, options: { ...options, log } }); + } finally { + log.indent(-4); + } continue; } - if (!(await hasTests({ configPath, options: opts }))) { - log.info('Skipping', configPath, 'since all tests are excluded'); - continue; + return; + } + + log.write('--- determining which ftr configs to run'); + const configPathsWithTests: string[] = []; + for (const configPath of options.configs) { + log.info('testing', configPath); + log.indent(4); + try { + if (await hasTests({ configPath, options: { ...options, log } })) { + configPathsWithTests.push(configPath); + } + } finally { + log.indent(-4); } + } - // eslint-disable-next-line no-console - console.log(`--- Running ${relative(process.cwd(), configPath)}`); + for (const configPath of configPathsWithTests) { + log.write(`--- Running ${relative(REPO_ROOT, configPath)}`); await withProcRunner(log, async (procs) => { const config = await readConfigFile(log, configPath); let es; try { - es = await runElasticsearch({ config, options: opts }); - await runKibanaServer({ procs, config, options: opts }); - await runFtr({ configPath, options: opts }); + es = await runElasticsearch({ config, options: { ...options, log } }); + await runKibanaServer({ procs, config, options }); + await runFtr({ configPath, options: { ...options, log } }); } finally { try { const delay = config.get('kbnTestServer.delayShutdown'); diff --git a/src/core/public/http/fetch.test.ts b/src/core/public/http/fetch.test.ts index 7e3cd9019b08d..d1af183e9e180 100644 --- a/src/core/public/http/fetch.test.ts +++ b/src/core/public/http/fetch.test.ts @@ -245,32 +245,6 @@ describe('Fetch', () => { }); }); - // Deprecated header used by legacy platform pre-7.7. Remove in 8.x. - it('should not allow overwriting of kbn-system-api when asSystemRequest: true', async () => { - fetchMock.get('*', {}); - await expect( - fetchInstance.fetch('/my/path', { - headers: { myHeader: 'foo', 'kbn-system-api': 'ANOTHER!' }, - asSystemRequest: true, - }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Invalid fetch headers, headers beginning with \\"kbn-\\" are not allowed: [kbn-system-api]"` - ); - }); - - // Deprecated header used by legacy platform pre-7.7. Remove in 8.x. - it('should not allow overwriting of kbn-system-api when asSystemRequest: false', async () => { - fetchMock.get('*', {}); - await expect( - fetchInstance.fetch('/my/path', { - headers: { myHeader: 'foo', 'kbn-system-api': 'ANOTHER!' }, - asSystemRequest: false, - }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Invalid fetch headers, headers beginning with \\"kbn-\\" are not allowed: [kbn-system-api]"` - ); - }); - it('should return response', async () => { fetchMock.get('*', { foo: 'bar' }); const json = await fetchInstance.fetch('/my/path'); diff --git a/src/core/server/http/router/request.test.ts b/src/core/server/http/router/request.test.ts index ce38fd63b712d..800c97550dffc 100644 --- a/src/core/server/http/router/request.test.ts +++ b/src/core/server/http/router/request.test.ts @@ -141,31 +141,6 @@ describe('KibanaRequest', () => { const kibanaRequest = KibanaRequest.from(request); expect(kibanaRequest.isSystemRequest).toBe(false); }); - - // Remove support for kbn-system-api header in 8.x. Only used by legacy platform. - it('is false when no kbn-system-api header is set', () => { - const request = httpServerMock.createRawRequest({ - headers: { custom: 'one' }, - }); - const kibanaRequest = KibanaRequest.from(request); - expect(kibanaRequest.isSystemRequest).toBe(false); - }); - - it('is true when kbn-system-api header is set to true', () => { - const request = httpServerMock.createRawRequest({ - headers: { custom: 'one', 'kbn-system-api': 'true' }, - }); - const kibanaRequest = KibanaRequest.from(request); - expect(kibanaRequest.isSystemRequest).toBe(true); - }); - - it('is false when kbn-system-api header is set to false', () => { - const request = httpServerMock.createRawRequest({ - headers: { custom: 'one', 'kbn-system-api': 'false' }, - }); - const kibanaRequest = KibanaRequest.from(request); - expect(kibanaRequest.isSystemRequest).toBe(false); - }); }); describe('route.options.authRequired property', () => { diff --git a/src/core/server/http/router/request.ts b/src/core/server/http/router/request.ts index 42e342f762e4d..b9bf5693ab758 100644 --- a/src/core/server/http/router/request.ts +++ b/src/core/server/http/router/request.ts @@ -202,10 +202,7 @@ export class KibanaRequest< this.url = request.url; this.headers = deepFreeze({ ...request.headers }); - this.isSystemRequest = - request.headers['kbn-system-request'] === 'true' || - // Remove support for `kbn-system-api` in 8.x. Used only by legacy platform. - request.headers['kbn-system-api'] === 'true'; + this.isSystemRequest = request.headers['kbn-system-request'] === 'true'; // prevent Symbol exposure via Object.getOwnPropertySymbols() Object.defineProperty(this, requestSymbol, { diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/migration_from_v1.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/migration_from_older_v1.test.ts similarity index 54% rename from src/core/server/saved_objects/migrationsv2/integration_tests/migration_from_v1.test.ts rename to src/core/server/saved_objects/migrationsv2/integration_tests/migration_from_older_v1.test.ts index d7a64e7368bf4..46fecdf05bbaf 100644 --- a/src/core/server/saved_objects/migrationsv2/integration_tests/migration_from_v1.test.ts +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/migration_from_older_v1.test.ts @@ -21,7 +21,7 @@ import { Root } from '../../../root'; const kibanaVersion = Env.createDefault(REPO_ROOT, getEnvOptions()).packageInfo.version; -const logFilePath = Path.join(__dirname, 'migration_from_v1.log'); +const logFilePath = Path.join(__dirname, 'migration_from_older_v1.log'); const asyncUnlink = Util.promisify(Fs.unlink); async function removeLogFile() { @@ -53,7 +53,10 @@ async function fetchDocuments(esClient: ElasticsearchClient, index: string) { .sort(sortByTypeAndId); } -describe('migration v2', () => { +describe('migrating from 7.3.0-xpack which used v1 migrations', () => { + const migratedIndex = `.kibana_${kibanaVersion}_001`; + const originalIndex = `.kibana_1`; // v1 migrations index + let esServer: kbnTestServer.TestElasticsearchUtils; let root: Root; let coreStart: InternalCoreStart; @@ -159,136 +162,50 @@ describe('migration v2', () => { await new Promise((resolve) => setTimeout(resolve, 10000)); }; - // FLAKY: https://github.com/elastic/kibana/issues/87968 - describe.skip('migrating from 7.3.0-xpack version', () => { - const migratedIndex = `.kibana_${kibanaVersion}_001`; - - beforeAll(async () => { - await removeLogFile(); - await startServers({ - oss: false, - dataArchive: Path.join(__dirname, 'archives', '7.3.0_xpack_sample_saved_objects.zip'), - }); - }); - - afterAll(async () => { - await stopServers(); + beforeAll(async () => { + await removeLogFile(); + await startServers({ + oss: false, + dataArchive: Path.join(__dirname, 'archives', '7.3.0_xpack_sample_saved_objects.zip'), }); + }); - it('creates the new index and the correct aliases', async () => { - const { body } = await esClient.indices.get( - { - index: migratedIndex, - }, - { ignore: [404] } - ); - - const response = body[migratedIndex]; - - expect(response).toBeDefined(); - expect(Object.keys(response.aliases!).sort()).toEqual([ - '.kibana', - `.kibana_${kibanaVersion}`, - ]); - }); + afterAll(async () => { + await stopServers(); + }); - it('copies all the document of the previous index to the new one', async () => { - const migratedIndexResponse = await esClient.count({ + it('creates the new index and the correct aliases', async () => { + const { body } = await esClient.indices.get( + { index: migratedIndex, - }); - const oldIndexResponse = await esClient.count({ - index: '.kibana_1', - }); + }, + { ignore: [404] } + ); - // Use a >= comparison since once Kibana has started it might create new - // documents like telemetry tasks - expect(migratedIndexResponse.body.count).toBeGreaterThanOrEqual(oldIndexResponse.body.count); - }); + const response = body[migratedIndex]; - it('migrates the documents to the highest version', async () => { - const expectedVersions = getExpectedVersionPerType(); - const res = await esClient.search({ - index: migratedIndex, - body: { - sort: ['_doc'], - }, - size: 10000, - }); - const allDocuments = res.body.hits.hits as SavedObjectsRawDoc[]; - allDocuments.forEach((doc) => { - assertMigrationVersion(doc, expectedVersions); - }); - }); + expect(response).toBeDefined(); + expect(Object.keys(response.aliases!).sort()).toEqual(['.kibana', `.kibana_${kibanaVersion}`]); }); - describe('migrating from the same Kibana version that used v1 migrations', () => { - const originalIndex = `.kibana_1`; // v1 migrations index - const migratedIndex = `.kibana_${kibanaVersion}_001`; - - beforeAll(async () => { - await removeLogFile(); - await startServers({ - oss: false, - dataArchive: Path.join( - __dirname, - 'archives', - '8.0.0_v1_migrations_sample_data_saved_objects.zip' - ), - }); - }); - - afterAll(async () => { - await stopServers(); - }); - - it('creates the new index and the correct aliases', async () => { - const { body } = await esClient.indices.get( - { - index: migratedIndex, - }, - { ignore: [404] } - ); - const response = body[migratedIndex]; - - expect(response).toBeDefined(); - expect(Object.keys(response.aliases!).sort()).toEqual([ - '.kibana', - `.kibana_${kibanaVersion}`, - ]); - }); - - it('copies the documents from the previous index to the new one', async () => { - // original assertion on document count comparison (how atteched are we to this assertion?) - const migratedIndexResponse = await esClient.count({ - index: migratedIndex, - }); - const oldIndexResponse = await esClient.count({ - index: originalIndex, - }); - - // Use a >= comparison since once Kibana has started it might create new - // documents like telemetry tasks - expect(migratedIndexResponse.body.count).toBeGreaterThanOrEqual(oldIndexResponse.body.count); + it('copies all the document of the previous index to the new one', async () => { + const originalDocs = await fetchDocuments(esClient, originalIndex); + const migratedDocs = await fetchDocuments(esClient, migratedIndex); + expect(assertMigratedDocuments(migratedDocs, originalDocs)); + }); - // new assertion against a document array comparison - const originalDocs = await fetchDocuments(esClient, originalIndex); - const migratedDocs = await fetchDocuments(esClient, migratedIndex); - expect(assertMigratedDocuments(migratedDocs, originalDocs)); + it('migrates the documents to the highest version', async () => { + const expectedVersions = getExpectedVersionPerType(); + const res = await esClient.search({ + index: migratedIndex, + body: { + sort: ['_doc'], + }, + size: 10000, }); - - it('migrates the documents to the highest version', async () => { - const expectedVersions = getExpectedVersionPerType(); - const res = await esClient.search({ - index: migratedIndex, - body: { - sort: ['_doc'], - }, - size: 10000, - }); - const allDocuments = res.body.hits.hits as SavedObjectsRawDoc[]; - allDocuments.forEach((doc) => { - assertMigrationVersion(doc, expectedVersions); - }); + const allDocuments = res.body.hits.hits as SavedObjectsRawDoc[]; + allDocuments.forEach((doc) => { + assertMigrationVersion(doc, expectedVersions); }); }); }); diff --git a/src/core/server/saved_objects/migrationsv2/integration_tests/migration_from_same_v1.test.ts b/src/core/server/saved_objects/migrationsv2/integration_tests/migration_from_same_v1.test.ts new file mode 100644 index 0000000000000..18eb5cc96e496 --- /dev/null +++ b/src/core/server/saved_objects/migrationsv2/integration_tests/migration_from_same_v1.test.ts @@ -0,0 +1,214 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import Path from 'path'; +import Fs from 'fs'; +import Util from 'util'; +import Semver from 'semver'; +import { REPO_ROOT } from '@kbn/dev-utils'; +import { Env } from '@kbn/config'; +import { getEnvOptions } from '../../../config/mocks'; +import * as kbnTestServer from '../../../../test_helpers/kbn_server'; +import { ElasticsearchClient } from '../../../elasticsearch'; +import { SavedObjectsRawDoc } from '../../serialization'; +import { InternalCoreStart } from '../../../internal_types'; +import { Root } from '../../../root'; + +const kibanaVersion = Env.createDefault(REPO_ROOT, getEnvOptions()).packageInfo.version; + +const logFilePath = Path.join(__dirname, 'migration_from_same_v1.log'); + +const asyncUnlink = Util.promisify(Fs.unlink); +async function removeLogFile() { + // ignore errors if it doesn't exist + await asyncUnlink(logFilePath).catch(() => void 0); +} +const assertMigratedDocuments = (arr: any[], target: any[]) => target.every((v) => arr.includes(v)); + +function sortByTypeAndId(a: { type: string; id: string }, b: { type: string; id: string }) { + return a.type.localeCompare(b.type) || a.id.localeCompare(b.id); +} + +async function fetchDocuments(esClient: ElasticsearchClient, index: string) { + const { body } = await esClient.search({ + index, + body: { + query: { + match_all: {}, + }, + _source: ['type', 'id'], + }, + }); + + return body.hits.hits + .map((h) => ({ + ...h._source, + id: h._id, + })) + .sort(sortByTypeAndId); +} + +describe('migrating from the same Kibana version that used v1 migrations', () => { + const originalIndex = `.kibana_1`; // v1 migrations index + const migratedIndex = `.kibana_${kibanaVersion}_001`; + + let esServer: kbnTestServer.TestElasticsearchUtils; + let root: Root; + let coreStart: InternalCoreStart; + let esClient: ElasticsearchClient; + + const startServers = async ({ dataArchive, oss }: { dataArchive: string; oss: boolean }) => { + const { startES } = kbnTestServer.createTestServers({ + adjustTimeout: (t: number) => jest.setTimeout(t), + settings: { + es: { + license: 'basic', + dataArchive, + }, + }, + }); + + root = kbnTestServer.createRootWithCorePlugins( + { + migrations: { + skip: false, + enableV2: true, + // There are 40 docs in fixtures. Batch size configured to enforce 3 migration steps. + batchSize: 15, + }, + logging: { + appenders: { + file: { + type: 'file', + fileName: logFilePath, + layout: { + type: 'json', + }, + }, + }, + loggers: [ + { + name: 'root', + appenders: ['file'], + }, + ], + }, + }, + { + oss, + } + ); + + const startEsPromise = startES().then((es) => (esServer = es)); + const startKibanaPromise = root + .preboot() + .then(() => root.setup()) + .then(() => root.start()) + .then((start) => { + coreStart = start; + esClient = coreStart.elasticsearch.client.asInternalUser; + }); + return await Promise.all([startEsPromise, startKibanaPromise]); + }; + + const getExpectedVersionPerType = () => + coreStart.savedObjects + .getTypeRegistry() + .getAllTypes() + .reduce((versionMap, type) => { + const { name, migrations, convertToMultiNamespaceTypeVersion } = type; + if (migrations || convertToMultiNamespaceTypeVersion) { + const migrationsMap = typeof migrations === 'function' ? migrations() : migrations; + const migrationsKeys = migrationsMap ? Object.keys(migrationsMap) : []; + if (convertToMultiNamespaceTypeVersion) { + // Setting this option registers a conversion migration that is reflected in the object's `migrationVersions` field + migrationsKeys.push(convertToMultiNamespaceTypeVersion); + } + const highestVersion = migrationsKeys.sort(Semver.compare).reverse()[0]; + return { + ...versionMap, + [name]: highestVersion, + }; + } else { + return { + ...versionMap, + [name]: undefined, + }; + } + }, {} as Record); + + const assertMigrationVersion = ( + doc: SavedObjectsRawDoc, + expectedVersions: Record + ) => { + const migrationVersions = doc._source.migrationVersion; + const type = doc._source.type; + expect(migrationVersions ? migrationVersions[type] : undefined).toEqual(expectedVersions[type]); + }; + + const stopServers = async () => { + if (root) { + await root.shutdown(); + } + if (esServer) { + await esServer.stop(); + } + + await new Promise((resolve) => setTimeout(resolve, 10000)); + }; + + beforeAll(async () => { + await removeLogFile(); + await startServers({ + oss: false, + dataArchive: Path.join( + __dirname, + 'archives', + '8.0.0_v1_migrations_sample_data_saved_objects.zip' + ), + }); + }); + + afterAll(async () => { + await stopServers(); + }); + + it('creates the new index and the correct aliases', async () => { + const { body } = await esClient.indices.get( + { + index: migratedIndex, + }, + { ignore: [404] } + ); + const response = body[migratedIndex]; + + expect(response).toBeDefined(); + expect(Object.keys(response.aliases!).sort()).toEqual(['.kibana', `.kibana_${kibanaVersion}`]); + }); + + it('copies the documents from the previous index to the new one', async () => { + const originalDocs = await fetchDocuments(esClient, originalIndex); + const migratedDocs = await fetchDocuments(esClient, migratedIndex); + expect(assertMigratedDocuments(migratedDocs, originalDocs)); + }); + + it('migrates the documents to the highest version', async () => { + const expectedVersions = getExpectedVersionPerType(); + const res = await esClient.search({ + index: migratedIndex, + body: { + sort: ['_doc'], + }, + size: 10000, + }); + const allDocuments = res.body.hits.hits as SavedObjectsRawDoc[]; + allDocuments.forEach((doc) => { + assertMigrationVersion(doc, expectedVersions); + }); + }); +}); diff --git a/src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/__snapshots__/tagcloud_function.test.ts.snap b/src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/__snapshots__/tagcloud_function.test.ts.snap index da116bc50f370..37da83ef8ac9d 100644 --- a/src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/__snapshots__/tagcloud_function.test.ts.snap +++ b/src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/__snapshots__/tagcloud_function.test.ts.snap @@ -71,10 +71,7 @@ Object { }, "minFontSize": 18, "orientation": "single", - "palette": Object { - "name": "default", - "type": "palette", - }, + "palette": "{palette}", "scale": "linear", "showLabel": true, }, @@ -142,10 +139,7 @@ Object { }, "minFontSize": 18, "orientation": "single", - "palette": Object { - "name": "default", - "type": "palette", - }, + "palette": "{palette}", "scale": "linear", "showLabel": true, }, diff --git a/src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/tagcloud_function.ts b/src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/tagcloud_function.ts index 2ce50e94aeda3..1c499db96917e 100644 --- a/src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/tagcloud_function.ts +++ b/src/plugins/chart_expressions/expression_tagcloud/common/expression_functions/tagcloud_function.ts @@ -110,9 +110,9 @@ export const tagcloudFunction: ExpressionTagcloudFunction = () => { help: argHelp.showLabel, }, palette: { - types: ['string'], + types: ['palette', 'system_palette'], help: argHelp.palette, - default: 'default', + default: '{palette}', }, metric: { types: ['vis_dimension'], @@ -135,10 +135,7 @@ export const tagcloudFunction: ExpressionTagcloudFunction = () => { ...(args.bucket && { bucket: args.bucket, }), - palette: { - type: 'palette', - name: args.palette, - }, + palette: args.palette, }; if (handlers?.inspectorAdapters?.tables) { diff --git a/src/plugins/chart_expressions/expression_tagcloud/common/types/expression_functions.ts b/src/plugins/chart_expressions/expression_tagcloud/common/types/expression_functions.ts index 1ee0434e1603e..091b3e861332d 100644 --- a/src/plugins/chart_expressions/expression_tagcloud/common/types/expression_functions.ts +++ b/src/plugins/chart_expressions/expression_tagcloud/common/types/expression_functions.ts @@ -41,7 +41,7 @@ export interface TagcloudRendererConfig { } interface Arguments extends TagCloudVisConfig { - palette: string; + palette: PaletteOutput; } export type ExpressionTagcloudFunction = () => ExpressionFunctionDefinition< diff --git a/src/plugins/chart_expressions/expression_tagcloud/public/components/tagcloud_component.tsx b/src/plugins/chart_expressions/expression_tagcloud/public/components/tagcloud_component.tsx index b7d38c71f5867..b0f9f3197a44a 100644 --- a/src/plugins/chart_expressions/expression_tagcloud/public/components/tagcloud_component.tsx +++ b/src/plugins/chart_expressions/expression_tagcloud/public/components/tagcloud_component.tsx @@ -11,7 +11,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { throttle } from 'lodash'; import { EuiIconTip, EuiResizeObserver } from '@elastic/eui'; import { Chart, Settings, Wordcloud, RenderChangeListener } from '@elastic/charts'; -import type { PaletteRegistry } from '../../../../charts/public'; +import type { PaletteRegistry, PaletteOutput } from '../../../../charts/public'; import { Datatable, DatatableColumn, @@ -36,12 +36,12 @@ const calculateWeight = (value: number, x1: number, y1: number, x2: number, y2: const getColor = ( palettes: PaletteRegistry, - activePalette: string, + activePalette: PaletteOutput, text: string, values: string[], syncColors: boolean ) => { - return palettes?.get(activePalette).getCategoricalColor( + return palettes?.get(activePalette?.name)?.getCategoricalColor( [ { name: text, @@ -54,7 +54,8 @@ const getColor = ( totalSeries: values.length || 1, behindText: false, syncColors, - } + }, + activePalette?.params ?? { colors: [] } ); }; @@ -113,14 +114,14 @@ export const TagCloudChart = ({ tag === 'all' || visData.rows.length <= 1 ? 1 : calculateWeight(row[metricColumn], minValue, maxValue, 0, 1) || 0, - color: getColor(palettesRegistry, palette.name, tag, values, syncColors) || 'rgba(0,0,0,0)', + color: getColor(palettesRegistry, palette, tag, values, syncColors) || 'rgba(0,0,0,0)', }; }); }, [ bucket, bucketFormatter, metric.accessor, - palette.name, + palette, palettesRegistry, syncColors, visData.columns, diff --git a/src/plugins/charts/common/palette.ts b/src/plugins/charts/common/palette.ts index 78c6fcc812028..1faeb4df7788e 100644 --- a/src/plugins/charts/common/palette.ts +++ b/src/plugins/charts/common/palette.ts @@ -35,11 +35,12 @@ export interface SystemPaletteArguments { name: string; } -export interface PaletteOutput { - type: 'palette'; +export interface PaletteOutput { + type: 'palette' | 'system_palette'; name: string; params?: T; } + export const defaultCustomColors = [ // This set of defaults originated in Canvas, which, at present, is the primary // consumer of this function. Changing this default requires a change in Canvas diff --git a/src/plugins/vis_default_editor/public/components/controls/palette_picker.tsx b/src/plugins/vis_default_editor/public/components/controls/palette_picker.tsx index 9249edef8af92..ee6ee405c479d 100644 --- a/src/plugins/vis_default_editor/public/components/controls/palette_picker.tsx +++ b/src/plugins/vis_default_editor/public/components/controls/palette_picker.tsx @@ -8,10 +8,12 @@ import React from 'react'; import { PaletteOutput, PaletteRegistry } from 'src/plugins/charts/public'; -import { EuiColorPalettePicker } from '@elastic/eui'; +import { EuiColorPalettePicker, EuiColorPalettePickerPaletteProps } from '@elastic/eui'; import { EuiFormRow } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +const DEFAULT_PALETTE = 'default'; + export interface PalettePickerProps { activePalette?: PaletteOutput; palettes: PaletteRegistry; @@ -25,6 +27,21 @@ export function PalettePicker({ paramName, setPalette, }: PalettePickerProps) { + const palettesList: EuiColorPalettePickerPaletteProps[] = palettes + .getAll() + .filter(({ internal }) => !internal) + .map(({ id, title, getCategoricalColors }) => { + return { + value: id, + title, + type: 'fixed', + palette: getCategoricalColors( + 10, + id === activePalette?.name ? activePalette?.params : undefined + ), + }; + }); + return ( ({ fullWidth data-test-subj="visEditorPalettePicker" compressed - palettes={palettes - .getAll() - .filter(({ internal }) => !internal) - .map(({ id, title, getCategoricalColors }) => { - return { - value: id, - title, - type: 'fixed', - palette: getCategoricalColors( - 10, - id === activePalette?.name ? activePalette?.params : undefined - ), - }; - })} + palettes={palettesList} onChange={(newPalette) => { + const palette = palettesList.find((item) => item.value === newPalette); setPalette(paramName, { type: 'palette', - name: newPalette, + name: palette?.value ?? DEFAULT_PALETTE, }); }} - valueOfSelected={activePalette?.name || 'default'} + valueOfSelected={activePalette?.name || DEFAULT_PALETTE} selectionDisplay={'palette'} /> diff --git a/src/plugins/vis_types/tagcloud/public/__snapshots__/to_ast.test.ts.snap b/src/plugins/vis_types/tagcloud/public/__snapshots__/to_ast.test.ts.snap index 9e4c3071db8d6..3f50cdf559e19 100644 --- a/src/plugins/vis_types/tagcloud/public/__snapshots__/to_ast.test.ts.snap +++ b/src/plugins/vis_types/tagcloud/public/__snapshots__/to_ast.test.ts.snap @@ -85,7 +85,20 @@ Object { "single", ], "palette": Array [ - "default", + Object { + "chain": Array [ + Object { + "arguments": Object { + "name": Array [ + "default", + ], + }, + "function": "system_palette", + "type": "function", + }, + ], + "type": "expression", + }, ], "scale": Array [ "linear", @@ -187,7 +200,20 @@ Object { "single", ], "palette": Array [ - "default", + Object { + "chain": Array [ + Object { + "arguments": Object { + "name": Array [ + "default", + ], + }, + "function": "system_palette", + "type": "function", + }, + ], + "type": "expression", + }, ], "scale": Array [ "linear", @@ -279,6 +305,18 @@ Object { "type": "expression", }, ], + "palette": Array [ + Object { + "chain": Array [ + Object { + "arguments": Object {}, + "function": "system_palette", + "type": "function", + }, + ], + "type": "expression", + }, + ], "showLabel": Array [ false, ], diff --git a/src/plugins/vis_types/tagcloud/public/tag_cloud_type.ts b/src/plugins/vis_types/tagcloud/public/tag_cloud_type.ts index a193a7fecc1fd..daad73c082980 100644 --- a/src/plugins/vis_types/tagcloud/public/tag_cloud_type.ts +++ b/src/plugins/vis_types/tagcloud/public/tag_cloud_type.ts @@ -14,66 +14,68 @@ import { getTagCloudOptions } from './components/get_tag_cloud_options'; import { toExpressionAst } from './to_ast'; import { TagCloudVisDependencies } from './plugin'; -export const getTagCloudVisTypeDefinition = ({ palettes }: TagCloudVisDependencies) => ({ - name: 'tagcloud', - title: i18n.translate('visTypeTagCloud.vis.tagCloudTitle', { defaultMessage: 'Tag cloud' }), - icon: 'visTagCloud', - getSupportedTriggers: () => { - return [VIS_EVENT_TO_TRIGGER.filter]; - }, - description: i18n.translate('visTypeTagCloud.vis.tagCloudDescription', { - defaultMessage: 'Display word frequency with font size.', - }), - visConfig: { - defaults: { - scale: 'linear', - orientation: 'single', - minFontSize: 18, - maxFontSize: 72, - showLabel: true, - palette: { - name: 'default', - type: 'palette', - }, +export const getTagCloudVisTypeDefinition = ({ palettes }: TagCloudVisDependencies) => { + return { + name: 'tagcloud', + title: i18n.translate('visTypeTagCloud.vis.tagCloudTitle', { defaultMessage: 'Tag cloud' }), + icon: 'visTagCloud', + getSupportedTriggers: () => { + return [VIS_EVENT_TO_TRIGGER.filter]; }, - }, - toExpressionAst, - editorConfig: { - optionsTemplate: getTagCloudOptions({ - palettes, + description: i18n.translate('visTypeTagCloud.vis.tagCloudDescription', { + defaultMessage: 'Display word frequency with font size.', }), - schemas: [ - { - group: AggGroupNames.Metrics, - name: 'metric', - title: i18n.translate('visTypeTagCloud.vis.schemas.metricTitle', { - defaultMessage: 'Tag size', - }), - min: 1, - max: 1, - aggFilter: [ - '!std_dev', - '!percentiles', - '!percentile_ranks', - '!derivative', - '!geo_bounds', - '!geo_centroid', - '!filtered_metric', - '!single_percentile', - ], - defaults: [{ schema: 'metric', type: 'count' }], - }, - { - group: AggGroupNames.Buckets, - name: 'segment', - title: i18n.translate('visTypeTagCloud.vis.schemas.segmentTitle', { - defaultMessage: 'Tags', - }), - min: 1, - max: 1, - aggFilter: ['terms', 'significant_terms'], + visConfig: { + defaults: { + scale: 'linear', + orientation: 'single', + minFontSize: 18, + maxFontSize: 72, + showLabel: true, + palette: { + name: 'default', + type: 'palette', + }, }, - ], - }, - requiresSearch: true, -}); + }, + toExpressionAst, + editorConfig: { + optionsTemplate: getTagCloudOptions({ + palettes, + }), + schemas: [ + { + group: AggGroupNames.Metrics, + name: 'metric', + title: i18n.translate('visTypeTagCloud.vis.schemas.metricTitle', { + defaultMessage: 'Tag size', + }), + min: 1, + max: 1, + aggFilter: [ + '!std_dev', + '!percentiles', + '!percentile_ranks', + '!derivative', + '!geo_bounds', + '!geo_centroid', + '!filtered_metric', + '!single_percentile', + ], + defaults: [{ schema: 'metric', type: 'count' }], + }, + { + group: AggGroupNames.Buckets, + name: 'segment', + title: i18n.translate('visTypeTagCloud.vis.schemas.segmentTitle', { + defaultMessage: 'Tags', + }), + min: 1, + max: 1, + aggFilter: ['terms', 'significant_terms'], + }, + ], + }, + requiresSearch: true, + }; +}; diff --git a/src/plugins/vis_types/tagcloud/public/to_ast.ts b/src/plugins/vis_types/tagcloud/public/to_ast.ts index b5256c586d1da..e9ef8f84ba55b 100644 --- a/src/plugins/vis_types/tagcloud/public/to_ast.ts +++ b/src/plugins/vis_types/tagcloud/public/to_ast.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import { PaletteOutput } from 'src/plugins/charts/common'; import { EsaggsExpressionFunctionDefinition, IndexPatternLoadExpressionFunctionDefinition, @@ -25,6 +26,13 @@ const prepareDimension = (params: SchemaConfig) => { return buildExpression([visdimension]); }; +const preparePalette = (palette?: PaletteOutput) => { + const paletteExpressionFunction = buildExpressionFunction('system_palette', { + name: palette?.name, + }); + return buildExpression([paletteExpressionFunction]); +}; + export const toExpressionAst: VisToExpressionAst = (vis, params) => { const esaggs = buildExpressionFunction('esaggs', { index: buildExpression([ @@ -47,7 +55,7 @@ export const toExpressionAst: VisToExpressionAst = (vis, para maxFontSize, showLabel, metric: prepareDimension(schemas.metric[0]), - palette: palette?.name, + palette: preparePalette(palette), }); if (schemas.segment) { diff --git a/test/interpreter_functional/snapshots/baseline/partial_test_1.json b/test/interpreter_functional/snapshots/baseline/partial_test_1.json index 082c7b934c17c..9877a0d3138c0 100644 --- a/test/interpreter_functional/snapshots/baseline/partial_test_1.json +++ b/test/interpreter_functional/snapshots/baseline/partial_test_1.json @@ -1 +1 @@ -{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/tagcloud_all_data.json b/test/interpreter_functional/snapshots/baseline/tagcloud_all_data.json index 9813a3ca036a1..5ddf081c54d95 100644 --- a/test/interpreter_functional/snapshots/baseline/tagcloud_all_data.json +++ b/test/interpreter_functional/snapshots/baseline/tagcloud_all_data.json @@ -1 +1 @@ -{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/tagcloud_empty_data.json b/test/interpreter_functional/snapshots/baseline/tagcloud_empty_data.json index 6dd90a4a6ca03..723ebb6e9f460 100644 --- a/test/interpreter_functional/snapshots/baseline/tagcloud_empty_data.json +++ b/test/interpreter_functional/snapshots/baseline/tagcloud_empty_data.json @@ -1 +1 @@ -{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/tagcloud_fontsize.json b/test/interpreter_functional/snapshots/baseline/tagcloud_fontsize.json index bef1b10120fe5..1655451d41d03 100644 --- a/test/interpreter_functional/snapshots/baseline/tagcloud_fontsize.json +++ b/test/interpreter_functional/snapshots/baseline/tagcloud_fontsize.json @@ -1 +1 @@ -{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":40,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":20,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":40,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":20,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/tagcloud_metric_data.json b/test/interpreter_functional/snapshots/baseline/tagcloud_metric_data.json index bea6dad294e01..f0bfd56ac99b8 100644 --- a/test/interpreter_functional/snapshots/baseline/tagcloud_metric_data.json +++ b/test/interpreter_functional/snapshots/baseline/tagcloud_metric_data.json @@ -1 +1 @@ -{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/tagcloud_options.json b/test/interpreter_functional/snapshots/baseline/tagcloud_options.json index c45b063fdb542..ba034fa2e435a 100644 --- a/test/interpreter_functional/snapshots/baseline/tagcloud_options.json +++ b/test/interpreter_functional/snapshots/baseline/tagcloud_options.json @@ -1 +1 @@ -{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"multiple","palette":{"name":"default","type":"palette"},"scale":"log","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"multiple","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"log","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/metric_empty_data.json b/test/interpreter_functional/snapshots/session/metric_empty_data.json new file mode 100644 index 0000000000000..c318121535c8f --- /dev/null +++ b/test/interpreter_functional/snapshots/session/metric_empty_data.json @@ -0,0 +1 @@ +{"as":"metric_vis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/metric_invalid_data.json b/test/interpreter_functional/snapshots/session/metric_invalid_data.json index c7b4a0325dc91..f23b9b0915774 100644 --- a/test/interpreter_functional/snapshots/session/metric_invalid_data.json +++ b/test/interpreter_functional/snapshots/session/metric_invalid_data.json @@ -1 +1 @@ -{"as":"metric_vis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[],"meta":{},"rows":[],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +"[metricVis] > [visdimension] > Column name or index provided is invalid" \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/metric_single_metric_data.json b/test/interpreter_functional/snapshots/session/metric_single_metric_data.json new file mode 100644 index 0000000000000..f4a8cd1f14e18 --- /dev/null +++ b/test/interpreter_functional/snapshots/session/metric_single_metric_data.json @@ -0,0 +1 @@ +{"as":"metric_vis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"}]},"metric":{"colorSchema":"Green to Red","colorsRange":[{"from":0,"to":10000,"type":"range"}],"invertColors":false,"labels":{"show":true},"metricColorMode":"None","percentageMode":false,"style":{"bgColor":false,"bgFill":"#000","fontSize":60,"labelColor":false,"subText":""},"useRanges":false}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/partial_test_1.json b/test/interpreter_functional/snapshots/session/partial_test_1.json new file mode 100644 index 0000000000000..9877a0d3138c0 --- /dev/null +++ b/test/interpreter_functional/snapshots/session/partial_test_1.json @@ -0,0 +1 @@ +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/tagcloud_all_data.json b/test/interpreter_functional/snapshots/session/tagcloud_all_data.json index 9813a3ca036a1..5ddf081c54d95 100644 --- a/test/interpreter_functional/snapshots/session/tagcloud_all_data.json +++ b/test/interpreter_functional/snapshots/session/tagcloud_all_data.json @@ -1 +1 @@ -{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/tagcloud_empty_data.json b/test/interpreter_functional/snapshots/session/tagcloud_empty_data.json index 6dd90a4a6ca03..723ebb6e9f460 100644 --- a/test/interpreter_functional/snapshots/session/tagcloud_empty_data.json +++ b/test/interpreter_functional/snapshots/session/tagcloud_empty_data.json @@ -1 +1 @@ -{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/tagcloud_fontsize.json b/test/interpreter_functional/snapshots/session/tagcloud_fontsize.json index bef1b10120fe5..1655451d41d03 100644 --- a/test/interpreter_functional/snapshots/session/tagcloud_fontsize.json +++ b/test/interpreter_functional/snapshots/session/tagcloud_fontsize.json @@ -1 +1 @@ -{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":40,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":20,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":40,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":20,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/tagcloud_metric_data.json b/test/interpreter_functional/snapshots/session/tagcloud_metric_data.json index bea6dad294e01..f0bfd56ac99b8 100644 --- a/test/interpreter_functional/snapshots/session/tagcloud_metric_data.json +++ b/test/interpreter_functional/snapshots/session/tagcloud_metric_data.json @@ -1 +1 @@ -{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"default","type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"linear","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/tagcloud_options.json b/test/interpreter_functional/snapshots/session/tagcloud_options.json index c45b063fdb542..ba034fa2e435a 100644 --- a/test/interpreter_functional/snapshots/session/tagcloud_options.json +++ b/test/interpreter_functional/snapshots/session/tagcloud_options.json @@ -1 +1 @@ -{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"multiple","palette":{"name":"default","type":"palette"},"scale":"log","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file +{"as":"tagcloud","type":"render","value":{"syncColors":false,"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"2","indexPatternId":"logstash-*","params":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"id":"1","indexPatternId":"logstash-*","params":{},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"multiple","palette":{"name":"custom","params":{"colors":["#882E72","#B178A6","#D6C1DE","#1965B0","#5289C7","#7BAFDE","#4EB265","#90C987","#CAE0AB","#F7EE55","#F6C141","#F1932D","#E8601C","#DC050C"],"continuity":"above","gradient":false,"range":"percent","rangeMax":100,"rangeMin":0,"stops":[]},"type":"palette"},"scale":"log","showLabel":true},"visType":"tagcloud"}} \ No newline at end of file diff --git a/x-pack/plugins/canvas/canvas_plugin_src/elements/tag_cloud/index.ts b/x-pack/plugins/canvas/canvas_plugin_src/elements/tag_cloud/index.ts index a0b464390fa22..b3543d532b9be 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/elements/tag_cloud/index.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/elements/tag_cloud/index.ts @@ -13,9 +13,9 @@ export const tagCloud: ElementFactory = () => ({ help: 'Tagcloud visualization', icon: 'visTagCloud', expression: `filters - | demodata - | head 150 - | ply by="country" expression={math "count(country)" | as "Count"} + | demodata + | ply by="country" fn={math "count(country)" | as "Count"} + | filterrows fn={getCell "Count" | gte 10} | tagcloud metric={visdimension "Count"} bucket={visdimension "country"} | render`, }); diff --git a/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/index.ts b/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/index.ts index 0b84abe191162..dd013116bb808 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/index.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/index.ts @@ -31,6 +31,7 @@ import { string } from './string'; import { textarea } from './textarea'; // @ts-expect-error untyped local import { toggle } from './toggle'; +import { visdimension } from './vis_dimension'; import { SetupInitializer } from '../../plugin'; @@ -48,6 +49,7 @@ export const args = [ string, textarea, toggle, + visdimension, ]; export const initializers = [dateFormatInitializer, numberFormatInitializer]; diff --git a/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/select.js b/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/select.js index 69041598f7a3a..196803670ec2f 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/select.js +++ b/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/select.js @@ -43,6 +43,12 @@ SelectArgInput.propTypes = { }), }), argId: PropTypes.string.isRequired, + choices: PropTypes.arrayOf( + PropTypes.shape({ + name: PropTypes.string.isRequired, + value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]).isRequired, + }) + ), }; export const select = () => ({ diff --git a/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/vis_dimension.tsx b/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/vis_dimension.tsx new file mode 100644 index 0000000000000..df75704ababb5 --- /dev/null +++ b/x-pack/plugins/canvas/canvas_plugin_src/uis/arguments/vis_dimension.tsx @@ -0,0 +1,99 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useState, useEffect, useCallback } from 'react'; +import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiSelect } from '@elastic/eui'; +import { DatatableColumn, ExpressionAstExpression } from 'src/plugins/expressions'; +import { templateFromReactComponent } from '../../../public/lib/template_from_react_component'; +import { ArgumentStrings } from '../../../i18n'; + +const { VisDimension: strings } = ArgumentStrings; + +interface VisDimensionArgInputProps { + onValueChange: (value: ExpressionAstExpression) => void; + argValue: ExpressionAstExpression; + argId?: string; + columns: DatatableColumn[]; + typeInstance: { + options?: { + confirm?: string; + }; + }; +} + +const VisDimensionArgInput: React.FC = ({ + argValue, + typeInstance, + onValueChange, + argId, + columns, +}: { + // @todo define types + [key: string]: any; +}) => { + const [value, setValue] = useState(argValue); + const confirm = typeInstance?.options?.confirm; + + useEffect(() => { + setValue(argValue); + }, [argValue]); + + const onChange = useCallback( + (ev) => { + const onChangeFn = confirm ? setValue : onValueChange; + const astObj: ExpressionAstExpression = { + type: 'expression', + chain: [ + { + type: 'function', + function: 'visdimension', + arguments: { + _: [ev.target.value], + }, + }, + ], + }; + + onChangeFn(astObj); + }, + [confirm, onValueChange] + ); + + const options = [ + { value: '', text: strings.getDefaultOptionName(), disabled: true }, + ...columns.map((column: DatatableColumn) => ({ value: column.name, text: column.name })), + ]; + + const selectedValue = value.chain[0].arguments._?.[0]; + + const column = + columns + .map((col: DatatableColumn) => col.name) + .find((colName: string) => colName === selectedValue) || ''; + + return ( + + + + + {confirm && ( + + onValueChange(value)}> + {confirm} + + + )} + + ); +}; + +export const visdimension = () => ({ + name: 'vis_dimension', + displayName: strings.getDisplayName(), + help: strings.getHelp(), + simpleTemplate: templateFromReactComponent(VisDimensionArgInput), +}); diff --git a/x-pack/plugins/canvas/canvas_plugin_src/uis/models/index.js b/x-pack/plugins/canvas/canvas_plugin_src/uis/models/index.js index 978ddb2a92f31..0762f70b19858 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/uis/models/index.js +++ b/x-pack/plugins/canvas/canvas_plugin_src/uis/models/index.js @@ -7,5 +7,6 @@ import { pointseries } from './point_series'; import { math } from './math'; +import { tagcloud } from './tagcloud'; -export const modelSpecs = [pointseries, math]; +export const modelSpecs = [pointseries, math, tagcloud]; diff --git a/x-pack/plugins/canvas/canvas_plugin_src/uis/models/tagcloud.ts b/x-pack/plugins/canvas/canvas_plugin_src/uis/models/tagcloud.ts new file mode 100644 index 0000000000000..11cad3461c025 --- /dev/null +++ b/x-pack/plugins/canvas/canvas_plugin_src/uis/models/tagcloud.ts @@ -0,0 +1,91 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { get } from 'lodash'; + +import { ViewStrings } from '../../../i18n'; +import { getState, getValue } from '../../../public/lib/resolved_arg'; + +const { Tagcloud: strings } = ViewStrings; + +export const tagcloud = () => ({ + name: 'tagcloud', + displayName: strings.getDisplayName(), + args: [ + { + name: 'metric', + displayName: strings.getMetricColumnDisplayName(), + help: strings.getMetricColumnHelp(), + argType: 'vis_dimension', + }, + { + name: 'bucket', + displayName: strings.getBucketColumnDisplayName(), + help: strings.getBucketColumnHelp(), + argType: 'vis_dimension', + }, + { + name: 'palette', + argType: 'palette', + }, + { + name: 'orientation', + displayName: strings.getOrientationColumnDisplayName(), + help: strings.getOrientationColumnHelp(), + argType: 'select', + default: 'single', + options: { + choices: [ + { value: 'single', name: strings.getOrientationSingle() }, + { value: 'right angled', name: strings.getOrientationRightAngled() }, + { value: 'multiple', name: strings.getOrientationMultiple() }, + ], + }, + }, + { + name: 'scale', + displayName: strings.getScaleColumnDisplayName(), + help: strings.getScaleColumnHelp(), + argType: 'select', + default: 'linear', + options: { + choices: [ + { value: 'linear', name: strings.getScaleLinear() }, + { value: 'log', name: strings.getScaleLog() }, + { value: 'square root', name: strings.getScaleSquareRoot() }, + ], + }, + }, + { + name: 'minFontSize', + displayName: strings.getMinFontHeightColumnDisplayName(), + help: strings.getMinFontHeightColumnHelp(), + argType: 'number', + default: 18, + }, + { + name: 'maxFontSize', + displayName: strings.getMaxFontHeightColumnDisplayName(), + help: strings.getMaxFontHeightColumnHelp(), + argType: 'number', + default: 72, + }, + { + name: 'showLabel', + displayName: strings.getShowLabelColumnDisplayName(), + help: strings.getShowLabelColumnHelp(), + argType: 'toggle', + default: true, + }, + ], + resolve({ context }: any) { + if (getState(context) !== 'ready') { + return { columns: [] }; + } + return { columns: get(getValue(context), 'columns', []) }; + }, +}); diff --git a/x-pack/plugins/canvas/canvas_plugin_src/uis/views/index.ts b/x-pack/plugins/canvas/canvas_plugin_src/uis/views/index.ts index ed8428f0203ca..74ad909648235 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/uis/views/index.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/uis/views/index.ts @@ -32,7 +32,6 @@ import { shape } from './shape'; import { table } from './table'; // @ts-expect-error untyped local import { timefilterControl } from './timefilterControl'; - import { SetupInitializer } from '../../plugin'; export const viewSpecs = [ diff --git a/x-pack/plugins/canvas/i18n/ui.ts b/x-pack/plugins/canvas/i18n/ui.ts index 4002da4115a23..30a09d51ffab4 100644 --- a/x-pack/plugins/canvas/i18n/ui.ts +++ b/x-pack/plugins/canvas/i18n/ui.ts @@ -314,6 +314,20 @@ export const ArgumentStrings = { defaultMessage: 'A true/false toggle switch', }), }, + VisDimension: { + getDisplayName: () => + i18n.translate('xpack.canvas.uis.arguments.visDimensionTitle', { + defaultMessage: 'Column', + }), + getHelp: () => + i18n.translate('xpack.canvas.uis.arguments.visDimensionLabel', { + defaultMessage: 'Generates visConfig dimension object', + }), + getDefaultOptionName: () => + i18n.translate('xpack.canvas.uis.arguments.visDimensionDefaultOptionName', { + defaultMessage: 'Select column', + }), + }, }; export const DataSourceStrings = { @@ -1173,4 +1187,90 @@ export const ViewStrings = { "Apply the selected group name to an element's filters function to target this filter", }), }, + Tagcloud: { + getDisplayName: () => + i18n.translate('xpack.canvas.uis.views.tagcloudTitle', { + defaultMessage: 'Tag Cloud', + }), + getScaleColumnDisplayName: () => + i18n.translate('xpack.canvas.uis.views.tagcloud.args.scaleDisplayName', { + defaultMessage: 'Scale', + }), + getScaleColumnHelp: () => + i18n.translate('xpack.canvas.uis.views.tagcloud.args.scaleHelp', { + defaultMessage: 'Scale to determine font size of a word', + }), + getScaleLinear: () => + i18n.translate('xpack.canvas.uis.views.tagcloud.args.scaleLinearLabel', { + defaultMessage: 'Linear', + }), + getScaleLog: () => + i18n.translate('xpack.canvas.uis.views.tagcloud.args.scaleLogLabel', { + defaultMessage: 'Log', + }), + getScaleSquareRoot: () => + i18n.translate('xpack.canvas.uis.views.tagcloud.args.scaleSquareRootLabel', { + defaultMessage: 'Square root', + }), + getOrientationColumnDisplayName: () => + i18n.translate('xpack.canvas.uis.views.tagcloud.args.orientationDisplayName', { + defaultMessage: 'Orientation', + }), + getOrientationColumnHelp: () => + i18n.translate('xpack.canvas.uis.views.tagcloud.args.orientationHelp', { + defaultMessage: 'Orientation of words inside tagcloud', + }), + getOrientationSingle: () => + i18n.translate('xpack.canvas.uis.views.tagcloud.args.orientationSingleLabel', { + defaultMessage: 'Single', + }), + getOrientationRightAngled: () => + i18n.translate('xpack.canvas.uis.views.tagcloud.args.orientationRightAngledLabel', { + defaultMessage: 'Right angled', + }), + getOrientationMultiple: () => + i18n.translate('xpack.canvas.uis.views.tagcloud.args.orientationMultipleLabel', { + defaultMessage: 'Multiple', + }), + getMinFontHeightColumnDisplayName: () => + i18n.translate('xpack.canvas.uis.views.tagcloud.args.minFontHeightDisplayName', { + defaultMessage: 'Minimum font height', + }), + getMinFontHeightColumnHelp: () => + i18n.translate('xpack.canvas.uis.views.tagcloud.args.minFontHeightHelp', { + defaultMessage: 'Minimum height of the element font', + }), + getMaxFontHeightColumnDisplayName: () => + i18n.translate('xpack.canvas.uis.views.tagcloud.args.maxFontHeightDisplayName', { + defaultMessage: 'Maximum font height', + }), + getMaxFontHeightColumnHelp: () => + i18n.translate('xpack.canvas.uis.views.tagcloud.args.maxFontHeightHelp', { + defaultMessage: 'Maximum height of the element font', + }), + getShowLabelColumnDisplayName: () => + i18n.translate('xpack.canvas.uis.views.tagcloud.args.showLabelDisplayName', { + defaultMessage: 'Show label', + }), + getShowLabelColumnHelp: () => + i18n.translate('xpack.canvas.uis.views.tagcloud.args.showLabelHelp', { + defaultMessage: 'Show label of the chart', + }), + getMetricColumnDisplayName: () => + i18n.translate('xpack.canvas.uis.views.tagcloud.args.metricDisplayName', { + defaultMessage: 'Metric', + }), + getMetricColumnHelp: () => + i18n.translate('xpack.canvas.uis.views.tagcloud.args.metricHelp', { + defaultMessage: 'Metric dimension configuration', + }), + getBucketColumnDisplayName: () => + i18n.translate('xpack.canvas.uis.views.tagcloud.args.bucketDisplayName', { + defaultMessage: 'Bucket', + }), + getBucketColumnHelp: () => + i18n.translate('xpack.canvas.uis.views.tagcloud.args.bucketHelp', { + defaultMessage: 'Bucket dimension configuration', + }), + }, }; diff --git a/x-pack/plugins/canvas/public/components/es_index_select/es_index_select.js b/x-pack/plugins/canvas/public/components/es_index_select/es_index_select.component.tsx similarity index 62% rename from x-pack/plugins/canvas/public/components/es_index_select/es_index_select.js rename to x-pack/plugins/canvas/public/components/es_index_select/es_index_select.component.tsx index 6400cb3a1c2e3..636b19092123a 100644 --- a/x-pack/plugins/canvas/public/components/es_index_select/es_index_select.js +++ b/x-pack/plugins/canvas/public/components/es_index_select/es_index_select.component.tsx @@ -5,21 +5,35 @@ * 2.0. */ -import React from 'react'; -import PropTypes from 'prop-types'; +import React, { FocusEventHandler } from 'react'; import { EuiComboBox } from '@elastic/eui'; -import { get } from 'lodash'; + +export interface ESIndexSelectProps { + loading: boolean; + value: string; + indices: string[]; + onChange: (index: string) => void; + onBlur: FocusEventHandler | undefined; + onFocus: FocusEventHandler | undefined; +} const defaultIndex = '_all'; -export const ESIndexSelect = ({ value, loading, indices, onChange, onFocus, onBlur }) => { +export const ESIndexSelect: React.FunctionComponent = ({ + value = defaultIndex, + loading, + indices, + onChange, + onFocus, + onBlur, +}) => { const selectedOption = value !== defaultIndex ? [{ label: value }] : []; const options = indices.map((index) => ({ label: index })); return ( onChange(get(index, 'label', defaultIndex))} + onChange={([index]) => onChange(index?.label ?? defaultIndex)} onSearchChange={(searchValue) => { // resets input when user starts typing if (searchValue) { @@ -28,7 +42,7 @@ export const ESIndexSelect = ({ value, loading, indices, onChange, onFocus, onBl }} onBlur={onBlur} onFocus={onFocus} - disabled={loading} + isDisabled={loading} options={options} singleSelection={{ asPlainText: true }} isClearable={false} @@ -37,16 +51,3 @@ export const ESIndexSelect = ({ value, loading, indices, onChange, onFocus, onBl /> ); }; - -ESIndexSelect.propTypes = { - value: PropTypes.string, - onChange: PropTypes.func.isRequired, - onFocus: PropTypes.func, - onBlur: PropTypes.func, - indices: PropTypes.array.isRequired, - loading: PropTypes.bool.isRequired, -}; - -ESIndexSelect.defaultProps = { - value: defaultIndex, -}; diff --git a/x-pack/plugins/canvas/public/components/es_index_select/es_index_select.tsx b/x-pack/plugins/canvas/public/components/es_index_select/es_index_select.tsx new file mode 100644 index 0000000000000..7d2e87902d2d1 --- /dev/null +++ b/x-pack/plugins/canvas/public/components/es_index_select/es_index_select.tsx @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useRef, useState } from 'react'; +import useEffectOnce from 'react-use/lib/useEffectOnce'; +import { getIndices } from '../../lib/es_service'; +import { + ESIndexSelect as Component, + ESIndexSelectProps as Props, +} from './es_index_select.component'; + +type ESIndexSelectProps = Omit; + +export const ESIndexSelect: React.FunctionComponent = (props) => { + const { value, onChange } = props; + + const [indices, setIndices] = useState([]); + const [loading, setLoading] = useState(true); + const mounted = useRef(true); + + useEffectOnce(() => { + getIndices().then((newIndices) => { + if (!mounted.current) { + return; + } + + if (!newIndices) { + newIndices = []; + } + + setLoading(false); + setIndices(newIndices.sort()); + if (!value && newIndices.length) { + onChange(newIndices[0]); + } + }); + + return () => { + mounted.current = false; + }; + }); + + return ; +}; diff --git a/x-pack/plugins/canvas/public/components/es_index_select/index.js b/x-pack/plugins/canvas/public/components/es_index_select/index.js deleted file mode 100644 index bcdbde06d54a7..0000000000000 --- a/x-pack/plugins/canvas/public/components/es_index_select/index.js +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { compose, withState, lifecycle } from 'recompose'; -import { getIndices } from '../../lib/es_service'; -import { ESIndexSelect as Component } from './es_index_select'; - -export const ESIndexSelect = compose( - withState('loading', 'setLoading', true), - withState('indices', 'setIndices', []), - lifecycle({ - componentDidMount() { - getIndices().then((indices = []) => { - const { setLoading, setIndices, value, onChange } = this.props; - setLoading(false); - setIndices(indices.sort()); - if (!value && indices.length) { - onChange(indices[0]); - } - }); - }, - }) -)(Component); diff --git a/x-pack/plugins/canvas/public/components/es_index_select/index.tsx b/x-pack/plugins/canvas/public/components/es_index_select/index.tsx new file mode 100644 index 0000000000000..29a19e8770606 --- /dev/null +++ b/x-pack/plugins/canvas/public/components/es_index_select/index.tsx @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { ESIndexSelect } from './es_index_select'; +export { ESIndexSelect as ESIndexSelectComponent } from './es_index_select.component'; diff --git a/x-pack/plugins/canvas/public/components/palette_picker/palette_picker.tsx b/x-pack/plugins/canvas/public/components/palette_picker/palette_picker.tsx index dcc77b75f25c3..c962dbae46b07 100644 --- a/x-pack/plugins/canvas/public/components/palette_picker/palette_picker.tsx +++ b/x-pack/plugins/canvas/public/components/palette_picker/palette_picker.tsx @@ -7,6 +7,7 @@ import React, { FC } from 'react'; import PropTypes from 'prop-types'; +import { isEqual } from 'lodash'; import { EuiColorPalettePicker, EuiColorPalettePickerPaletteProps } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -39,6 +40,15 @@ interface ClearableProps { type Props = RequiredProps | ClearableProps; +const findPalette = (colorPalette: ColorPalette | null, colorPalettes: ColorPalette[] = []) => { + const palette = colorPalettes.filter((cp) => cp.id === colorPalette?.id)[0] ?? null; + if (palette === null) { + return colorPalettes.filter((cp) => isEqual(cp.colors, colorPalette?.colors))[0] ?? null; + } + + return palette; +}; + export const PalettePicker: FC = (props) => { const colorPalettes: EuiColorPalettePickerPaletteProps[] = palettes.map((item) => ({ value: item.id, @@ -61,13 +71,15 @@ export const PalettePicker: FC = (props) => { onChange(canvasPalette || null); }; + const foundPalette = findPalette(palette, palettes); + return ( ); } @@ -84,13 +96,15 @@ export const PalettePicker: FC = (props) => { onChange(canvasPalette); }; + const foundPalette = findPalette(palette, palettes); + return ( ); }; diff --git a/x-pack/plugins/canvas/public/components/workpad_app/workpad_app.scss b/x-pack/plugins/canvas/public/components/workpad_app/workpad_app.scss index 11f4efdd67a01..3f6d6887e0c80 100644 --- a/x-pack/plugins/canvas/public/components/workpad_app/workpad_app.scss +++ b/x-pack/plugins/canvas/public/components/workpad_app/workpad_app.scss @@ -73,6 +73,9 @@ $canvasLayoutFontSize: $euiFontSizeS; .euiPanel { margin-bottom: $euiSizeS; } + .euiPanel.euiSplitPanel__inner { + margin-bottom: 0; + } } .canvasLayout__footer { diff --git a/x-pack/plugins/lens/public/heatmap_visualization/chart_component.tsx b/x-pack/plugins/lens/public/heatmap_visualization/chart_component.tsx index c666d27e780b5..5d2207e93d491 100644 --- a/x-pack/plugins/lens/public/heatmap_visualization/chart_component.tsx +++ b/x-pack/plugins/lens/public/heatmap_visualization/chart_component.tsx @@ -125,7 +125,7 @@ export const HeatmapComponent: FC = ({ const tableId = Object.keys(data.tables)[0]; const table = data.tables[tableId]; - const paletteParams = args.palette?.params as CustomPaletteState; + const paletteParams = args.palette?.params; const xAxisColumnIndex = table.columns.findIndex((v) => v.id === args.xAccessor); const yAxisColumnIndex = table.columns.findIndex((v) => v.id === args.yAccessor); diff --git a/x-pack/plugins/lens/public/heatmap_visualization/types.ts b/x-pack/plugins/lens/public/heatmap_visualization/types.ts index 5515d77d1a8ab..d6b0e7ddc1d74 100644 --- a/x-pack/plugins/lens/public/heatmap_visualization/types.ts +++ b/x-pack/plugins/lens/public/heatmap_visualization/types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { PaletteOutput } from '../../../../../src/plugins/charts/common'; +import type { CustomPaletteState, PaletteOutput } from '../../../../../src/plugins/charts/common'; import type { LensBrushEvent, LensFilterEvent } from '../types'; import type { LensMultiTable, FormatFactory, CustomPaletteParams, LayerType } from '../../common'; import type { HeatmapGridConfigResult, HeatmapLegendConfigResult } from '../../common/expressions'; @@ -36,7 +36,7 @@ export type HeatmapVisualizationState = HeatmapLayerState & { export type HeatmapExpressionArgs = SharedHeatmapLayerState & { title?: string; description?: string; - palette: PaletteOutput; + palette: PaletteOutput; }; export interface HeatmapRender { diff --git a/x-pack/test/functional/apps/ml/anomaly_detection/anomaly_explorer.ts b/x-pack/test/functional/apps/ml/anomaly_detection/anomaly_explorer.ts index 4373da71512e4..3622c5dba1696 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection/anomaly_explorer.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection/anomaly_explorer.ts @@ -63,7 +63,8 @@ export default function ({ getService }: FtrProviderContext) { const ml = getService('ml'); const elasticChart = getService('elasticChart'); - describe('anomaly explorer', function () { + // Failing: See https://github.com/elastic/kibana/issues/112405 + describe.skip('anomaly explorer', function () { this.tags(['mlqa']); before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); diff --git a/x-pack/test/functional/apps/ml/anomaly_detection/saved_search_job.ts b/x-pack/test/functional/apps/ml/anomaly_detection/saved_search_job.ts index fb10414d2d9ef..1637369142aa2 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection/saved_search_job.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection/saved_search_job.ts @@ -265,7 +265,8 @@ export default function ({ getService }: FtrProviderContext) { }, ]; - describe('saved search', function () { + // Failing: See https://github.com/elastic/kibana/issues/104174 + describe.skip('saved search', function () { this.tags(['mlqa']); before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); diff --git a/x-pack/test/functional_execution_context/tests/browser.ts b/x-pack/test/functional_execution_context/tests/browser.ts index 9e927dd2bc171..f6e46a6bc2280 100644 --- a/x-pack/test/functional_execution_context/tests/browser.ts +++ b/x-pack/test/functional_execution_context/tests/browser.ts @@ -12,7 +12,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'dashboard', 'header', 'home']); const retry = getService('retry'); - describe('Browser apps', () => { + // Failing: See https://github.com/elastic/kibana/issues/112102 + describe.skip('Browser apps', () => { before(async () => { await PageObjects.common.navigateToUrl('home', '/tutorial_directory/sampleData', { useActualUrl: true,