[ML] Move Index Data Visualizer into separate plugin (Part 1) (#100922)

* [ML] Add index visualizer

* [ML] Readd support for global state

* [ML] Add time buckets & fix dependencies

* [ML] Working ver

* [ML] Add back and boolean support

* [ML] Remove old files inside ml

* [ML] Rename files

* [ML] Move field type icon

* [ML] Create new folder structure

* [ML] Organize index_data_visualizer

* [ML] Move types into index_data_visualizer folder

* [ML] Move more files into file_data_visualizer

* [ML] Move more files into index_data_visualizer

* [ML] Add new data visualizer model

* [ML] Remove getVisualizerFieldStats which is not used by dv

* [ML] Delete redundant folder

* [ML] Copy old data visualizer routes to new plugin

* [ML] Remove old routes

* [ML] Disable for ml job cards tests for now

* [ML] Remove todos

* [ML] Move the toast error to the UI component

* [ML] Fix map styling

* [ML] Add runtime_mappings for internal/file_upload/time_field_range

* [ML] Move routes into folder

* [ML] Update permissions

* [ML] Update texts

* [ML] Update schemas import and api get_field_stats

* [ML] Reorg folders into common

* [ML] Update types & tests

* [ML] Update internal/data_visualizer permissions and action panel tests

* [ML] Update imports after #100863

* [ML] Fix CI

* [ML] Rename folder from file_data_visualizer to data_visualizer

* [ML] Rename i18n ids

* [ML] Update fileDataVisualizer -> dataVisualizer dependency name in ml plugin

* [ML] Remove ml prefix in data test subjs

* [ML] Fix settings and docs

* [ML] Update plugin description

* [ML] Remove mlContext dependency completely

* [ML] Set query to optional

* Revert "[ML] Update plugin description"

This reverts commit 4ab1a25c

* [ML] Update plugins list docs

* [ML] Fix types and i18n

* [ML] Revert ml data test subj/class name changes

* [ML] Split up data visualizer model, remove Logger

* [ML] Remove empty file and indexPatternFieldEditor

* [ML] Move imports of file_upload

* [ML] Update plugin dependencies

* Re-add missing data_visualizer.json

* Remove capabilities in data_visualizer

* Fix test subjs

* Update ownership for data_visualizer and file_upload code to be ml

* Update estypes after 98266

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Quynh Nguyen 2021-06-08 14:50:14 -05:00 committed by GitHub
parent 8aa370ba3b
commit 65b8dda157
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
372 changed files with 6256 additions and 5096 deletions

46
.github/CODEOWNERS vendored
View file

@ -130,6 +130,8 @@
# ML team owns and maintains the transform plugin despite it living in the Data management section.
/x-pack/plugins/transform/ @elastic/ml-ui
/x-pack/plugins/data_visualizer/ @elastic/ml-ui
/x-pack/plugins/file_upload/ @elastic/ml-ui
/x-pack/test/accessibility/apps/transform.ts @elastic/ml-ui
/x-pack/test/api_integration/apis/transform/ @elastic/ml-ui
/x-pack/test/api_integration_basic/apis/transform/ @elastic/ml-ui
@ -306,28 +308,28 @@
/x-pack/plugins/enterprise_search/server/saved_objects/workplace_search/ @elastic/workplace-search-frontend
# Stack Management
/src/plugins/dev_tools/ @elastic/kibana-stack-management
/src/plugins/console/ @elastic/kibana-stack-management
/src/plugins/es_ui_shared/ @elastic/kibana-stack-management
/x-pack/plugins/cross_cluster_replication/ @elastic/kibana-stack-management
/x-pack/plugins/index_lifecycle_management/ @elastic/kibana-stack-management
/x-pack/plugins/console_extensions/ @elastic/kibana-stack-management
/x-pack/plugins/grokdebugger/ @elastic/kibana-stack-management
/x-pack/plugins/index_management/ @elastic/kibana-stack-management
/x-pack/plugins/license_api_guard/ @elastic/kibana-stack-management
/x-pack/plugins/license_management/ @elastic/kibana-stack-management
/x-pack/plugins/painless_lab/ @elastic/kibana-stack-management
/x-pack/plugins/remote_clusters/ @elastic/kibana-stack-management
/x-pack/plugins/rollup/ @elastic/kibana-stack-management
/x-pack/plugins/searchprofiler/ @elastic/kibana-stack-management
/x-pack/plugins/snapshot_restore/ @elastic/kibana-stack-management
/x-pack/plugins/upgrade_assistant/ @elastic/kibana-stack-management
/x-pack/plugins/watcher/ @elastic/kibana-stack-management
/x-pack/plugins/ingest_pipelines/ @elastic/kibana-stack-management
/packages/kbn-ace/ @elastic/kibana-stack-management
/packages/kbn-monaco/ @elastic/kibana-stack-management
#CC# /x-pack/plugins/console_extensions/ @elastic/kibana-stack-management
#CC# /x-pack/plugins/cross_cluster_replication/ @elastic/kibana-stack-management
/src/plugins/dev_tools/ @elastic/kibana-stack-management
/src/plugins/console/ @elastic/kibana-stack-management
/src/plugins/es_ui_shared/ @elastic/kibana-stack-management
/x-pack/plugins/cross_cluster_replication/ @elastic/kibana-stack-management
/x-pack/plugins/index_lifecycle_management/ @elastic/kibana-stack-management
/x-pack/plugins/console_extensions/ @elastic/kibana-stack-management
/x-pack/plugins/grokdebugger/ @elastic/kibana-stack-management
/x-pack/plugins/index_management/ @elastic/kibana-stack-management
/x-pack/plugins/license_api_guard/ @elastic/kibana-stack-management
/x-pack/plugins/license_management/ @elastic/kibana-stack-management
/x-pack/plugins/painless_lab/ @elastic/kibana-stack-management
/x-pack/plugins/remote_clusters/ @elastic/kibana-stack-management
/x-pack/plugins/rollup/ @elastic/kibana-stack-management
/x-pack/plugins/searchprofiler/ @elastic/kibana-stack-management
/x-pack/plugins/snapshot_restore/ @elastic/kibana-stack-management
/x-pack/plugins/upgrade_assistant/ @elastic/kibana-stack-management
/x-pack/plugins/watcher/ @elastic/kibana-stack-management
/x-pack/plugins/ingest_pipelines/ @elastic/kibana-stack-management
/packages/kbn-ace/ @elastic/kibana-stack-management
/packages/kbn-monaco/ @elastic/kibana-stack-management
#CC# /x-pack/plugins/console_extensions/ @elastic/kibana-stack-management
#CC# /x-pack/plugins/cross_cluster_replication/ @elastic/kibana-stack-management
# Security Solution
/x-pack/test/endpoint_api_integration_no_ingest/ @elastic/security-solution

View file

@ -1,5 +1,5 @@
{
"id": "fileDataVisualizer",
"id": "dataVisualizer",
"client": {
"classes": [],
"functions": [],
@ -8,18 +8,18 @@
"misc": [],
"objects": [],
"start": {
"parentPluginId": "fileDataVisualizer",
"id": "def-public.FileDataVisualizerPluginStart",
"parentPluginId": "dataVisualizer",
"id": "def-public.DataVisualizerPluginStart",
"type": "Type",
"tags": [],
"label": "FileDataVisualizerPluginStart",
"label": "DataVisualizerPluginStart",
"description": [],
"signature": [
"{ getFileDataVisualizerComponent: () => Promise<React.FC<{}>>; getMaxBytesFormatted: () => string; }"
],
"source": {
"path": "x-pack/plugins/file_data_visualizer/public/plugin.ts",
"lineNumber": 36
"path": "x-pack/plugins/data_visualizer/public/plugin.ts",
"lineNumber": 33
},
"deprecated": false,
"lifecycle": "start",
@ -39,72 +39,72 @@
"functions": [],
"interfaces": [
{
"parentPluginId": "fileDataVisualizer",
"parentPluginId": "dataVisualizer",
"id": "def-common.DataVisualizerTableState",
"type": "Interface",
"tags": [],
"label": "DataVisualizerTableState",
"description": [],
"source": {
"path": "x-pack/plugins/file_data_visualizer/common/types.ts",
"path": "x-pack/plugins/data_visualizer/common/types.ts",
"lineNumber": 14
},
"deprecated": false,
"children": [
{
"parentPluginId": "fileDataVisualizer",
"parentPluginId": "dataVisualizer",
"id": "def-common.DataVisualizerTableState.pageSize",
"type": "number",
"tags": [],
"label": "pageSize",
"description": [],
"source": {
"path": "x-pack/plugins/file_data_visualizer/common/types.ts",
"path": "x-pack/plugins/data_visualizer/common/types.ts",
"lineNumber": 15
},
"deprecated": false
},
{
"parentPluginId": "fileDataVisualizer",
"parentPluginId": "dataVisualizer",
"id": "def-common.DataVisualizerTableState.pageIndex",
"type": "number",
"tags": [],
"label": "pageIndex",
"description": [],
"source": {
"path": "x-pack/plugins/file_data_visualizer/common/types.ts",
"path": "x-pack/plugins/data_visualizer/common/types.ts",
"lineNumber": 16
},
"deprecated": false
},
{
"parentPluginId": "fileDataVisualizer",
"parentPluginId": "dataVisualizer",
"id": "def-common.DataVisualizerTableState.sortField",
"type": "string",
"tags": [],
"label": "sortField",
"description": [],
"source": {
"path": "x-pack/plugins/file_data_visualizer/common/types.ts",
"path": "x-pack/plugins/data_visualizer/common/types.ts",
"lineNumber": 17
},
"deprecated": false
},
{
"parentPluginId": "fileDataVisualizer",
"parentPluginId": "dataVisualizer",
"id": "def-common.DataVisualizerTableState.sortDirection",
"type": "string",
"tags": [],
"label": "sortDirection",
"description": [],
"source": {
"path": "x-pack/plugins/file_data_visualizer/common/types.ts",
"path": "x-pack/plugins/data_visualizer/common/types.ts",
"lineNumber": 18
},
"deprecated": false
},
{
"parentPluginId": "fileDataVisualizer",
"parentPluginId": "dataVisualizer",
"id": "def-common.DataVisualizerTableState.visibleFieldTypes",
"type": "Array",
"tags": [],
@ -114,13 +114,13 @@
"string[]"
],
"source": {
"path": "x-pack/plugins/file_data_visualizer/common/types.ts",
"path": "x-pack/plugins/data_visualizer/common/types.ts",
"lineNumber": 19
},
"deprecated": false
},
{
"parentPluginId": "fileDataVisualizer",
"parentPluginId": "dataVisualizer",
"id": "def-common.DataVisualizerTableState.visibleFieldNames",
"type": "Array",
"tags": [],
@ -130,20 +130,20 @@
"string[]"
],
"source": {
"path": "x-pack/plugins/file_data_visualizer/common/types.ts",
"path": "x-pack/plugins/data_visualizer/common/types.ts",
"lineNumber": 20
},
"deprecated": false
},
{
"parentPluginId": "fileDataVisualizer",
"parentPluginId": "dataVisualizer",
"id": "def-common.DataVisualizerTableState.showDistributions",
"type": "boolean",
"tags": [],
"label": "showDistributions",
"description": [],
"source": {
"path": "x-pack/plugins/file_data_visualizer/common/types.ts",
"path": "x-pack/plugins/data_visualizer/common/types.ts",
"lineNumber": 21
},
"deprecated": false
@ -155,7 +155,7 @@
"enums": [],
"misc": [
{
"parentPluginId": "fileDataVisualizer",
"parentPluginId": "dataVisualizer",
"id": "def-common.ABSOLUTE_MAX_FILE_SIZE_BYTES",
"type": "number",
"tags": [],
@ -165,14 +165,14 @@
"1073741274"
],
"source": {
"path": "x-pack/plugins/file_data_visualizer/common/constants.ts",
"path": "x-pack/plugins/data_visualizer/common/constants.ts",
"lineNumber": 14
},
"deprecated": false,
"initialIsOpen": false
},
{
"parentPluginId": "fileDataVisualizer",
"parentPluginId": "dataVisualizer",
"id": "def-common.FILE_SIZE_DISPLAY_FORMAT",
"type": "string",
"tags": [],
@ -182,14 +182,14 @@
"\"0,0.[0] b\""
],
"source": {
"path": "x-pack/plugins/file_data_visualizer/common/constants.ts",
"path": "x-pack/plugins/data_visualizer/common/constants.ts",
"lineNumber": 15
},
"deprecated": false,
"initialIsOpen": false
},
{
"parentPluginId": "fileDataVisualizer",
"parentPluginId": "dataVisualizer",
"id": "def-common.INDEX_META_DATA_CREATED_BY",
"type": "string",
"tags": [],
@ -199,14 +199,14 @@
"\"file-data-visualizer\""
],
"source": {
"path": "x-pack/plugins/file_data_visualizer/common/constants.ts",
"path": "x-pack/plugins/data_visualizer/common/constants.ts",
"lineNumber": 19
},
"deprecated": false,
"initialIsOpen": false
},
{
"parentPluginId": "fileDataVisualizer",
"parentPluginId": "dataVisualizer",
"id": "def-common.InputData",
"type": "Type",
"tags": [],
@ -216,31 +216,31 @@
"any[]"
],
"source": {
"path": "x-pack/plugins/file_data_visualizer/common/types.ts",
"path": "x-pack/plugins/data_visualizer/common/types.ts",
"lineNumber": 10
},
"deprecated": false,
"initialIsOpen": false
},
{
"parentPluginId": "fileDataVisualizer",
"parentPluginId": "dataVisualizer",
"id": "def-common.JobFieldType",
"type": "Type",
"tags": [],
"label": "JobFieldType",
"description": [],
"signature": [
"\"number\" | \"boolean\" | \"date\" | \"keyword\" | \"text\" | \"ip\" | \"geo_point\" | \"geo_shape\" | \"unknown\""
"\"number\" | \"boolean\" | \"date\" | \"text\" | \"keyword\" | \"ip\" | \"geo_point\" | \"geo_shape\" | \"unknown\""
],
"source": {
"path": "x-pack/plugins/file_data_visualizer/common/types.ts",
"path": "x-pack/plugins/data_visualizer/common/types.ts",
"lineNumber": 12
},
"deprecated": false,
"initialIsOpen": false
},
{
"parentPluginId": "fileDataVisualizer",
"parentPluginId": "dataVisualizer",
"id": "def-common.MAX_FILE_SIZE",
"type": "string",
"tags": [],
@ -250,14 +250,14 @@
"\"100MB\""
],
"source": {
"path": "x-pack/plugins/file_data_visualizer/common/constants.ts",
"path": "x-pack/plugins/data_visualizer/common/constants.ts",
"lineNumber": 11
},
"deprecated": false,
"initialIsOpen": false
},
{
"parentPluginId": "fileDataVisualizer",
"parentPluginId": "dataVisualizer",
"id": "def-common.MAX_FILE_SIZE_BYTES",
"type": "number",
"tags": [],
@ -267,28 +267,28 @@
"104857600"
],
"source": {
"path": "x-pack/plugins/file_data_visualizer/common/constants.ts",
"path": "x-pack/plugins/data_visualizer/common/constants.ts",
"lineNumber": 12
},
"deprecated": false,
"initialIsOpen": false
},
{
"parentPluginId": "fileDataVisualizer",
"parentPluginId": "dataVisualizer",
"id": "def-common.MB",
"type": "number",
"tags": [],
"label": "MB",
"description": [],
"source": {
"path": "x-pack/plugins/file_data_visualizer/common/constants.ts",
"path": "x-pack/plugins/data_visualizer/common/constants.ts",
"lineNumber": 10
},
"deprecated": false,
"initialIsOpen": false
},
{
"parentPluginId": "fileDataVisualizer",
"parentPluginId": "dataVisualizer",
"id": "def-common.UI_SETTING_MAX_FILE_SIZE",
"type": "string",
"tags": [],
@ -298,7 +298,7 @@
"\"fileUpload:maxFileSize\""
],
"source": {
"path": "x-pack/plugins/file_data_visualizer/common/constants.ts",
"path": "x-pack/plugins/data_visualizer/common/constants.ts",
"lineNumber": 8
},
"deprecated": false,
@ -307,7 +307,7 @@
],
"objects": [
{
"parentPluginId": "fileDataVisualizer",
"parentPluginId": "dataVisualizer",
"id": "def-common.JOB_FIELD_TYPES",
"type": "Object",
"tags": [],
@ -317,7 +317,7 @@
"{ readonly BOOLEAN: \"boolean\"; readonly DATE: \"date\"; readonly GEO_POINT: \"geo_point\"; readonly GEO_SHAPE: \"geo_shape\"; readonly IP: \"ip\"; readonly KEYWORD: \"keyword\"; readonly NUMBER: \"number\"; readonly TEXT: \"text\"; readonly UNKNOWN: \"unknown\"; }"
],
"source": {
"path": "x-pack/plugins/file_data_visualizer/common/constants.ts",
"path": "x-pack/plugins/data_visualizer/common/constants.ts",
"lineNumber": 21
},
"deprecated": false,
@ -325,4 +325,4 @@
}
]
}
}
}

View file

@ -369,6 +369,10 @@ The client-side plugin configures following values:
|The data_enhanced plugin is the x-pack counterpart to the src/plguins/data plugin.
|{kib-repo}blob/{branch}/x-pack/plugins/data_visualizer/README.md[dataVisualizer]
|The data_visualizer plugin enables you to explore the fields in your data.
|{kib-repo}blob/{branch}/x-pack/plugins/discover_enhanced/README.md[discoverEnhanced]
|Contains the enhancements to the OSS discover app.
@ -396,10 +400,6 @@ actitivies.
|The features plugin enhance Kibana with a per-feature privilege system.
|{kib-repo}blob/{branch}/x-pack/plugins/file_data_visualizer[fileDataVisualizer]
|WARNING: Missing README.
|{kib-repo}blob/{branch}/x-pack/plugins/file_upload[fileUpload]
|WARNING: Missing README.

View file

@ -104,7 +104,7 @@ pageLoadAssetSize:
indexPatternFieldEditor: 90489
osquery: 107090
fileUpload: 25664
fileDataVisualizer: 27530
dataVisualizer: 27530
banners: 17946
mapsEms: 26072
timelines: 28613

View file

@ -19,7 +19,7 @@
"xpack.endpoint": "plugins/endpoint",
"xpack.enterpriseSearch": "plugins/enterprise_search",
"xpack.features": "plugins/features",
"xpack.fileDataVisualizer": "plugins/file_data_visualizer",
"xpack.dataVisualizer": "plugins/data_visualizer",
"xpack.fileUpload": "plugins/file_upload",
"xpack.globalSearch": ["plugins/global_search"],
"xpack.globalSearchBar": ["plugins/global_search_bar"],

View file

@ -0,0 +1 @@
The data_visualizer plugin enables you to explore the fields in your data.

View file

@ -29,3 +29,5 @@ export const JOB_FIELD_TYPES = {
TEXT: 'text',
UNKNOWN: 'unknown',
} as const;
export const OMIT_FIELDS: string[] = ['_source', '_type', '_index', '_id', '_version', '_score'];

View file

@ -0,0 +1,60 @@
/*
* 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 type { JobFieldType } from './index';
export interface Percentile {
percent: number;
minValue: number;
maxValue: number;
}
export interface FieldRequestConfig {
fieldName?: string;
type: JobFieldType;
cardinality: number;
}
export interface DocumentCountBuckets {
[key: string]: number;
}
export interface DocumentCounts {
buckets?: DocumentCountBuckets;
interval?: number;
}
export interface FieldVisStats {
cardinality?: number;
count?: number;
sampleCount?: number;
trueCount?: number;
falseCount?: number;
earliest?: number;
latest?: number;
documentCounts?: {
buckets?: DocumentCountBuckets;
interval?: number;
};
avg?: number;
distribution?: {
percentiles: Percentile[];
maxPercentile: number;
minPercentile: 0;
};
fieldName?: string;
isTopValuesSampled?: boolean;
max?: number;
median?: number;
min?: number;
topValues?: Array<{ key: number | string; doc_count: number }>;
topValuesSampleSize?: number;
topValuesSamplerShardSize?: number;
examples?: Array<string | object>;
timeRangeEarliest?: number;
timeRangeLatest?: number;
}

View file

@ -5,12 +5,17 @@
* 2.0.
*/
import { JOB_FIELD_TYPES } from './constants';
import type { SimpleSavedObject } from 'kibana/public';
export type { JobFieldType } from './job_field_type';
export type {
FieldRequestConfig,
DocumentCountBuckets,
DocumentCounts,
FieldVisStats,
Percentile,
} from './field_request_config';
export type InputData = any[];
export type JobFieldType = typeof JOB_FIELD_TYPES[keyof typeof JOB_FIELD_TYPES];
export interface DataVisualizerTableState {
pageSize: number;
pageIndex: number;
@ -20,3 +25,5 @@ export interface DataVisualizerTableState {
visibleFieldNames: string[];
showDistributions: boolean;
}
export type SavedSearchSavedObject = SimpleSavedObject<any>;

View file

@ -5,8 +5,10 @@
* 2.0.
*/
import type { FieldVisConfig, FileBasedFieldVisConfig } from './field_vis_config';
import { estypes } from '@elastic/elasticsearch';
export interface FieldDataRowProps {
config: FieldVisConfig | FileBasedFieldVisConfig;
export interface IndicesOptions {
allow_no_indices?: boolean;
expand_wildcards?: estypes.ExpandWildcards;
ignore_unavailable?: boolean;
}

View file

@ -5,6 +5,5 @@
* 2.0.
*/
import { FileDataVisualizerPlugin } from './plugin';
export const plugin = () => new FileDataVisualizerPlugin();
import { JOB_FIELD_TYPES } from '../constants';
export type JobFieldType = typeof JOB_FIELD_TYPES[keyof typeof JOB_FIELD_TYPES];

View file

@ -5,7 +5,8 @@
* 2.0.
*/
export interface CombinedQuery {
searchString: string | { [key: string]: any };
searchQueryLanguage: string;
export interface GetTimeFieldRangeResponse {
success: boolean;
start: { epoch: number; string: string };
end: { epoch: number; string: string };
}

View file

@ -0,0 +1,23 @@
/*
* 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 { estypes } from '@elastic/elasticsearch';
export type Datafeed = estypes.MlDatafeed;
export type Aggregation = Record<string, estypes.AggregationsAggregationContainer>;
export function getAggregations<T>(obj: any): T | undefined {
if (obj?.aggregations !== undefined) return obj.aggregations;
if (obj?.aggs !== undefined) return obj.aggs;
return undefined;
}
export const getDatafeedAggregations = (
datafeedConfig: Partial<Datafeed> | undefined
): Aggregation | undefined => {
return getAggregations<Aggregation>(datafeedConfig);
};

View file

@ -0,0 +1,36 @@
/*
* 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.
*/
/*
* A type guard to check record like object structures.
*
* Examples:
* - `isPopulatedObject({...})`
* Limits type to Record<string, unknown>
*
* - `isPopulatedObject({...}, ['attribute'])`
* Limits type to Record<'attribute', unknown>
*
* - `isPopulatedObject<keyof MyInterface>({...})`
* Limits type to a record with keys of the given interface.
* Note that you might want to add keys from the interface to the
* array of requiredAttributes to satisfy runtime requirements.
* Otherwise you'd just satisfy TS requirements but might still
* run into runtime issues.
*/
export const isPopulatedObject = <U extends string = string>(
arg: unknown,
requiredAttributes: U[] = []
): arg is Record<U, unknown> => {
return (
typeof arg === 'object' &&
arg !== null &&
Object.keys(arg).length > 0 &&
(requiredAttributes.length === 0 ||
requiredAttributes.every((d) => ({}.hasOwnProperty.call(arg, d))))
);
};

View file

@ -0,0 +1,76 @@
/*
* 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 { estypes } from '@elastic/elasticsearch';
/*
* Contains utility functions for building and processing queries.
*/
// Builds the base filter criteria used in queries,
// adding criteria for the time range and an optional query.
export function buildBaseFilterCriteria(
timeFieldName?: string,
earliestMs?: number,
latestMs?: number,
query?: object
) {
const filterCriteria = [];
if (timeFieldName && earliestMs && latestMs) {
filterCriteria.push({
range: {
[timeFieldName]: {
gte: earliestMs,
lte: latestMs,
format: 'epoch_millis',
},
},
});
}
if (query) {
filterCriteria.push(query);
}
return filterCriteria;
}
// Wraps the supplied aggregations in a sampler aggregation.
// A supplied samplerShardSize (the shard_size parameter of the sampler aggregation)
// of less than 1 indicates no sampling, and the aggs are returned as-is.
export function buildSamplerAggregation(
aggs: any,
samplerShardSize: number
): Record<string, estypes.AggregationsAggregationContainer> {
if (samplerShardSize < 1) {
return aggs;
}
return {
sample: {
sampler: {
shard_size: samplerShardSize,
},
aggs,
},
};
}
// Returns the path of aggregations in the elasticsearch response, as an array,
// depending on whether sampling is being used.
// A supplied samplerShardSize (the shard_size parameter of the sampler aggregation)
// of less than 1 indicates no sampling, and an empty array is returned.
export function getSamplerAggregationsResponsePath(samplerShardSize: number): string[] {
return samplerShardSize > 0 ? ['sample'] : [];
}
// Returns a name which is safe to use in elasticsearch aggregations for the supplied
// field name. Aggregation names must be alpha-numeric and can only contain '_' and '-' characters,
// so if the supplied field names contains disallowed characters, the provided index
// identifier is used to return a safe 'dummy' name in the format 'field_index' e.g. field_0, field_1
export function getSafeAggregationName(fieldName: string, index: number): string {
return fieldName.match(/^[a-zA-Z0-9-_.]+$/) ? fieldName : `field_${index}`;
}

View file

@ -0,0 +1,28 @@
/*
* 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 { estypes } from '@elastic/elasticsearch';
import { isPopulatedObject } from './object_utils';
import { RUNTIME_FIELD_TYPES } from '../../../../../src/plugins/data/common';
type RuntimeType = typeof RUNTIME_FIELD_TYPES[number];
export function isRuntimeField(arg: unknown): arg is estypes.MappingRuntimeField {
return (
((isPopulatedObject(arg, ['type']) && Object.keys(arg).length === 1) ||
(isPopulatedObject(arg, ['type', 'script']) &&
Object.keys(arg).length === 2 &&
(typeof arg.script === 'string' ||
(isPopulatedObject(arg.script, ['source']) &&
Object.keys(arg.script).length === 1 &&
typeof arg.script.source === 'string')))) &&
RUNTIME_FIELD_TYPES.includes(arg.type as RuntimeType)
);
}
export function isRuntimeMappings(arg: unknown): arg is estypes.MappingRuntimeFields {
return isPopulatedObject(arg) && Object.values(arg).every((d) => isRuntimeField(d));
}

View file

@ -0,0 +1,23 @@
/*
* 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.
*/
/**
* Creates a deterministic number based hash out of a string.
*/
export function stringHash(str: string): number {
let hash = 0;
let chr = 0;
if (str.length === 0) {
return hash;
}
for (let i = 0; i < str.length; i++) {
chr = str.charCodeAt(i);
hash = (hash << 5) - hash + chr; // eslint-disable-line no-bitwise
hash |= 0; // eslint-disable-line no-bitwise
}
return hash < 0 ? hash * -2 : hash;
}

View file

@ -8,5 +8,5 @@
module.exports = {
preset: '@kbn/test',
rootDir: '../../..',
roots: ['<rootDir>/x-pack/plugins/file_data_visualizer'],
roots: ['<rootDir>/x-pack/plugins/data_visualizer'],
};

View file

@ -1,5 +1,5 @@
{
"id": "fileDataVisualizer",
"id": "dataVisualizer",
"version": "8.0.0",
"kibanaVersion": "kibana",
"server": true,
@ -15,7 +15,8 @@
"optionalPlugins": [
"security",
"maps",
"home"
"home",
"lens"
],
"requiredBundles": [
"kibanaReact",

View file

@ -6,9 +6,13 @@
*/
import { lazyLoadModules } from '../lazy_load_bundle';
import { FileDataVisualizer } from '../application';
import type { FileDataVisualizerSpec, IndexDataVisualizerSpec } from '../application';
export async function getFileDataVisualizerComponent(): Promise<typeof FileDataVisualizer> {
export async function getFileDataVisualizerComponent(): Promise<FileDataVisualizerSpec> {
const modules = await lazyLoadModules();
return modules.FileDataVisualizer;
}
export async function getIndexDataVisualizerComponent(): Promise<IndexDataVisualizerSpec> {
const modules = await lazyLoadModules();
return modules.IndexDataVisualizer;
}

View file

@ -0,0 +1,2 @@
@import 'common/components/index';
@import 'file_data_visualizer/index';

View file

@ -0,0 +1,4 @@
@import 'embedded_map/index';
@import 'experimental_badge/index';
@import 'stats_table/index';
@import 'top_values/top_values';

View file

@ -29,7 +29,7 @@ import {
removeCombinedFieldsFromMappings,
removeCombinedFieldsFromPipeline,
} from './utils';
import { FindFileStructureResponse } from '../../../../../file_upload/common';
import { FindFileStructureResponse } from '../../../../../../file_upload/common';
interface Props {
mappingsString: string;
@ -110,7 +110,7 @@ export class CombinedFieldsForm extends Component<Props, State> {
return JSON.parse(this.props.mappingsString);
} catch (error) {
throw new Error(
i18n.translate('xpack.fileDataVisualizer.combinedFieldsForm.mappingsParseError', {
i18n.translate('xpack.dataVisualizer.combinedFieldsForm.mappingsParseError', {
defaultMessage: 'Error parsing mappings: {error}',
values: { error: error.message },
})
@ -123,7 +123,7 @@ export class CombinedFieldsForm extends Component<Props, State> {
return JSON.parse(this.props.pipelineString);
} catch (error) {
throw new Error(
i18n.translate('xpack.fileDataVisualizer.combinedFieldsForm.pipelineParseError', {
i18n.translate('xpack.dataVisualizer.combinedFieldsForm.pipelineParseError', {
defaultMessage: 'Error parsing pipeline: {error}',
values: { error: error.message },
})
@ -149,9 +149,12 @@ export class CombinedFieldsForm extends Component<Props, State> {
};
render() {
const geoPointLabel = i18n.translate('xpack.fileDataVisualizer.geoPointCombinedFieldLabel', {
defaultMessage: 'Add geo point field',
});
const geoPointLabel = i18n.translate(
'xpack.dataVisualizer.file.geoPointForm.combinedFieldLabel',
{
defaultMessage: 'Add geo point field',
}
);
const panels = [
{
id: 0,
@ -176,7 +179,7 @@ export class CombinedFieldsForm extends Component<Props, State> {
];
return (
<EuiFormRow
label={i18n.translate('xpack.fileDataVisualizer.combinedFieldsLabel', {
label={i18n.translate('xpack.dataVisualizer.combinedFieldsLabel', {
defaultMessage: 'Combined fields',
})}
>
@ -192,15 +195,12 @@ export class CombinedFieldsForm extends Component<Props, State> {
iconType="trash"
color="danger"
onClick={this.removeCombinedField.bind(null, idx)}
title={i18n.translate('xpack.fileDataVisualizer.removeCombinedFieldsLabel', {
title={i18n.translate('xpack.dataVisualizer.removeCombinedFieldsLabel', {
defaultMessage: 'Remove combined field',
})}
aria-label={i18n.translate('xpack.dataVisualizer.removeCombinedFieldsLabel', {
defaultMessage: 'Remove combined field',
})}
aria-label={i18n.translate(
'xpack.fileDataVisualizer.removeCombinedFieldsLabel',
{
defaultMessage: 'Remove combined field',
}
)}
/>
</EuiFlexItem>
)}
@ -216,7 +216,7 @@ export class CombinedFieldsForm extends Component<Props, State> {
isDisabled={this.props.isDisabled}
>
<FormattedMessage
id="xpack.fileDataVisualizer.addCombinedFieldsLabel"
id="xpack.dataVisualizer.addCombinedFieldsLabel"
defaultMessage="Add combined field"
/>
</EuiButtonEmpty>

View file

@ -20,10 +20,10 @@ export function CombinedFieldsReadOnlyForm({
}) {
return combinedFields.length ? (
<EuiFormRow
label={i18n.translate('xpack.fileDataVisualizer.combinedFieldsReadOnlyLabel', {
label={i18n.translate('xpack.dataVisualizer.combinedFieldsReadOnlyLabel', {
defaultMessage: 'Combined fields',
})}
helpText={i18n.translate('xpack.fileDataVisualizer.combinedFieldsReadOnlyHelpTextLabel', {
helpText={i18n.translate('xpack.dataVisualizer.combinedFieldsReadOnlyHelpTextLabel', {
defaultMessage: 'Edit combined fields in advanced tab',
})}
>

View file

@ -29,7 +29,7 @@ import {
getFieldNames,
getNameCollisionMsg,
} from './utils';
import { FindFileStructureResponse } from '../../../../../file_upload/common';
import { FindFileStructureResponse } from '../../../../../../file_upload/common';
interface Props {
addCombinedField: (combinedField: CombinedField) => void;
@ -119,7 +119,7 @@ export class GeoPointForm extends Component<Props, State> {
return (
<Fragment>
<EuiFormRow
label={i18n.translate('xpack.fileDataVisualizer.geoPointForm.latFieldLabel', {
label={i18n.translate('xpack.dataVisualizer.file.geoPointForm.latFieldLabel', {
defaultMessage: 'Latitude field',
})}
>
@ -131,7 +131,7 @@ export class GeoPointForm extends Component<Props, State> {
</EuiFormRow>
<EuiFormRow
label={i18n.translate('xpack.fileDataVisualizer.geoPointForm.lonFieldLabel', {
label={i18n.translate('xpack.dataVisualizer.file.geoPointForm.lonFieldLabel', {
defaultMessage: 'Longitude field',
})}
>
@ -143,7 +143,7 @@ export class GeoPointForm extends Component<Props, State> {
</EuiFormRow>
<EuiFormRow
label={i18n.translate('xpack.fileDataVisualizer.geoPointForm.geoPointFieldLabel', {
label={i18n.translate('xpack.dataVisualizer.file.geoPointForm.geoPointFieldLabel', {
defaultMessage: 'Geo point field',
})}
isInvalid={this.state.geoPointFieldError !== ''}
@ -154,7 +154,7 @@ export class GeoPointForm extends Component<Props, State> {
onChange={this.onGeoPointFieldChange}
isInvalid={this.state.geoPointFieldError !== ''}
aria-label={i18n.translate(
'xpack.fileDataVisualizer.geoPointForm.geoPointFieldAriaLabel',
'xpack.dataVisualizer.file.geoPointForm.geoPointFieldAriaLabel',
{
defaultMessage: 'Geo point field, required field',
}
@ -179,7 +179,7 @@ export class GeoPointForm extends Component<Props, State> {
onClick={this.onSubmit}
>
<FormattedMessage
id="xpack.fileDataVisualizer.geoPointForm.submitButtonLabel"
id="xpack.dataVisualizer.file.geoPointForm.submitButtonLabel"
defaultMessage="Add"
/>
</EuiButton>

View file

@ -13,7 +13,7 @@ import {
FindFileStructureResponse,
IngestPipeline,
Mappings,
} from '../../../../../file_upload/common';
} from '../../../../../../file_upload/common';
const COMMON_LAT_NAMES = ['latitude', 'lat'];
const COMMON_LON_NAMES = ['longitude', 'long', 'lon'];
@ -127,7 +127,7 @@ export function createGeoPointCombinedField(
}
export function getNameCollisionMsg(name: string) {
return i18n.translate('xpack.fileDataVisualizer.nameCollisionMsg', {
return i18n.translate('xpack.dataVisualizer.nameCollisionMsg', {
defaultMessage: '"{name}" already exists, please provide a unique name',
values: { name },
});

View file

@ -0,0 +1,172 @@
/*
* 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, { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { Subscription } from 'rxjs';
import { debounce } from 'lodash';
import { EuiSuperDatePicker, OnRefreshProps } from '@elastic/eui';
import {
TimeHistoryContract,
TimeRange,
UI_SETTINGS,
} from '../../../../../../../../src/plugins/data/public';
import { useUrlState } from '../../util/url_state';
import { useDataVisualizerKibana } from '../../../kibana_context';
import { dataVisualizerTimefilterRefresh$ } from '../../../index_data_visualizer/services/timefilter_refresh_service';
interface TimePickerQuickRange {
from: string;
to: string;
display: string;
}
interface Duration {
start: string;
end: string;
}
interface RefreshInterval {
pause: boolean;
value: number;
}
function getRecentlyUsedRangesFactory(timeHistory: TimeHistoryContract) {
return function (): Duration[] {
return (
timeHistory.get()?.map(({ from, to }: TimeRange) => {
return {
start: from,
end: to,
};
}) ?? []
);
};
}
function updateLastRefresh(timeRange: OnRefreshProps) {
dataVisualizerTimefilterRefresh$.next({ lastRefresh: Date.now(), timeRange });
}
export const DatePickerWrapper: FC = () => {
const { services } = useDataVisualizerKibana();
const config = services.uiSettings;
const { timefilter, history } = services.data.query.timefilter;
const [globalState, setGlobalState] = useUrlState('_g');
const getRecentlyUsedRanges = getRecentlyUsedRangesFactory(history);
const refreshInterval: RefreshInterval =
globalState?.refreshInterval ?? timefilter.getRefreshInterval();
// eslint-disable-next-line react-hooks/exhaustive-deps
const setRefreshInterval = useCallback(
debounce((refreshIntervalUpdate: RefreshInterval) => {
setGlobalState('refreshInterval', refreshIntervalUpdate, true);
}, 200),
[setGlobalState]
);
const [time, setTime] = useState(timefilter.getTime());
const [recentlyUsedRanges, setRecentlyUsedRanges] = useState(getRecentlyUsedRanges());
const [isAutoRefreshSelectorEnabled, setIsAutoRefreshSelectorEnabled] = useState(
timefilter.isAutoRefreshSelectorEnabled()
);
const [isTimeRangeSelectorEnabled, setIsTimeRangeSelectorEnabled] = useState(
timefilter.isTimeRangeSelectorEnabled()
);
const dateFormat = config.get('dateFormat');
const timePickerQuickRanges = config.get<TimePickerQuickRange[]>(
UI_SETTINGS.TIMEPICKER_QUICK_RANGES
);
const commonlyUsedRanges = useMemo(
() =>
timePickerQuickRanges.map(({ from, to, display }) => ({
start: from,
end: to,
label: display,
})),
[timePickerQuickRanges]
);
useEffect(() => {
const subscriptions = new Subscription();
const refreshIntervalUpdate$ = timefilter.getRefreshIntervalUpdate$();
if (refreshIntervalUpdate$ !== undefined) {
subscriptions.add(
refreshIntervalUpdate$.subscribe((r) => {
setRefreshInterval(timefilter.getRefreshInterval());
})
);
}
const timeUpdate$ = timefilter.getTimeUpdate$();
if (timeUpdate$ !== undefined) {
subscriptions.add(
timeUpdate$.subscribe((v) => {
setTime(timefilter.getTime());
})
);
}
const enabledUpdated$ = timefilter.getEnabledUpdated$();
if (enabledUpdated$ !== undefined) {
subscriptions.add(
enabledUpdated$.subscribe((w) => {
setIsAutoRefreshSelectorEnabled(timefilter.isAutoRefreshSelectorEnabled());
setIsTimeRangeSelectorEnabled(timefilter.isTimeRangeSelectorEnabled());
})
);
}
return function cleanup() {
subscriptions.unsubscribe();
};
}, [setRefreshInterval, timefilter]);
function updateFilter({ start, end }: Duration) {
const newTime = { from: start, to: end };
// Update timefilter for controllers listening for changes
timefilter.setTime(newTime);
setTime(newTime);
setRecentlyUsedRanges(getRecentlyUsedRanges());
}
function updateInterval({
isPaused: pause,
refreshInterval: value,
}: {
isPaused: boolean;
refreshInterval: number;
}) {
setRefreshInterval({ pause, value });
}
/**
* Enforce pause when it's set to false with 0 refresh interval.
*/
const isPaused = refreshInterval.pause || (!refreshInterval.pause && !refreshInterval.value);
return isAutoRefreshSelectorEnabled || isTimeRangeSelectorEnabled ? (
<div className="mlNavigationMenu__datePickerWrapper">
<EuiSuperDatePicker
start={time.from}
end={time.to}
isPaused={isPaused}
isAutoRefreshOnly={!isTimeRangeSelectorEnabled}
refreshInterval={refreshInterval.value}
onTimeChange={updateFilter}
onRefresh={updateLastRefresh}
onRefreshChange={updateInterval}
recentlyUsedRanges={recentlyUsedRanges}
dateFormat={dateFormat}
commonlyUsedRanges={commonlyUsedRanges}
/>
</div>
) : null;
};

View file

@ -0,0 +1,8 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export { DatePickerWrapper } from './date_picker_wrapper';

View file

@ -41,9 +41,12 @@ export const DocumentCountChart: FC<Props> = ({
timeRangeLatest,
interval,
}) => {
const seriesName = i18n.translate('xpack.ml.fieldDataCard.documentCountChart.seriesLabel', {
defaultMessage: 'document count',
});
const seriesName = i18n.translate(
'xpack.dataVisualizer.dataGrid.field.documentCountChart.seriesLabel',
{
defaultMessage: 'document count',
}
);
const xDomain = {
min: timeRangeEarliest,
@ -65,10 +68,11 @@ export const DocumentCountChart: FC<Props> = ({
];
}
return chartPoints;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [chartPoints, timeRangeEarliest, timeRangeLatest, interval]);
return (
<div style={{ width: width ?? '100%' }} data-test-subj="mlFieldDataDocumentCountChart">
<div style={{ width: width ?? '100%' }} data-test-subj="dataVisualizerDocumentCountChart">
<Chart
size={{
width: '100%',

View file

@ -6,9 +6,9 @@
*/
import React, { FC } from 'react';
import { DocumentCountChart, DocumentCountChartPoint } from '../document_count_chart';
import { TotalCountHeader } from '../../total_count_header';
import { FieldVisConfig, FileBasedFieldVisConfig } from '../../../../stats_table/types';
import { DocumentCountChart, DocumentCountChartPoint } from './document_count_chart';
import { FieldVisConfig, FileBasedFieldVisConfig } from '../stats_table/types';
import { TotalCountHeader } from './total_count_header';
export interface Props {
config?: FieldVisConfig | FileBasedFieldVisConfig;

View file

@ -6,4 +6,3 @@
*/
export { DocumentCountContent } from './document_count_content';
export { NotInDocsContent } from './not_in_docs_content';

View file

@ -12,15 +12,15 @@ import React from 'react';
export const TotalCountHeader = ({ totalCount }: { totalCount: number }) => {
return (
<EuiFlexItem>
<EuiText size="s" data-test-subj="mlDataVisualizerTotalDocCountHeader">
<EuiText size="s" data-test-subj="dataVisualizerTotalDocCountHeader">
<FormattedMessage
id="xpack.ml.datavisualizer.searchPanel.totalDocCountLabel"
id="xpack.dataVisualizer.searchPanel.totalDocCountLabel"
defaultMessage="Total documents: {strongTotalCount}"
values={{
strongTotalCount: (
<strong data-test-subj="mlDataVisualizerTotalDocCount">
<strong data-test-subj="dataVisualizerTotalDocCount">
<FormattedMessage
id="xpack.ml.datavisualizer.searchPanel.totalDocCountNumber"
id="xpack.dataVisualizer.searchPanel.totalDocCountNumber"
defaultMessage="{totalCount, plural, one {#} other {#}}"
values={{ totalCount }}
/>

View file

@ -8,22 +8,22 @@
import React, { useEffect, useRef, useState } from 'react';
import { htmlIdGenerator } from '@elastic/eui';
import { LayerDescriptor } from '../../../../../maps/common/descriptor_types';
import { INITIAL_LOCATION } from '../../../../../maps/common/constants';
import { LayerDescriptor } from '../../../../../../maps/common/descriptor_types';
import { INITIAL_LOCATION } from '../../../../../../maps/common/constants';
import {
MapEmbeddable,
MapEmbeddableInput,
MapEmbeddableOutput,
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
} from '../../../../../maps/public/embeddable';
import { MAP_SAVED_OBJECT_TYPE, RenderTooltipContentParams } from '../../../../../maps/public';
} from '../../../../../../maps/public/embeddable';
import { MAP_SAVED_OBJECT_TYPE, RenderTooltipContentParams } from '../../../../../../maps/public';
import {
EmbeddableFactory,
ErrorEmbeddable,
isErrorEmbeddable,
ViewMode,
} from '../../../../../../../src/plugins/embeddable/public';
import { useFileDataVisualizerKibana } from '../../kibana_context';
} from '../../../../../../../../src/plugins/embeddable/public';
import { useDataVisualizerKibana } from '../../../kibana_context';
export function EmbeddedMapComponent({
layerList,
@ -41,7 +41,7 @@ export function EmbeddedMapComponent({
const {
services: { embeddable: embeddablePlugin, maps: mapsPlugin },
} = useFileDataVisualizerKibana();
} = useDataVisualizerKibana();
const factory:
| EmbeddableFactory<MapEmbeddableInput, MapEmbeddableOutput, MapEmbeddable>
@ -143,7 +143,7 @@ export function EmbeddedMapComponent({
return (
<div
data-test-subj="mlEmbeddedMapContent"
data-test-subj="dataVisualizerEmbeddedMapContent"
className="embeddedMapContent"
ref={embeddableRoot}
/>

View file

@ -23,7 +23,7 @@ export const ExamplesList: FC<Props> = ({ examples }) => {
if (examples.length === 0) {
examplesContent = (
<FormattedMessage
id="xpack.fileDataVisualizer.fieldDataCard.examplesList.noExamplesMessage"
id="xpack.dataVisualizer.dataGrid.field.examplesList.noExamplesMessage"
defaultMessage="No examples were obtained for this field"
/>
);
@ -41,10 +41,10 @@ export const ExamplesList: FC<Props> = ({ examples }) => {
}
return (
<div data-test-subj="mlFieldDataExamplesList">
<div data-test-subj="dataVisualizerFieldDataExamplesList">
<ExpandedRowFieldHeader>
<FormattedMessage
id="xpack.fileDataVisualizer.fieldDataCard.examplesList.title"
id="xpack.dataVisualizer.dataGrid.field.examplesList.title"
defaultMessage="{numExamples, plural, one {Value} other {Examples}}"
values={{
numExamples: examples.length,

View file

@ -16,7 +16,7 @@ import {
NumberContent,
} from '../stats_table/components/field_data_expanded_row';
import { GeoPointContent } from './geo_point_content/geo_point_content';
import { JOB_FIELD_TYPES } from '../../../../common';
import { JOB_FIELD_TYPES } from '../../../../../common';
import type { FileBasedFieldVisConfig } from '../stats_table/types/field_vis_config';
export const FileBasedDataVisualizerExpandedRow = ({ item }: { item: FileBasedFieldVisConfig }) => {
@ -54,7 +54,7 @@ export const FileBasedDataVisualizerExpandedRow = ({ item }: { item: FileBasedFi
return (
<div
className="dataVisualizerFieldExpandedRow"
data-test-subj={`mlDataVisualizerFieldExpandedRow-${fieldName}`}
data-test-subj={`dataVisualizerFieldExpandedRow-${fieldName}`}
>
{getCardContent()}
</div>

View file

@ -8,7 +8,7 @@
import { Feature, Point } from 'geojson';
import { euiPaletteColorBlind } from '@elastic/eui';
import { DEFAULT_GEO_REGEX } from './geo_point_content';
import { SOURCE_TYPES } from '../../../../../../maps/common/constants';
import { SOURCE_TYPES } from '../../../../../../../maps/common/constants';
export const convertWKTGeoToLonLat = (
value: string | number

View file

@ -60,7 +60,7 @@ export const GeoPointContent: FC<FieldDataRowProps> = ({ config }) => {
}
}, [config]);
return (
<ExpandedRowContent dataTestSubj={'mlDVGeoPointContent'}>
<ExpandedRowContent dataTestSubj={'dataVisualizerGeoPointContent'}>
<DocumentStatsTable config={config} />
{formattedResults && Array.isArray(formattedResults.examples) && (
<EuiFlexItem>
@ -70,7 +70,7 @@ export const GeoPointContent: FC<FieldDataRowProps> = ({ config }) => {
{formattedResults && Array.isArray(formattedResults.layerList) && (
<EuiFlexItem
className={'dataVisualizerMapWrapper'}
data-test-subj={'mlDataVisualizerEmbeddedMap'}
data-test-subj={'dataVisualizerEmbeddedMap'}
>
<EmbeddedMapComponent layerList={formattedResults.layerList} />
</EuiFlexItem>

View file

@ -6,21 +6,20 @@
*/
import React, { FC, useEffect, useState } from 'react';
import { EuiFlexItem } from '@elastic/eui';
import { ExamplesList } from '../../../index_based/components/field_data_row/examples_list';
import { MlEmbeddedMapComponent } from '../../../../components/ml_embedded_map';
import { ML_JOB_FIELD_TYPES } from '../../../../../../common/constants/field_types';
import { ES_GEO_FIELD_TYPE } from '../../../../../../../maps/common/constants';
import { useMlKibana } from '../../../../contexts/kibana';
import { DocumentStatsTable } from '../../../stats_table/components/field_data_expanded_row/document_stats';
import { ExpandedRowContent } from '../../../stats_table/components/field_data_expanded_row/expanded_row_content';
import type { CombinedQuery } from '../../common';
import type { IndexPattern } from '../../../../../../../../../src/plugins/data/common/index_patterns/index_patterns';
import type { LayerDescriptor } from '../../../../../../../maps/common/descriptor_types';
import type { FieldVisConfig } from '../../../stats_table/types';
import { IndexPattern } from '../../../../../../../../../src/plugins/data/common/index_patterns/index_patterns';
import { CombinedQuery } from '../../../../index_data_visualizer/types/combined_query';
import { ExpandedRowContent } from '../../stats_table/components/field_data_expanded_row/expanded_row_content';
import { DocumentStatsTable } from '../../stats_table/components/field_data_expanded_row/document_stats';
import { ExamplesList } from '../../examples_list';
import { FieldVisConfig } from '../../stats_table/types';
import { LayerDescriptor } from '../../../../../../../maps/common/descriptor_types';
import { useDataVisualizerKibana } from '../../../../kibana_context';
import { JOB_FIELD_TYPES } from '../../../../../../common';
import { ES_GEO_FIELD_TYPE } from '../../../../../../../maps/common';
import { EmbeddedMapComponent } from '../../embedded_map';
export const GeoPointContent: FC<{
export const GeoPointContentWithMap: FC<{
config: FieldVisConfig;
indexPattern: IndexPattern | undefined;
combinedQuery: CombinedQuery;
@ -29,7 +28,7 @@ export const GeoPointContent: FC<{
const [layerList, setLayerList] = useState<LayerDescriptor[]>([]);
const {
services: { maps: mapsPlugin },
} = useMlKibana();
} = useDataVisualizerKibana();
// Update the layer list with updated geo points upon refresh
useEffect(() => {
@ -38,8 +37,7 @@ export const GeoPointContent: FC<{
indexPattern?.id !== undefined &&
config !== undefined &&
config.fieldName !== undefined &&
(config.type === ML_JOB_FIELD_TYPES.GEO_POINT ||
config.type === ML_JOB_FIELD_TYPES.GEO_SHAPE)
(config.type === JOB_FIELD_TYPES.GEO_POINT || config.type === JOB_FIELD_TYPES.GEO_SHAPE)
) {
const params = {
indexPatternId: indexPattern.id,
@ -59,18 +57,19 @@ export const GeoPointContent: FC<{
}
}
updateIndexPatternSearchLayer();
}, [indexPattern, config.fieldName, combinedQuery]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [indexPattern, combinedQuery, config, mapsPlugin]);
if (stats?.examples === undefined) return null;
return (
<ExpandedRowContent dataTestSubj={'mlDVIndexBasedMapContent'}>
<ExpandedRowContent dataTestSubj={'dataVisualizerIndexBasedMapContent'}>
<DocumentStatsTable config={config} />
<EuiFlexItem style={{ maxWidth: '50%' }}>
<ExamplesList examples={stats.examples} />
</EuiFlexItem>
<EuiFlexItem className={'mlDataVisualizerMapWrapper'}>
<MlEmbeddedMapComponent layerList={layerList} />
<EuiFlexItem className={'dataVisualizerMapWrapper'}>
<EmbeddedMapComponent layerList={layerList} />
</EuiFlexItem>
</ExpandedRowContent>
);

View file

@ -5,4 +5,4 @@
* 2.0.
*/
export { FileDataVisualizer } from './file_datavisualizer';
export { GeoPointContentWithMap } from './geo_point_content_with_map';

View file

@ -6,10 +6,8 @@
*/
import React from 'react';
import { ML_JOB_FIELD_TYPES } from '../../../../../../common/constants/field_types';
import { LoadingIndicator } from '../field_data_row/loading_indicator';
import { NotInDocsContent } from '../field_data_row/content_types';
import { GeoPointContentWithMap } from './geo_point_content_with_map';
import { JOB_FIELD_TYPES } from '../../../../../common';
import {
BooleanContent,
DateContent,
@ -18,11 +16,12 @@ import {
NumberContent,
OtherContent,
TextContent,
} from '../../../stats_table/components/field_data_expanded_row';
import { GeoPointContent } from './geo_point_content';
import type { CombinedQuery } from '../../common';
import type { IndexPattern } from '../../../../../../../../../src/plugins/data/common/index_patterns/index_patterns';
import type { FieldVisConfig } from '../../../stats_table/types';
} from '../stats_table/components/field_data_expanded_row';
import { NotInDocsContent } from '../not_in_docs_content';
import { FieldVisConfig } from '../stats_table/types';
import { IndexPattern } from '../../../../../../../../src/plugins/data/common/index_patterns/index_patterns';
import { CombinedQuery } from '../../../index_data_visualizer/types/combined_query';
import { LoadingIndicator } from '../loading_indicator';
export const IndexBasedDataVisualizerExpandedRow = ({
item,
@ -42,32 +41,32 @@ export const IndexBasedDataVisualizerExpandedRow = ({
}
switch (type) {
case ML_JOB_FIELD_TYPES.NUMBER:
case JOB_FIELD_TYPES.NUMBER:
return <NumberContent config={config} />;
case ML_JOB_FIELD_TYPES.BOOLEAN:
case JOB_FIELD_TYPES.BOOLEAN:
return <BooleanContent config={config} />;
case ML_JOB_FIELD_TYPES.DATE:
case JOB_FIELD_TYPES.DATE:
return <DateContent config={config} />;
case ML_JOB_FIELD_TYPES.GEO_POINT:
case ML_JOB_FIELD_TYPES.GEO_SHAPE:
case JOB_FIELD_TYPES.GEO_POINT:
case JOB_FIELD_TYPES.GEO_SHAPE:
return (
<GeoPointContent
<GeoPointContentWithMap
config={config}
indexPattern={indexPattern}
combinedQuery={combinedQuery}
/>
);
case ML_JOB_FIELD_TYPES.IP:
case JOB_FIELD_TYPES.IP:
return <IpContent config={config} />;
case ML_JOB_FIELD_TYPES.KEYWORD:
case JOB_FIELD_TYPES.KEYWORD:
return <KeywordContent config={config} />;
case ML_JOB_FIELD_TYPES.TEXT:
case JOB_FIELD_TYPES.TEXT:
return <TextContent config={config} />;
default:
@ -77,8 +76,8 @@ export const IndexBasedDataVisualizerExpandedRow = ({
return (
<div
className="mlDataVisualizerFieldExpandedRow"
data-test-subj={`mlDataVisualizerFieldExpandedRow-${fieldName}`}
className="dataVisualizerFieldExpandedRow"
data-test-subj={`dataVisualizerFieldExpandedRow-${fieldName}`}
>
{loading === true ? <LoadingIndicator /> : getCardContent()}
</div>

View file

@ -17,7 +17,7 @@ export const ExperimentalBadge: FC<{ tooltipContent: string }> = ({ tooltipConte
className="experimental-badge"
label={
<FormattedMessage
id="xpack.fileDataVisualizer.experimentalBadge.experimentalLabel"
id="xpack.dataVisualizer.experimentalBadge.experimentalLabel"
defaultMessage="Experimental"
/>
}

View file

@ -8,14 +8,11 @@
import { EuiFlexGroup, EuiFlexItem, EuiSwitch } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import React, { FC } from 'react';
import {
MetricFieldsCount,
TotalFieldsCount,
} from '../../../stats_table/components/field_count_stats';
import type {
TotalFieldsCountProps,
MetricFieldsCountProps,
} from '../../../stats_table/components/field_count_stats';
TotalFieldsCountProps,
} from '../stats_table/components/field_count_stats';
import { MetricFieldsCount, TotalFieldsCount } from '../stats_table/components/field_count_stats';
interface Props extends TotalFieldsCountProps, MetricFieldsCountProps {
showEmptyFields: boolean;
@ -32,16 +29,16 @@ export const FieldCountPanel: FC<Props> = ({
alignItems="center"
gutterSize="xs"
style={{ marginLeft: 4 }}
data-test-subj="mlDataVisualizerFieldCountPanel"
data-test-subj="dataVisualizerFieldCountPanel"
>
<TotalFieldsCount fieldsCountStats={fieldsCountStats} />
<MetricFieldsCount metricsStats={metricsStats} />
<EuiFlexItem>
<EuiSwitch
data-test-subj="mlDataVisualizerShowEmptyFieldsSwitch"
data-test-subj="dataVisualizerShowEmptyFieldsSwitch"
label={
<FormattedMessage
id="xpack.ml.dataVisualizer.searchPanel.showEmptyFields"
id="xpack.dataVisualizer.searchPanel.showEmptyFields"
defaultMessage="Show empty fields"
/>
}

View file

@ -8,28 +8,24 @@
import { i18n } from '@kbn/i18n';
import { Action } from '@elastic/eui/src/components/basic_table/action_types';
import { getCompatibleLensDataType, getLensAttributes } from './lens_utils';
import type { CombinedQuery } from '../../../common';
import type { IIndexPattern } from '../../../../../../../../../../src/plugins/data/common/index_patterns';
import type { LensPublicStart } from '../../../../../../../../lens/public';
import type { FieldVisConfig } from '../../../../stats_table/types';
import { IndexPattern } from '../../../../../../../../../src/plugins/data/common/index_patterns/index_patterns';
import { CombinedQuery } from '../../../../index_data_visualizer/types/combined_query';
import { FieldVisConfig } from '../../stats_table/types';
import { LensPublicStart } from '../../../../../../../lens/public';
export function getActions(
indexPattern: IIndexPattern,
indexPattern: IndexPattern,
lensPlugin: LensPublicStart,
combinedQuery: CombinedQuery
): Array<Action<FieldVisConfig>> {
const canUseLensEditor = lensPlugin.canUseEditor();
return [
{
name: i18n.translate('xpack.ml.dataVisualizer.indexBasedDataGrid.exploreInLensTitle', {
name: i18n.translate('xpack.dataVisualizer.index.dataGrid.exploreInLensTitle', {
defaultMessage: 'Explore in Lens',
}),
description: i18n.translate('xpack.dataVisualizer.index.dataGrid.exploreInLensDescription', {
defaultMessage: 'Explore in Lens',
}),
description: i18n.translate(
'xpack.ml.dataVisualizer.indexBasedDataGrid.exploreInLensDescription',
{
defaultMessage: 'Explore in Lens',
}
),
type: 'icon',
icon: 'lensApp',
available: (item: FieldVisConfig) =>
@ -38,12 +34,12 @@ export function getActions(
const lensAttributes = getLensAttributes(indexPattern, combinedQuery, item);
if (lensAttributes) {
lensPlugin.navigateToPrefilledEditor({
id: `ml-dataVisualizer-${item.fieldName}`,
id: `dataVisualizer-${item.fieldName}`,
attributes: lensAttributes,
});
}
},
'data-test-subj': 'mlActionButtonViewInLens',
'data-test-subj': 'dataVisualizerActionViewInLensButton',
},
];
}

View file

@ -6,25 +6,28 @@
*/
import { i18n } from '@kbn/i18n';
import { ML_JOB_FIELD_TYPES } from '../../../../../../../common/constants/field_types';
import type { TypedLensByValueInput } from '../../../../../../../../lens/public';
import type { FieldVisConfig } from '../../../../stats_table/types';
import type { IndexPatternColumn, XYLayerConfig } from '../../../../../../../../lens/public';
import type { CombinedQuery } from '../../../common';
import type { IIndexPattern } from '../../../../../../../../../../src/plugins/data/common/index_patterns';
import type { IndexPattern } from '../../../../../../../../../src/plugins/data/common/index_patterns/index_patterns';
import type { CombinedQuery } from '../../../../index_data_visualizer/types/combined_query';
import type {
IndexPatternColumn,
TypedLensByValueInput,
XYLayerConfig,
} from '../../../../../../../lens/public';
import { FieldVisConfig } from '../../stats_table/types';
import { JOB_FIELD_TYPES } from '../../../../../../common';
interface ColumnsAndLayer {
columns: Record<string, IndexPatternColumn>;
layer: XYLayerConfig;
}
const TOP_VALUES_LABEL = i18n.translate('xpack.ml.dataVisualizer.lensChart.topValuesLabel', {
const TOP_VALUES_LABEL = i18n.translate('xpack.dataVisualizer.index.lensChart.topValuesLabel', {
defaultMessage: 'Top values',
});
const COUNT = i18n.translate('xpack.ml.dataVisualizer.lensChart.countLabel', {
const COUNT = i18n.translate('xpack.dataVisualizer.index.lensChart.countLabel', {
defaultMessage: 'Count',
});
export function getNumberSettings(item: FieldVisConfig, defaultIndexPattern: IIndexPattern) {
export function getNumberSettings(item: FieldVisConfig, defaultIndexPattern: IndexPattern) {
// if index has no timestamp field
if (defaultIndexPattern.timeFieldName === undefined) {
const columns: Record<string, IndexPatternColumn> = {
@ -62,7 +65,7 @@ export function getNumberSettings(item: FieldVisConfig, defaultIndexPattern: IIn
col2: {
dataType: 'number',
isBucketed: false,
label: i18n.translate('xpack.ml.dataVisualizer.lensChart.averageOfLabel', {
label: i18n.translate('xpack.dataVisualizer.index.lensChart.averageOfLabel', {
defaultMessage: 'Average of {fieldName}',
values: { fieldName: item.fieldName },
}),
@ -186,19 +189,19 @@ export function getBooleanSettings(item: FieldVisConfig) {
export function getCompatibleLensDataType(type: FieldVisConfig['type']): string | undefined {
let lensType: string | undefined;
switch (type) {
case ML_JOB_FIELD_TYPES.KEYWORD:
case JOB_FIELD_TYPES.KEYWORD:
lensType = 'string';
break;
case ML_JOB_FIELD_TYPES.DATE:
case JOB_FIELD_TYPES.DATE:
lensType = 'date';
break;
case ML_JOB_FIELD_TYPES.NUMBER:
case JOB_FIELD_TYPES.NUMBER:
lensType = 'number';
break;
case ML_JOB_FIELD_TYPES.IP:
case JOB_FIELD_TYPES.IP:
lensType = 'ip';
break;
case ML_JOB_FIELD_TYPES.BOOLEAN:
case JOB_FIELD_TYPES.BOOLEAN:
lensType = 'string';
break;
default:
@ -210,20 +213,20 @@ export function getCompatibleLensDataType(type: FieldVisConfig['type']): string
function getColumnsAndLayer(
fieldType: FieldVisConfig['type'],
item: FieldVisConfig,
defaultIndexPattern: IIndexPattern
defaultIndexPattern: IndexPattern
): ColumnsAndLayer | undefined {
if (item.fieldName === undefined) return;
if (fieldType === ML_JOB_FIELD_TYPES.DATE) {
if (fieldType === JOB_FIELD_TYPES.DATE) {
return getDateSettings(item);
}
if (fieldType === ML_JOB_FIELD_TYPES.NUMBER) {
if (fieldType === JOB_FIELD_TYPES.NUMBER) {
return getNumberSettings(item, defaultIndexPattern);
}
if (fieldType === ML_JOB_FIELD_TYPES.IP || fieldType === ML_JOB_FIELD_TYPES.KEYWORD) {
if (fieldType === JOB_FIELD_TYPES.IP || fieldType === JOB_FIELD_TYPES.KEYWORD) {
return getKeywordSettings(item);
}
if (fieldType === ML_JOB_FIELD_TYPES.BOOLEAN) {
if (fieldType === JOB_FIELD_TYPES.BOOLEAN) {
return getBooleanSettings(item);
}
}
@ -231,7 +234,7 @@ function getColumnsAndLayer(
// currently only supports the following types:
// 'document' | 'string' | 'number' | 'date' | 'boolean' | 'ip'
export function getLensAttributes(
defaultIndexPattern: IIndexPattern | undefined,
defaultIndexPattern: IndexPattern | undefined,
combinedQuery: CombinedQuery,
item: FieldVisConfig
): TypedLensByValueInput['attributes'] | undefined {
@ -244,7 +247,7 @@ export function getLensAttributes(
return {
visualizationType: 'lnsXY',
title: i18n.translate('xpack.ml.dataVisualizer.lensChart.chartTitle', {
title: i18n.translate('xpack.dataVisualizer.index.lensChart.chartTitle', {
defaultMessage: 'Lens for {fieldName}',
values: { fieldName: item.fieldName },
}),

View file

@ -24,26 +24,20 @@ export const FileBasedNumberContentPreview = ({ config }: { config: FileBasedFie
<EuiFlexGroup gutterSize="xs">
<EuiFlexItem>
<b>
<FormattedMessage
id="xpack.fileDataVisualizer.fieldStatsCard.minTitle"
defaultMessage="min"
/>
<FormattedMessage id="xpack.dataVisualizer.fieldStats.minTitle" defaultMessage="min" />
</b>
</EuiFlexItem>
<EuiFlexItem>
<b>
<FormattedMessage
id="xpack.fileDataVisualizer.fieldStatsCard.medianTitle"
id="xpack.dataVisualizer.fieldStats.medianTitle"
defaultMessage="median"
/>
</b>
</EuiFlexItem>
<EuiFlexItem>
<b>
<FormattedMessage
id="xpack.fileDataVisualizer.fieldStatsCard.maxTitle"
defaultMessage="max"
/>
<FormattedMessage id="xpack.dataVisualizer.fieldStats.maxTitle" defaultMessage="max" />
</b>
</EuiFlexItem>
</EuiFlexGroup>

View file

@ -26,7 +26,7 @@ export const DataVisualizerFieldNamesFilter: FC<Props> = ({
}) => {
const fieldNameTitle = useMemo(
() =>
i18n.translate('xpack.fileDataVisualizer.fieldNameSelect', {
i18n.translate('xpack.dataVisualizer.fieldNameSelect', {
defaultMessage: 'Field name',
}),
[]
@ -42,7 +42,7 @@ export const DataVisualizerFieldNamesFilter: FC<Props> = ({
options={options}
onChange={setVisibleFieldNames}
checkedOptions={visibleFieldNames}
dataTestSubj={'mlDataVisualizerFieldNameSelect'}
dataTestSubj={'dataVisualizerFieldNameSelect'}
/>
);
};

View file

@ -9,7 +9,7 @@ import React from 'react';
import { mount, shallow } from 'enzyme';
import { FieldTypeIcon } from './field_type_icon';
import { JOB_FIELD_TYPES } from '../../../../common';
import { JOB_FIELD_TYPES } from '../../../../../common';
describe('FieldTypeIcon', () => {
test(`render component when type matches a field type`, () => {

View file

@ -12,8 +12,8 @@ import { EuiToken, EuiToolTip } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { getJobTypeAriaLabel } from '../../util/field_types_utils';
import { JOB_FIELD_TYPES } from '../../../../common';
import type { JobFieldType } from '../../../../common';
import { JOB_FIELD_TYPES } from '../../../../../common';
import type { JobFieldType } from '../../../../../common';
interface FieldTypeIconProps {
tooltipEnabled: boolean;
@ -91,7 +91,7 @@ export const FieldTypeIcon: FC<FieldTypeIconProps> = ({
return (
<EuiToolTip
position="left"
content={i18n.translate('xpack.fileDataVisualizer.fieldTypeIcon.fieldTypeTooltip', {
content={i18n.translate('xpack.dataVisualizer.fieldTypeIcon.fieldTypeTooltip', {
defaultMessage: '{type} type',
values: { type },
})}

View file

@ -14,7 +14,7 @@ import type {
FileBasedUnknownFieldVisConfig,
} from '../stats_table/types/field_vis_config';
import { FieldTypeIcon } from '../field_type_icon';
import { JOB_FIELD_TYPES } from '../../../../common';
import { JOB_FIELD_TYPES } from '../../../../../common';
const JOB_FIELD_TYPES_OPTIONS = {
[JOB_FIELD_TYPES.BOOLEAN]: { name: 'Boolean', icon: 'tokenBoolean' },
@ -41,7 +41,7 @@ export const DataVisualizerFieldTypesFilter: FC<Props> = ({
}) => {
const fieldNameTitle = useMemo(
() =>
i18n.translate('xpack.fileDataVisualizer.fieldTypeSelect', {
i18n.translate('xpack.dataVisualizer.fieldTypeSelect', {
defaultMessage: 'Field type',
}),
[]
@ -87,7 +87,7 @@ export const DataVisualizerFieldTypesFilter: FC<Props> = ({
options={options}
onChange={setVisibleFieldTypes}
checkedOptions={visibleFieldTypes}
dataTestSubj={'mlDataVisualizerFieldTypeSelect'}
dataTestSubj={'dataVisualizerFieldTypeSelect'}
/>
);
};

View file

@ -5,10 +5,10 @@
* 2.0.
*/
import { FindFileStructureResponse } from '../../../../../file_upload/common';
import { FindFileStructureResponse } from '../../../../../../file_upload/common';
import { getFieldNames, getSupportedFieldType } from './get_field_names';
import { FileBasedFieldVisConfig } from '../stats_table/types';
import { JOB_FIELD_TYPES } from '../../../../common';
import { JOB_FIELD_TYPES } from '../../../../../common';
import { roundToDecimalPlace } from '../utils';
export function createFields(results: FindFileStructureResponse) {

View file

@ -7,8 +7,8 @@
import React, { useMemo, FC, useState } from 'react';
import { EuiFlexGroup, EuiSpacer } from '@elastic/eui';
import type { FindFileStructureResponse } from '../../../../../file_upload/common';
import type { DataVisualizerTableState } from '../../../../common';
import type { FindFileStructureResponse } from '../../../../../../file_upload/common';
import type { DataVisualizerTableState } from '../../../../../common';
import { DataVisualizerTable, ItemIdToExpandedRowMap } from '../stats_table';
import type { FileBasedFieldVisConfig } from '../stats_table/types/field_vis_config';
import { FileBasedDataVisualizerExpandedRow } from '../expanded_row';
@ -85,14 +85,14 @@ export const FieldsStatsGrid: FC<Props> = ({ results }) => {
alignItems="center"
gutterSize="xs"
style={{ marginLeft: 4 }}
data-test-subj="mlDataVisualizerFieldCountPanel"
data-test-subj="dataVisualizerFieldCountPanel"
>
<TotalFieldsCount fieldsCountStats={fieldsCountStats} />
<MetricFieldsCount metricsStats={metricsStats} />
<EuiFlexGroup
gutterSize="xs"
data-test-subj="mlDataVisualizerFieldCountPanel"
data-test-subj="dataVisualizerFieldCountPanel"
justifyContent={'flexEnd'}
>
<DataVisualizerFieldNamesFilter

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { JOB_FIELD_TYPES } from '../../../../common';
import { JOB_FIELD_TYPES } from '../../../../../common';
import type {
FileBasedFieldVisConfig,
FileBasedUnknownFieldVisConfig,

View file

@ -6,10 +6,10 @@
*/
import { difference } from 'lodash';
import { ES_FIELD_TYPES } from '../../../../../../../src/plugins/data/common';
import type { FindFileStructureResponse } from '../../../../../file_upload/common';
import type { JobFieldType } from '../../../../common';
import { JOB_FIELD_TYPES } from '../../../../common';
import { ES_FIELD_TYPES } from '../../../../../../../../src/plugins/data/common';
import type { FindFileStructureResponse } from '../../../../../../file_upload/common';
import type { JobFieldType } from '../../../../../common';
import { JOB_FIELD_TYPES } from '../../../../../common';
export function getFieldNames(results: FindFileStructureResponse) {
const { mappings, field_stats: fieldStats, column_names: columnNames } = results;

View file

@ -6,7 +6,7 @@
*/
import { i18n } from '@kbn/i18n';
import { FindFileStructureResponse } from '../../../../../file_upload/common';
import { FindFileStructureResponse } from '../../../../../../file_upload/common';
export function createFilebeatConfig(
index: string,
@ -36,7 +36,7 @@ export function createFilebeatConfig(
}
function getPaths() {
const txt = i18n.translate('xpack.fileDataVisualizer.fileBeatConfig.paths', {
const txt = i18n.translate('xpack.dataVisualizer.fileBeatConfig.paths', {
defaultMessage: 'add path to your files here',
});
return [' paths:', ` - '<${txt}>'`];

View file

@ -22,8 +22,8 @@ import {
EuiCopy,
} from '@elastic/eui';
import { createFilebeatConfig } from './filebeat_config';
import { useFileDataVisualizerKibana } from '../../kibana_context'; // copy context?
import { FindFileStructureResponse } from '../../../../../file_upload/common';
import { useDataVisualizerKibana } from '../../../kibana_context'; // copy context?
import { FindFileStructureResponse } from '../../../../../../file_upload/common';
export enum EDITOR_MODE {
HIDDEN,
@ -48,7 +48,7 @@ export const FilebeatConfigFlyout: FC<Props> = ({
const [username, setUsername] = useState<string | null>(null);
const {
services: { security },
} = useFileDataVisualizerKibana();
} = useDataVisualizerKibana();
useEffect(() => {
if (security !== undefined) {
@ -75,7 +75,7 @@ export const FilebeatConfigFlyout: FC<Props> = ({
<EuiFlexItem grow={false}>
<EuiButtonEmpty iconType="cross" onClick={closeFlyout} flush="left">
<FormattedMessage
id="xpack.fileDataVisualizer.fileBeatConfigFlyout.closeButton"
id="xpack.dataVisualizer.fileBeatConfigFlyout.closeButton"
defaultMessage="Close"
/>
</EuiButtonEmpty>
@ -85,7 +85,7 @@ export const FilebeatConfigFlyout: FC<Props> = ({
{(copy) => (
<EuiButton onClick={copy}>
<FormattedMessage
id="xpack.fileDataVisualizer.fileBeatConfigFlyout.copyButton"
id="xpack.dataVisualizer.fileBeatConfigFlyout.copyButton"
defaultMessage="Copy to clipboard"
/>
</EuiButton>
@ -108,7 +108,7 @@ const Contents: FC<{
<EuiTitle size="s">
<h5>
<FormattedMessage
id="xpack.fileDataVisualizer.resultsLinks.fileBeatConfigTitle"
id="xpack.dataVisualizer.file.resultsLinks.fileBeatConfigTitle"
defaultMessage="Filebeat configuration"
/>
</h5>
@ -116,14 +116,14 @@ const Contents: FC<{
<EuiSpacer size="s" />
<p>
<FormattedMessage
id="xpack.fileDataVisualizer.resultsLinks.fileBeatConfigTopText1"
id="xpack.dataVisualizer.file.resultsLinks.fileBeatConfigTopText1"
defaultMessage="Additional data can be uploaded to the {index} index using Filebeat."
values={{ index: <EuiCode>{index}</EuiCode> }}
/>
</p>
<p>
<FormattedMessage
id="xpack.fileDataVisualizer.resultsLinks.fileBeatConfigTopText2"
id="xpack.dataVisualizer.file.resultsLinks.fileBeatConfigTopText2"
defaultMessage="Modify {filebeatYml} to set the connection information:"
values={{ filebeatYml: <EuiCode>filebeat.yml</EuiCode> }}
/>
@ -137,7 +137,7 @@ const Contents: FC<{
<p>
{username === null ? (
<FormattedMessage
id="xpack.fileDataVisualizer.resultsLinks.fileBeatConfigBottomTextNoUsername"
id="xpack.dataVisualizer.file.resultsLinks.fileBeatConfigBottomTextNoUsername"
defaultMessage="Where {esUrl} is the URL of Elasticsearch."
values={{
esUrl: <EuiCode>{'<es_url>'}</EuiCode>,
@ -145,7 +145,7 @@ const Contents: FC<{
/>
) : (
<FormattedMessage
id="xpack.fileDataVisualizer.resultsLinks.fileBeatConfigBottomText"
id="xpack.dataVisualizer.file.resultsLinks.fileBeatConfigBottomText"
defaultMessage="Where {password} is the password of the {user} user, {esUrl} is the URL of Elasticsearch."
values={{
user: <EuiCode>{username}</EuiCode>,

View file

@ -0,0 +1,37 @@
/*
* 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, { FC, useEffect } from 'react';
import { i18n } from '@kbn/i18n';
import { useDataVisualizerKibana } from '../../../kibana_context';
interface HelpMenuProps {
docLink: string;
}
// Component for adding a documentation link to the help menu
export const HelpMenu: FC<HelpMenuProps> = React.memo(({ docLink }) => {
const { chrome } = useDataVisualizerKibana().services;
useEffect(() => {
chrome.setHelpExtension({
appName: i18n.translate('xpack.dataVisualizer.chrome.help.appName', {
defaultMessage: 'Data Visualizer',
}),
links: [
{
href: docLink,
linkType: 'documentation',
},
],
});
}, [chrome, docLink]);
return null;
});
HelpMenu.displayName = 'HelpMenu';

View file

@ -0,0 +1,8 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export { HelpMenu } from './help_menu';

View file

@ -0,0 +1,81 @@
/*
* 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, { FC, ReactElement } from 'react';
import {
EuiIcon,
IconType,
EuiText,
EuiTitle,
EuiFlexItem,
EuiFlexGroup,
EuiPanel,
EuiLink,
} from '@elastic/eui';
interface Props {
icon: IconType | ReactElement;
iconAreaLabel?: string;
title: any;
description: any;
href?: string;
onClick?: () => void;
isDisabled?: boolean;
'data-test-subj'?: string;
}
// Component for rendering a card which links to the Create Job page, displaying an
// icon, card title, description and link.
export const LinkCard: FC<Props> = ({
icon,
iconAreaLabel,
title,
description,
onClick,
href,
isDisabled,
'data-test-subj': dateTestSubj,
}) => {
const linkHrefAndOnClickProps = {
...(href ? { href } : {}),
...(onClick ? { onClick } : {}),
};
return (
<EuiPanel style={{ cursor: isDisabled ? 'not-allowed' : undefined }}>
<EuiLink
style={{
display: 'block',
pointerEvents: isDisabled ? 'none' : undefined,
background: 'transparent',
outline: 'none',
}}
data-test-subj={dateTestSubj}
color="subdued"
{...linkHrefAndOnClickProps}
>
<EuiFlexGroup gutterSize="l" responsive={true}>
<EuiFlexItem grow={false} style={{ paddingTop: '8px' }}>
{typeof icon === 'string' ? (
<EuiIcon size="xl" type={icon} aria-label={iconAreaLabel} />
) : (
icon
)}
</EuiFlexItem>
<EuiFlexItem>
<EuiTitle size="s">
<h3>{title}</h3>
</EuiTitle>
<EuiText color="subdued">
<p>{description}</p>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiLink>
</EuiPanel>
);
};

View file

@ -10,7 +10,6 @@ import React, { FC, Fragment } from 'react';
import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, EuiSpacer, EuiText } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
export const LoadingIndicator: FC = () => (
<Fragment>
<EuiSpacer size="xxl" />
@ -22,7 +21,10 @@ export const LoadingIndicator: FC = () => (
<EuiFlexGroup justifyContent="spaceAround">
<EuiFlexItem grow={false}>
<EuiText color="subdued">
<FormattedMessage id="xpack.ml.fieldDataCard.loadingLabel" defaultMessage="Loading" />
<FormattedMessage
id="xpack.dataVisualizer.dataGrid.field.loadingLabel"
defaultMessage="Loading"
/>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>

View file

@ -32,7 +32,7 @@ const NoFilterItems = () => {
<EuiSpacer size="xs" />
<p>
<FormattedMessage
id="xpack.fileDataVisualizer.multiSelectPicker.NoFiltersFoundMessage"
id="xpack.dataVisualizer.multiSelectPicker.NoFiltersFoundMessage"
defaultMessage="No filters found"
/>
</p>

View file

@ -5,4 +5,4 @@
* 2.0.
*/
export { FileDataVisualizer } from '../../application';
export { NotInDocsContent } from './not_in_docs_context';

View file

@ -20,7 +20,7 @@ export const NotInDocsContent: FC = () => (
<EuiSpacer size="s" />
<EuiText textAlign="center">
<FormattedMessage
id="xpack.ml.fieldDataCard.fieldNotInDocsLabel"
id="xpack.dataVisualizer.dataGrid.field.fieldNotInDocsLabel"
defaultMessage="This field does not appear in any documents for the selected time range"
/>
</EuiText>

View file

@ -12,11 +12,11 @@ import { EuiFlexGroup, EuiFlexItem, EuiCard, EuiIcon } from '@elastic/eui';
import {
DISCOVER_APP_URL_GENERATOR,
DiscoverUrlGeneratorState,
} from '../../../../../../../src/plugins/discover/public';
import { TimeRange, RefreshInterval } from '../../../../../../../src/plugins/data/public';
import { FindFileStructureResponse } from '../../../../../file_upload/common';
import type { FileUploadPluginStart } from '../../../../../file_upload/public';
import { useFileDataVisualizerKibana } from '../../kibana_context';
} from '../../../../../../../../src/plugins/discover/public';
import { TimeRange, RefreshInterval } from '../../../../../../../../src/plugins/data/public';
import { FindFileStructureResponse } from '../../../../../../file_upload/common';
import type { FileUploadPluginStart } from '../../../../../../file_upload/public';
import { useDataVisualizerKibana } from '../../../kibana_context';
interface Props {
fieldStats: FindFileStructureResponse['field_stats'];
@ -44,7 +44,7 @@ export const ResultsLinks: FC<Props> = ({
}) => {
const {
services: { fileUpload },
} = useFileDataVisualizerKibana();
} = useDataVisualizerKibana();
const [duration, setDuration] = useState({
from: 'now-30m',
@ -63,7 +63,7 @@ export const ResultsLinks: FC<Props> = ({
urlGenerators: { getUrlGenerator },
},
},
} = useFileDataVisualizerKibana();
} = useDataVisualizerKibana();
useEffect(() => {
let unmounted = false;
@ -176,7 +176,7 @@ export const ResultsLinks: FC<Props> = ({
icon={<EuiIcon size="xxl" type={`discoverApp`} />}
title={
<FormattedMessage
id="xpack.fileDataVisualizer.resultsLinks.viewIndexInDiscoverTitle"
id="xpack.dataVisualizer.file.resultsLinks.viewIndexInDiscoverTitle"
defaultMessage="View index in Discover"
/>
}
@ -192,7 +192,7 @@ export const ResultsLinks: FC<Props> = ({
icon={<EuiIcon size="xxl" type={`managementApp`} />}
title={
<FormattedMessage
id="xpack.fileDataVisualizer.resultsLinks.indexManagementTitle"
id="xpack.dataVisualizer.file.resultsLinks.indexManagementTitle"
defaultMessage="Index Management"
/>
}
@ -208,7 +208,7 @@ export const ResultsLinks: FC<Props> = ({
icon={<EuiIcon size="xxl" type={`managementApp`} />}
title={
<FormattedMessage
id="xpack.fileDataVisualizer.resultsLinks.indexPatternManagementTitle"
id="xpack.dataVisualizer.file.resultsLinks.indexPatternManagementTitle"
defaultMessage="Index Pattern Management"
/>
}
@ -223,7 +223,7 @@ export const ResultsLinks: FC<Props> = ({
data-test-subj="fileDataVisFilebeatConfigLink"
title={
<FormattedMessage
id="xpack.fileDataVisualizer.resultsLinks.fileBeatConfig"
id="xpack.dataVisualizer.file.resultsLinks.fileBeatConfig"
defaultMessage="Create Filebeat configuration"
/>
}

View file

@ -31,13 +31,13 @@ export const MetricFieldsCount: FC<MetricFieldsCountProps> = ({ metricsStats })
gutterSize="s"
alignItems="center"
className="dataVisualizerFieldCountContainer"
data-test-subj="mlDataVisualizerMetricFieldsSummary"
data-test-subj="dataVisualizerMetricFieldsSummary"
>
<EuiFlexItem grow={false}>
<EuiText>
<h5>
<FormattedMessage
id="xpack.fileDataVisualizer.searchPanel.numberFieldsLabel"
id="xpack.dataVisualizer.searchPanel.numberFieldsLabel"
defaultMessage="Number fields"
/>
</h5>
@ -47,15 +47,15 @@ export const MetricFieldsCount: FC<MetricFieldsCountProps> = ({ metricsStats })
<EuiNotificationBadge
color="subdued"
size="m"
data-test-subj="mlDataVisualizerVisibleMetricFieldsCount"
data-test-subj="dataVisualizerVisibleMetricFieldsCount"
>
<strong>{metricsStats.visibleMetricsCount}</strong>
</EuiNotificationBadge>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText color="subdued" size="s" data-test-subj="mlDataVisualizerMetricFieldsCount">
<EuiText color="subdued" size="s" data-test-subj="dataVisualizerMetricFieldsCount">
<FormattedMessage
id="xpack.fileDataVisualizer.searchPanel.ofFieldsTotal"
id="xpack.dataVisualizer.searchPanel.ofFieldsTotal"
defaultMessage="of {totalCount} total"
values={{ totalCount: metricsStats.totalMetricFieldsCount }}
/>

View file

@ -31,13 +31,13 @@ export const TotalFieldsCount: FC<TotalFieldsCountProps> = ({ fieldsCountStats }
gutterSize="s"
alignItems="center"
className="dataVisualizerFieldCountContainer"
data-test-subj="mlDataVisualizerFieldsSummary"
data-test-subj="dataVisualizerFieldsSummary"
>
<EuiFlexItem grow={false}>
<EuiText>
<h5>
<FormattedMessage
id="xpack.fileDataVisualizer.searchPanel.allFieldsLabel"
id="xpack.dataVisualizer.searchPanel.allFieldsLabel"
defaultMessage="All fields"
/>
</h5>
@ -48,15 +48,15 @@ export const TotalFieldsCount: FC<TotalFieldsCountProps> = ({ fieldsCountStats }
<EuiNotificationBadge
color="subdued"
size="m"
data-test-subj="mlDataVisualizerVisibleFieldsCount"
data-test-subj="dataVisualizerVisibleFieldsCount"
>
<strong>{fieldsCountStats.visibleFieldsCount}</strong>
</EuiNotificationBadge>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText color="subdued" size="s" data-test-subj="mlDataVisualizerTotalFieldsCount">
<EuiText color="subdued" size="s" data-test-subj="dataVisualizerTotalFieldsCount">
<FormattedMessage
id="xpack.fileDataVisualizer.searchPanel.ofFieldsTotal"
id="xpack.dataVisualizer.searchPanel.ofFieldsTotal"
defaultMessage="of {totalCount} total"
values={{ totalCount: fieldsCountStats.totalFieldsCount }}
/>

Some files were not shown because too many files have changed in this diff Show more