mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[ML] Moving file data vizualizer to its own plugin (#96408)
* [ML] Moving file data vizualizer to file upload plugin * removing maps plug dependency * fixing imports * small refactor * adding missing endpoints * fixing translations * fxing table controls * fixing types and disabling geo point test * actually disabling geo point test * making endpoints internal * moving UI code to separate plugin * enabling maps integration * cleaning up dependencies * fixing translation ids * moving analyze file endpoint out of file upload plugin * fixing transtations issues * refactor for lazy loading of component * updating limits * updating plugin asciidoc * code clean up * further clean up * adding comment * fixing really obvious CI error * removing commented out include * reenabling geo point test * fixing incorrectly changed import * removing ml from labels and identifiers * renaming function * moving analyse file endpoint to file upload plugin * reverting import path changes * adding esUiShared back in * fixing navigation tabs alignment in basic license * adding key to tab wrapper * reverting test label * further removal of ml references * removing ml label from more identifiers * fixing tests Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
f1d167de86
commit
088a618f92
219 changed files with 5249 additions and 969 deletions
|
@ -392,6 +392,10 @@ 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.
|
||||
|
||||
|
|
|
@ -106,6 +106,7 @@ pageLoadAssetSize:
|
|||
indexPatternFieldEditor: 90489
|
||||
osquery: 107090
|
||||
fileUpload: 25664
|
||||
fileDataVisualizer: 27530
|
||||
banners: 17946
|
||||
mapsEms: 26072
|
||||
timelines: 28613
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
"xpack.endpoint": "plugins/endpoint",
|
||||
"xpack.enterpriseSearch": "plugins/enterprise_search",
|
||||
"xpack.features": "plugins/features",
|
||||
"xpack.fileDataVisualizer": "plugins/file_data_visualizer",
|
||||
"xpack.fileUpload": "plugins/file_upload",
|
||||
"xpack.globalSearch": ["plugins/global_search"],
|
||||
"xpack.globalSearchBar": ["plugins/global_search_bar"],
|
||||
|
|
31
x-pack/plugins/file_data_visualizer/common/constants.ts
Normal file
31
x-pack/plugins/file_data_visualizer/common/constants.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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 const UI_SETTING_MAX_FILE_SIZE = 'fileUpload:maxFileSize';
|
||||
|
||||
export const MB = Math.pow(2, 20);
|
||||
export const MAX_FILE_SIZE = '100MB';
|
||||
export const MAX_FILE_SIZE_BYTES = 104857600; // 100MB
|
||||
|
||||
export const ABSOLUTE_MAX_FILE_SIZE_BYTES = 1073741274; // 1GB
|
||||
export const FILE_SIZE_DISPLAY_FORMAT = '0,0.[0] b';
|
||||
|
||||
// Value to use in the Elasticsearch index mapping meta data to identify the
|
||||
// index as having been created by the File Data Visualizer.
|
||||
export const INDEX_META_DATA_CREATED_BY = 'file-data-visualizer';
|
||||
|
||||
export const JOB_FIELD_TYPES = {
|
||||
BOOLEAN: 'boolean',
|
||||
DATE: 'date',
|
||||
GEO_POINT: 'geo_point',
|
||||
GEO_SHAPE: 'geo_shape',
|
||||
IP: 'ip',
|
||||
KEYWORD: 'keyword',
|
||||
NUMBER: 'number',
|
||||
TEXT: 'text',
|
||||
UNKNOWN: 'unknown',
|
||||
} as const;
|
|
@ -5,4 +5,5 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
export { createUrlOverrides, processResults, readFile, DEFAULT_LINES_TO_SAMPLE } from './utils';
|
||||
export * from './constants';
|
||||
export * from './types';
|
22
x-pack/plugins/file_data_visualizer/common/types.ts
Normal file
22
x-pack/plugins/file_data_visualizer/common/types.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { JOB_FIELD_TYPES } from './constants';
|
||||
|
||||
export type InputData = any[];
|
||||
|
||||
export type JobFieldType = typeof JOB_FIELD_TYPES[keyof typeof JOB_FIELD_TYPES];
|
||||
|
||||
export interface DataVisualizerTableState {
|
||||
pageSize: number;
|
||||
pageIndex: number;
|
||||
sortField: string;
|
||||
sortDirection: string;
|
||||
visibleFieldTypes: string[];
|
||||
visibleFieldNames: string[];
|
||||
showDistributions: boolean;
|
||||
}
|
12
x-pack/plugins/file_data_visualizer/jest.config.js
Normal file
12
x-pack/plugins/file_data_visualizer/jest.config.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
preset: '@kbn/test',
|
||||
rootDir: '../../..',
|
||||
roots: ['<rootDir>/x-pack/plugins/file_data_visualizer'],
|
||||
};
|
27
x-pack/plugins/file_data_visualizer/kibana.json
Normal file
27
x-pack/plugins/file_data_visualizer/kibana.json
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"id": "fileDataVisualizer",
|
||||
"version": "8.0.0",
|
||||
"kibanaVersion": "kibana",
|
||||
"server": true,
|
||||
"ui": true,
|
||||
"requiredPlugins": [
|
||||
"data",
|
||||
"usageCollection",
|
||||
"embeddable",
|
||||
"share",
|
||||
"discover",
|
||||
"fileUpload"
|
||||
],
|
||||
"optionalPlugins": [
|
||||
"security",
|
||||
"maps"
|
||||
],
|
||||
"requiredBundles": [
|
||||
"kibanaReact",
|
||||
"maps",
|
||||
"esUiShared"
|
||||
],
|
||||
"extraPublicDirs": [
|
||||
"common"
|
||||
]
|
||||
}
|
14
x-pack/plugins/file_data_visualizer/public/api/index.ts
Normal file
14
x-pack/plugins/file_data_visualizer/public/api/index.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* 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 { lazyLoadModules } from '../lazy_load_bundle';
|
||||
import { FileDataVisualizer } from '../application';
|
||||
|
||||
export async function getFileDataVisualizerComponent(): Promise<typeof FileDataVisualizer> {
|
||||
const modules = await lazyLoadModules();
|
||||
return modules.FileDataVisualizer;
|
||||
}
|
|
@ -43,7 +43,7 @@ export const AboutPanel: FC<Props> = ({ onFilePickerChange }) => {
|
|||
<EuiFilePicker
|
||||
id="filePicker"
|
||||
initialPromptText={i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.aboutPanel.selectOrDragAndDropFileDescription',
|
||||
'xpack.fileDataVisualizer.aboutPanel.selectOrDragAndDropFileDescription',
|
||||
{
|
||||
defaultMessage: 'Select or drag and drop a file',
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ export const LoadingPanel: FC = () => {
|
|||
<EuiTitle size="s">
|
||||
<h1 role="alert">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.aboutPanel.analyzingDataTitle"
|
||||
id="xpack.fileDataVisualizer.aboutPanel.analyzingDataTitle"
|
||||
defaultMessage="Analyzing data"
|
||||
/>
|
||||
</h1>
|
|
@ -21,26 +21,22 @@ import {
|
|||
|
||||
import { ExperimentalBadge } from '../experimental_badge';
|
||||
|
||||
import { useMlKibana } from '../../../../contexts/kibana';
|
||||
import { useFileDataVisualizerKibana } from '../../kibana_context';
|
||||
|
||||
export const WelcomeContent: FC = () => {
|
||||
const toolTipContent = i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.welcomeContent.experimentalFeatureTooltip',
|
||||
'xpack.fileDataVisualizer.welcomeContent.experimentalFeatureTooltip',
|
||||
{
|
||||
defaultMessage: "Experimental feature. We'd love to hear your feedback.",
|
||||
}
|
||||
);
|
||||
|
||||
const {
|
||||
services: { fileUpload },
|
||||
} = useMlKibana();
|
||||
|
||||
if (fileUpload === undefined) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('File upload plugin not available');
|
||||
return null;
|
||||
}
|
||||
const maxFileSize = fileUpload.getMaxBytesFormatted();
|
||||
services: {
|
||||
fileUpload: { getMaxBytesFormatted },
|
||||
},
|
||||
} = useFileDataVisualizerKibana();
|
||||
const maxFileSize = getMaxBytesFormatted();
|
||||
|
||||
return (
|
||||
<EuiFlexGroup gutterSize="xl" alignItems="center">
|
||||
|
@ -51,7 +47,7 @@ export const WelcomeContent: FC = () => {
|
|||
<EuiTitle size="m">
|
||||
<h1>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.welcomeContent.visualizeDataFromLogFileTitle"
|
||||
id="xpack.fileDataVisualizer.welcomeContent.visualizeDataFromLogFileTitle"
|
||||
defaultMessage="Visualize data from a log file {experimentalBadge}"
|
||||
values={{
|
||||
experimentalBadge: <ExperimentalBadge tooltipContent={toolTipContent} />,
|
||||
|
@ -63,7 +59,7 @@ export const WelcomeContent: FC = () => {
|
|||
<EuiText>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.welcomeContent.visualizeDataFromLogFileDescription"
|
||||
id="xpack.fileDataVisualizer.welcomeContent.visualizeDataFromLogFileDescription"
|
||||
defaultMessage="The File Data Visualizer helps you understand the fields and metrics in a log file.
|
||||
Upload your file, analyze its data, and then choose whether to import the data into an Elasticsearch index."
|
||||
/>
|
||||
|
@ -73,7 +69,7 @@ export const WelcomeContent: FC = () => {
|
|||
<EuiText>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.welcomeContent.supportedFileFormatDescription"
|
||||
id="xpack.fileDataVisualizer.welcomeContent.supportedFileFormatDescription"
|
||||
defaultMessage="The File Data Visualizer supports these file formats:"
|
||||
/>
|
||||
</p>
|
||||
|
@ -87,7 +83,7 @@ export const WelcomeContent: FC = () => {
|
|||
<EuiText>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.welcomeContent.delimitedTextFilesDescription"
|
||||
id="xpack.fileDataVisualizer.welcomeContent.delimitedTextFilesDescription"
|
||||
defaultMessage="Delimited text files, such as CSV and TSV"
|
||||
/>
|
||||
</p>
|
||||
|
@ -103,7 +99,7 @@ export const WelcomeContent: FC = () => {
|
|||
<EuiText>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.welcomeContent.newlineDelimitedJsonDescription"
|
||||
id="xpack.fileDataVisualizer.welcomeContent.newlineDelimitedJsonDescription"
|
||||
defaultMessage="Newline-delimited JSON"
|
||||
/>
|
||||
</p>
|
||||
|
@ -119,7 +115,7 @@ export const WelcomeContent: FC = () => {
|
|||
<EuiText>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.welcomeContent.logFilesWithCommonFormatDescription"
|
||||
id="xpack.fileDataVisualizer.welcomeContent.logFilesWithCommonFormatDescription"
|
||||
defaultMessage="Log files with a common format for the timestamp"
|
||||
/>
|
||||
</p>
|
||||
|
@ -130,7 +126,7 @@ export const WelcomeContent: FC = () => {
|
|||
<EuiText>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.welcomeContent.uploadedFilesAllowedSizeDescription"
|
||||
id="xpack.fileDataVisualizer.welcomeContent.uploadedFilesAllowedSizeDescription"
|
||||
defaultMessage="You can upload files up to {maxFileSize}."
|
||||
values={{ maxFileSize }}
|
||||
/>
|
||||
|
@ -140,7 +136,7 @@ export const WelcomeContent: FC = () => {
|
|||
<EuiText>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.welcomeContent.experimentalFeatureDescription"
|
||||
id="xpack.fileDataVisualizer.welcomeContent.experimentalFeatureDescription"
|
||||
defaultMessage="This feature is experimental. Got feedback? Please create an issue in {githubLink}."
|
||||
values={{
|
||||
githubLink: (
|
|
@ -9,7 +9,7 @@ import { FormattedMessage } from '@kbn/i18n/react';
|
|||
import React, { FC } from 'react';
|
||||
|
||||
import { EuiTitle, EuiSpacer, EuiDescriptionList } from '@elastic/eui';
|
||||
import { FindFileStructureResponse } from '../../../../../../../file_upload/common';
|
||||
import { FindFileStructureResponse } from '../../../../../file_upload/common';
|
||||
|
||||
export const AnalysisSummary: FC<{ results: FindFileStructureResponse }> = ({ results }) => {
|
||||
const items = createDisplayItems(results);
|
||||
|
@ -19,7 +19,7 @@ export const AnalysisSummary: FC<{ results: FindFileStructureResponse }> = ({ re
|
|||
<EuiTitle size="s">
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.analysisSummary.summaryTitle"
|
||||
id="xpack.fileDataVisualizer.analysisSummary.summaryTitle"
|
||||
defaultMessage="Summary"
|
||||
/>
|
||||
</h2>
|
||||
|
@ -37,7 +37,7 @@ function createDisplayItems(results: FindFileStructureResponse) {
|
|||
{
|
||||
title: (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.analysisSummary.analyzedLinesNumberTitle"
|
||||
id="xpack.fileDataVisualizer.analysisSummary.analyzedLinesNumberTitle"
|
||||
defaultMessage="Number of lines analyzed"
|
||||
/>
|
||||
),
|
||||
|
@ -53,7 +53,7 @@ function createDisplayItems(results: FindFileStructureResponse) {
|
|||
items.push({
|
||||
title: (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.analysisSummary.formatTitle"
|
||||
id="xpack.fileDataVisualizer.analysisSummary.formatTitle"
|
||||
defaultMessage="Format"
|
||||
/>
|
||||
),
|
||||
|
@ -64,7 +64,7 @@ function createDisplayItems(results: FindFileStructureResponse) {
|
|||
items.push({
|
||||
title: (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.analysisSummary.delimiterTitle"
|
||||
id="xpack.fileDataVisualizer.analysisSummary.delimiterTitle"
|
||||
defaultMessage="Delimiter"
|
||||
/>
|
||||
),
|
||||
|
@ -74,7 +74,7 @@ function createDisplayItems(results: FindFileStructureResponse) {
|
|||
items.push({
|
||||
title: (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.analysisSummary.hasHeaderRowTitle"
|
||||
id="xpack.fileDataVisualizer.analysisSummary.hasHeaderRowTitle"
|
||||
defaultMessage="Has header row"
|
||||
/>
|
||||
),
|
||||
|
@ -87,7 +87,7 @@ function createDisplayItems(results: FindFileStructureResponse) {
|
|||
items.push({
|
||||
title: (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.analysisSummary.grokPatternTitle"
|
||||
id="xpack.fileDataVisualizer.analysisSummary.grokPatternTitle"
|
||||
defaultMessage="Grok pattern"
|
||||
/>
|
||||
),
|
||||
|
@ -99,7 +99,7 @@ function createDisplayItems(results: FindFileStructureResponse) {
|
|||
items.push({
|
||||
title: (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.analysisSummary.timeFieldTitle"
|
||||
id="xpack.fileDataVisualizer.analysisSummary.timeFieldTitle"
|
||||
defaultMessage="Time field"
|
||||
/>
|
||||
),
|
||||
|
@ -111,7 +111,7 @@ function createDisplayItems(results: FindFileStructureResponse) {
|
|||
items.push({
|
||||
title: (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.analysisSummary.timeFormatTitle"
|
||||
id="xpack.fileDataVisualizer.analysisSummary.timeFormatTitle"
|
||||
defaultMessage="Time {timestampFormats, plural, zero {format} one {format} other {formats}}"
|
||||
values={{
|
||||
timestampFormats: results.java_timestamp_formats.length,
|
|
@ -39,7 +39,7 @@ export const BottomBar: FC<BottomBarProps> = ({ mode, onChangeMode, onCancel, di
|
|||
content={
|
||||
disableImport ? (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.bottomBar.missingImportPrivilegesMessage"
|
||||
id="xpack.fileDataVisualizer.bottomBar.missingImportPrivilegesMessage"
|
||||
defaultMessage="You require the ingest_admin role to enable data importing"
|
||||
/>
|
||||
) : null
|
||||
|
@ -52,7 +52,7 @@ export const BottomBar: FC<BottomBarProps> = ({ mode, onChangeMode, onCancel, di
|
|||
data-test-subj="mlFileDataVisOpenImportPageButton"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.bottomBar.readMode.importButtonLabel"
|
||||
id="xpack.fileDataVisualizer.bottomBar.readMode.importButtonLabel"
|
||||
defaultMessage="Import"
|
||||
/>
|
||||
</EuiButton>
|
||||
|
@ -61,7 +61,7 @@ export const BottomBar: FC<BottomBarProps> = ({ mode, onChangeMode, onCancel, di
|
|||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty color="ghost" onClick={() => onCancel()}>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.bottomBar.readMode.cancelButtonLabel"
|
||||
id="xpack.fileDataVisualizer.bottomBar.readMode.cancelButtonLabel"
|
||||
defaultMessage="Cancel"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
|
@ -76,7 +76,7 @@ export const BottomBar: FC<BottomBarProps> = ({ mode, onChangeMode, onCancel, di
|
|||
<EuiFlexItem grow={false}>
|
||||
<EuiButton color="ghost" onClick={() => onChangeMode(DATAVISUALIZER_MODE.READ)}>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.bottomBar.backButtonLabel"
|
||||
id="xpack.fileDataVisualizer.bottomBar.backButtonLabel"
|
||||
defaultMessage="Back"
|
||||
/>
|
||||
</EuiButton>
|
||||
|
@ -84,7 +84,7 @@ export const BottomBar: FC<BottomBarProps> = ({ mode, onChangeMode, onCancel, di
|
|||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty color="ghost" onClick={() => onCancel()}>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.bottomBar.cancelButtonLabel"
|
||||
id="xpack.fileDataVisualizer.bottomBar.cancelButtonLabel"
|
||||
defaultMessage="Cancel"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
|
@ -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.ml.fileDatavisualizer.combinedFieldsForm.mappingsParseError', {
|
||||
i18n.translate('xpack.fileDataVisualizer.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.ml.fileDatavisualizer.combinedFieldsForm.pipelineParseError', {
|
||||
i18n.translate('xpack.fileDataVisualizer.combinedFieldsForm.pipelineParseError', {
|
||||
defaultMessage: 'Error parsing pipeline: {error}',
|
||||
values: { error: error.message },
|
||||
})
|
||||
|
@ -149,7 +149,7 @@ export class CombinedFieldsForm extends Component<Props, State> {
|
|||
};
|
||||
|
||||
render() {
|
||||
const geoPointLabel = i18n.translate('xpack.ml.fileDatavisualizer.geoPointCombinedFieldLabel', {
|
||||
const geoPointLabel = i18n.translate('xpack.fileDataVisualizer.geoPointCombinedFieldLabel', {
|
||||
defaultMessage: 'Add geo point field',
|
||||
});
|
||||
const panels = [
|
||||
|
@ -176,7 +176,7 @@ export class CombinedFieldsForm extends Component<Props, State> {
|
|||
];
|
||||
return (
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.ml.fileDatavisualizer.combinedFieldsLabel', {
|
||||
label={i18n.translate('xpack.fileDataVisualizer.combinedFieldsLabel', {
|
||||
defaultMessage: 'Combined fields',
|
||||
})}
|
||||
>
|
||||
|
@ -192,11 +192,11 @@ export class CombinedFieldsForm extends Component<Props, State> {
|
|||
iconType="trash"
|
||||
color="danger"
|
||||
onClick={this.removeCombinedField.bind(null, idx)}
|
||||
title={i18n.translate('xpack.ml.fileDatavisualizer.removeCombinedFieldsLabel', {
|
||||
title={i18n.translate('xpack.fileDataVisualizer.removeCombinedFieldsLabel', {
|
||||
defaultMessage: 'Remove combined field',
|
||||
})}
|
||||
aria-label={i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.removeCombinedFieldsLabel',
|
||||
'xpack.fileDataVisualizer.removeCombinedFieldsLabel',
|
||||
{
|
||||
defaultMessage: 'Remove combined field',
|
||||
}
|
||||
|
@ -216,7 +216,7 @@ export class CombinedFieldsForm extends Component<Props, State> {
|
|||
isDisabled={this.props.isDisabled}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.addCombinedFieldsLabel"
|
||||
id="xpack.fileDataVisualizer.addCombinedFieldsLabel"
|
||||
defaultMessage="Add combined field"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
|
@ -20,10 +20,10 @@ export function CombinedFieldsReadOnlyForm({
|
|||
}) {
|
||||
return combinedFields.length ? (
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.ml.fileDatavisualizer.combinedFieldsReadOnlyLabel', {
|
||||
label={i18n.translate('xpack.fileDataVisualizer.combinedFieldsReadOnlyLabel', {
|
||||
defaultMessage: 'Combined fields',
|
||||
})}
|
||||
helpText={i18n.translate('xpack.ml.fileDatavisualizer.combinedFieldsReadOnlyHelpTextLabel', {
|
||||
helpText={i18n.translate('xpack.fileDataVisualizer.combinedFieldsReadOnlyHelpTextLabel', {
|
||||
defaultMessage: 'Edit combined fields in advanced tab',
|
||||
})}
|
||||
>
|
|
@ -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.ml.fileDatavisualizer.geoPointForm.latFieldLabel', {
|
||||
label={i18n.translate('xpack.fileDataVisualizer.geoPointForm.latFieldLabel', {
|
||||
defaultMessage: 'Latitude field',
|
||||
})}
|
||||
>
|
||||
|
@ -131,7 +131,7 @@ export class GeoPointForm extends Component<Props, State> {
|
|||
</EuiFormRow>
|
||||
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.ml.fileDatavisualizer.geoPointForm.lonFieldLabel', {
|
||||
label={i18n.translate('xpack.fileDataVisualizer.geoPointForm.lonFieldLabel', {
|
||||
defaultMessage: 'Longitude field',
|
||||
})}
|
||||
>
|
||||
|
@ -143,7 +143,7 @@ export class GeoPointForm extends Component<Props, State> {
|
|||
</EuiFormRow>
|
||||
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.ml.fileDatavisualizer.geoPointForm.geoPointFieldLabel', {
|
||||
label={i18n.translate('xpack.fileDataVisualizer.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.ml.fileDatavisualizer.geoPointForm.geoPointFieldAriaLabel',
|
||||
'xpack.fileDataVisualizer.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.ml.fileDatavisualizer.geoPointForm.submitButtonLabel"
|
||||
id="xpack.fileDataVisualizer.geoPointForm.submitButtonLabel"
|
||||
defaultMessage="Add"
|
||||
/>
|
||||
</EuiButton>
|
|
@ -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.ml.fileDatavisualizer.nameCollisionMsg', {
|
||||
return i18n.translate('xpack.fileDataVisualizer.nameCollisionMsg', {
|
||||
defaultMessage: '"{name}" already exists, please provide a unique name',
|
||||
values: { name },
|
||||
});
|
|
@ -13,7 +13,7 @@ exports[`Overrides render overrides 1`] = `
|
|||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Number of lines to sample"
|
||||
id="xpack.ml.fileDatavisualizer.editFlyout.overrides.linesToSampleFormRowLabel"
|
||||
id="xpack.fileDataVisualizer.editFlyout.overrides.linesToSampleFormRowLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ exports[`Overrides render overrides 1`] = `
|
|||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Data format"
|
||||
id="xpack.ml.fileDatavisualizer.editFlyout.overrides.dataFormatFormRowLabel"
|
||||
id="xpack.fileDataVisualizer.editFlyout.overrides.dataFormatFormRowLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ exports[`Overrides render overrides 1`] = `
|
|||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Timestamp format"
|
||||
id="xpack.ml.fileDatavisualizer.editFlyout.overrides.timestampFormatFormRowLabel"
|
||||
id="xpack.fileDataVisualizer.editFlyout.overrides.timestampFormatFormRowLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
|
@ -335,7 +335,7 @@ exports[`Overrides render overrides 1`] = `
|
|||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Time field"
|
||||
id="xpack.ml.fileDatavisualizer.editFlyout.overrides.timeFieldFormRowLabel"
|
||||
id="xpack.fileDataVisualizer.editFlyout.overrides.timeFieldFormRowLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
|
@ -69,7 +69,7 @@ export class EditFlyout extends Component {
|
|||
<EuiTitle>
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.editFlyout.overrideSettingsTitle"
|
||||
id="xpack.fileDataVisualizer.editFlyout.overrideSettingsTitle"
|
||||
defaultMessage="Override settings"
|
||||
/>
|
||||
</h2>
|
||||
|
@ -96,7 +96,7 @@ export class EditFlyout extends Component {
|
|||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty iconType="cross" onClick={closeEditFlyout} flush="left">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.editFlyout.closeOverrideSettingsButtonLabel"
|
||||
id="xpack.fileDataVisualizer.editFlyout.closeOverrideSettingsButtonLabel"
|
||||
defaultMessage="Close"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
|
@ -108,7 +108,7 @@ export class EditFlyout extends Component {
|
|||
fill
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.editFlyout.applyOverrideSettingsButtonLabel"
|
||||
id="xpack.fileDataVisualizer.editFlyout.applyOverrideSettingsButtonLabel"
|
||||
defaultMessage="Apply"
|
||||
/>
|
||||
</EuiButton>
|
|
@ -31,7 +31,7 @@ import {
|
|||
// getCharsetOptions,
|
||||
} from './options';
|
||||
import { isTimestampFormatValid } from './overrides_validation';
|
||||
import { withKibana } from '../../../../../../../../../src/plugins/kibana_react/public';
|
||||
import { withKibana } from '../../../../../../../src/plugins/kibana_react/public';
|
||||
|
||||
import { TIMESTAMP_OPTIONS, CUSTOM_DROPDOWN_OPTION } from './options/option_lists';
|
||||
|
||||
|
@ -52,7 +52,7 @@ class OverridesUI extends Component {
|
|||
}
|
||||
|
||||
linesToSampleErrors = i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.editFlyout.overrides.linesToSampleErrorMessage',
|
||||
'xpack.fileDataVisualizer.editFlyout.overrides.linesToSampleErrorMessage',
|
||||
{
|
||||
defaultMessage: 'Value must be greater than {min} and less than or equal to {max}',
|
||||
values: {
|
||||
|
@ -63,7 +63,7 @@ class OverridesUI extends Component {
|
|||
);
|
||||
|
||||
customTimestampFormatErrors = i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.editFlyout.overrides.customTimestampFormatErrorMessage',
|
||||
'xpack.fileDataVisualizer.editFlyout.overrides.customTimestampFormatErrorMessage',
|
||||
{
|
||||
defaultMessage: `Timestamp format must be a combination of these Java date/time formats:
|
||||
yy, yyyy, M, MM, MMM, MMMM, d, dd, EEE, EEEE, H, HH, h, mm, ss, S through SSSSSSSSS, a, XX, XXX, zzz`,
|
||||
|
@ -274,12 +274,9 @@ class OverridesUI extends Component {
|
|||
const timestampFormatHelp = (
|
||||
<EuiText size="xs">
|
||||
<EuiLink href={docsUrl} target="_blank">
|
||||
{i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.editFlyout.overrides.timestampFormatHelpText',
|
||||
{
|
||||
defaultMessage: 'See more on accepted formats',
|
||||
}
|
||||
)}
|
||||
{i18n.translate('xpack.fileDataVisualizer.editFlyout.overrides.timestampFormatHelpText', {
|
||||
defaultMessage: 'See more on accepted formats',
|
||||
})}
|
||||
</EuiLink>
|
||||
</EuiText>
|
||||
);
|
||||
|
@ -291,7 +288,7 @@ class OverridesUI extends Component {
|
|||
isInvalid={linesToSampleValid === false}
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.editFlyout.overrides.linesToSampleFormRowLabel"
|
||||
id="xpack.fileDataVisualizer.editFlyout.overrides.linesToSampleFormRowLabel"
|
||||
defaultMessage="Number of lines to sample"
|
||||
/>
|
||||
}
|
||||
|
@ -306,7 +303,7 @@ class OverridesUI extends Component {
|
|||
<EuiFormRow
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.editFlyout.overrides.dataFormatFormRowLabel"
|
||||
id="xpack.fileDataVisualizer.editFlyout.overrides.dataFormatFormRowLabel"
|
||||
defaultMessage="Data format"
|
||||
/>
|
||||
}
|
||||
|
@ -324,7 +321,7 @@ class OverridesUI extends Component {
|
|||
<EuiFormRow
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.editFlyout.overrides.delimiterFormRowLabel"
|
||||
id="xpack.fileDataVisualizer.editFlyout.overrides.delimiterFormRowLabel"
|
||||
defaultMessage="Delimiter"
|
||||
/>
|
||||
}
|
||||
|
@ -341,7 +338,7 @@ class OverridesUI extends Component {
|
|||
<EuiFormRow
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.editFlyout.overrides.customDelimiterFormRowLabel"
|
||||
id="xpack.fileDataVisualizer.editFlyout.overrides.customDelimiterFormRowLabel"
|
||||
defaultMessage="Custom delimiter"
|
||||
/>
|
||||
}
|
||||
|
@ -353,7 +350,7 @@ class OverridesUI extends Component {
|
|||
<EuiFormRow
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.editFlyout.overrides.quoteCharacterFormRowLabel"
|
||||
id="xpack.fileDataVisualizer.editFlyout.overrides.quoteCharacterFormRowLabel"
|
||||
defaultMessage="Quote character"
|
||||
/>
|
||||
}
|
||||
|
@ -372,7 +369,7 @@ class OverridesUI extends Component {
|
|||
id={'hasHeaderRow'}
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.editFlyout.overrides.hasHeaderRowLabel"
|
||||
id="xpack.fileDataVisualizer.editFlyout.overrides.hasHeaderRowLabel"
|
||||
defaultMessage="Has header row"
|
||||
/>
|
||||
}
|
||||
|
@ -386,7 +383,7 @@ class OverridesUI extends Component {
|
|||
id={'shouldTrimFields'}
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.editFlyout.overrides.trimFieldsLabel"
|
||||
id="xpack.fileDataVisualizer.editFlyout.overrides.trimFieldsLabel"
|
||||
defaultMessage="Should trim fields"
|
||||
/>
|
||||
}
|
||||
|
@ -401,7 +398,7 @@ class OverridesUI extends Component {
|
|||
<EuiFormRow
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.editFlyout.overrides.grokPatternFormRowLabel"
|
||||
id="xpack.fileDataVisualizer.editFlyout.overrides.grokPatternFormRowLabel"
|
||||
defaultMessage="Grok pattern"
|
||||
/>
|
||||
}
|
||||
|
@ -418,7 +415,7 @@ class OverridesUI extends Component {
|
|||
helpText={timestampFormatHelp}
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.editFlyout.overrides.timestampFormatFormRowLabel"
|
||||
id="xpack.fileDataVisualizer.editFlyout.overrides.timestampFormatFormRowLabel"
|
||||
defaultMessage="Timestamp format"
|
||||
/>
|
||||
}
|
||||
|
@ -437,7 +434,7 @@ class OverridesUI extends Component {
|
|||
isInvalid={timestampFormatValid === false}
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.editFlyout.overrides.customTimestampFormatFormRowLabel"
|
||||
id="xpack.fileDataVisualizer.editFlyout.overrides.customTimestampFormatFormRowLabel"
|
||||
defaultMessage="Custom timestamp format"
|
||||
/>
|
||||
}
|
||||
|
@ -453,7 +450,7 @@ class OverridesUI extends Component {
|
|||
<EuiFormRow
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.editFlyout.overrides.timeFieldFormRowLabel"
|
||||
id="xpack.fileDataVisualizer.editFlyout.overrides.timeFieldFormRowLabel"
|
||||
defaultMessage="Time field"
|
||||
/>
|
||||
}
|
||||
|
@ -483,7 +480,7 @@ class OverridesUI extends Component {
|
|||
<EuiTitle size="s">
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.editFlyout.overrides.editFieldNamesTitle"
|
||||
id="xpack.fileDataVisualizer.editFlyout.overrides.editFieldNamesTitle"
|
||||
defaultMessage="Edit field names"
|
||||
/>
|
||||
</h3>
|
|
@ -10,7 +10,7 @@ import React from 'react';
|
|||
|
||||
import { Overrides } from './overrides';
|
||||
|
||||
jest.mock('../../../../../../../../../src/plugins/kibana_react/public', () => ({
|
||||
jest.mock('../../../../../../../src/plugins/kibana_react/public', () => ({
|
||||
withKibana: (comp) => {
|
||||
return comp;
|
||||
},
|
|
@ -41,7 +41,7 @@ export function isTimestampFormatValid(timestampFormat) {
|
|||
if (timestampFormat.indexOf('?') >= 0) {
|
||||
result.isValid = false;
|
||||
result.errorMessage = i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.editFlyout.overrides.timestampQuestionMarkValidationErrorMessage',
|
||||
'xpack.fileDataVisualizer.editFlyout.overrides.timestampQuestionMarkValidationErrorMessage',
|
||||
{
|
||||
defaultMessage:
|
||||
'Timestamp format {timestampFormat} not supported because it contains a question mark character ({fieldPlaceholder})',
|
||||
|
@ -86,7 +86,7 @@ export function isTimestampFormatValid(timestampFormat) {
|
|||
result.isValid = false;
|
||||
|
||||
result.errorMessage = i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.editFlyout.overrides.timestampLetterValidationErrorMessage',
|
||||
'xpack.fileDataVisualizer.editFlyout.overrides.timestampLetterValidationErrorMessage',
|
||||
{
|
||||
defaultMessage:
|
||||
'Letter { length, plural, one { {lg} } other { group {lg} } } in {format} is not supported',
|
||||
|
@ -101,9 +101,10 @@ export function isTimestampFormatValid(timestampFormat) {
|
|||
if (curChar === 'S') {
|
||||
// disable exceeds maximum line length error so i18n check passes
|
||||
result.errorMessage = i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.editFlyout.overrides.timestampLetterSValidationErrorMessage',
|
||||
'xpack.fileDataVisualizer.editFlyout.overrides.timestampLetterSValidationErrorMessage',
|
||||
{
|
||||
defaultMessage: 'Letter { length, plural, one { {lg} } other { group {lg} } } in {format} is not supported because it is not preceded by ss and a separator from {sep}', // eslint-disable-line
|
||||
defaultMessage:
|
||||
'Letter { length, plural, one { {lg} } other { group {lg} } } in {format} is not supported because it is not preceded by ss and a separator from {sep}', // eslint-disable-line
|
||||
values: {
|
||||
length,
|
||||
lg: letterGroup,
|
||||
|
@ -127,7 +128,7 @@ export function isTimestampFormatValid(timestampFormat) {
|
|||
if (prevLetterGroup == null) {
|
||||
result.isValid = false;
|
||||
result.errorMessage = i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.editFlyout.overrides.timestampEmptyValidationErrorMessage',
|
||||
'xpack.fileDataVisualizer.editFlyout.overrides.timestampEmptyValidationErrorMessage',
|
||||
{
|
||||
defaultMessage: 'No time format letter groups in timestamp format {timestampFormat}',
|
||||
values: {
|
|
@ -0,0 +1,8 @@
|
|||
.embeddedMapContent {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex: 1 1 100%;
|
||||
z-index: 1;
|
||||
min-height: 0; // Absolute must for Firefox to scroll contents
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
@import 'embedded_map';
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* 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, { 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 {
|
||||
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';
|
||||
import {
|
||||
EmbeddableFactory,
|
||||
ErrorEmbeddable,
|
||||
isErrorEmbeddable,
|
||||
ViewMode,
|
||||
} from '../../../../../../../src/plugins/embeddable/public';
|
||||
import { useFileDataVisualizerKibana } from '../../kibana_context';
|
||||
|
||||
export function EmbeddedMapComponent({
|
||||
layerList,
|
||||
mapEmbeddableInput,
|
||||
renderTooltipContent,
|
||||
}: {
|
||||
layerList: LayerDescriptor[];
|
||||
mapEmbeddableInput?: MapEmbeddableInput;
|
||||
renderTooltipContent?: (params: RenderTooltipContentParams) => JSX.Element;
|
||||
}) {
|
||||
const [embeddable, setEmbeddable] = useState<ErrorEmbeddable | MapEmbeddable | undefined>();
|
||||
|
||||
const embeddableRoot: React.RefObject<HTMLDivElement> = useRef<HTMLDivElement>(null);
|
||||
const baseLayers = useRef<LayerDescriptor[]>();
|
||||
|
||||
const {
|
||||
services: { embeddable: embeddablePlugin, maps: mapsPlugin },
|
||||
} = useFileDataVisualizerKibana();
|
||||
|
||||
const factory:
|
||||
| EmbeddableFactory<MapEmbeddableInput, MapEmbeddableOutput, MapEmbeddable>
|
||||
| undefined = embeddablePlugin
|
||||
? embeddablePlugin.getEmbeddableFactory(MAP_SAVED_OBJECT_TYPE)
|
||||
: undefined;
|
||||
|
||||
// Update the layer list with updated geo points upon refresh
|
||||
useEffect(() => {
|
||||
async function updateIndexPatternSearchLayer() {
|
||||
if (
|
||||
embeddable &&
|
||||
!isErrorEmbeddable(embeddable) &&
|
||||
Array.isArray(layerList) &&
|
||||
Array.isArray(baseLayers.current)
|
||||
) {
|
||||
embeddable.setLayerList([...baseLayers.current, ...layerList]);
|
||||
}
|
||||
}
|
||||
updateIndexPatternSearchLayer();
|
||||
}, [embeddable, layerList]);
|
||||
|
||||
useEffect(() => {
|
||||
async function setupEmbeddable() {
|
||||
if (!factory) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('Map embeddable not found.');
|
||||
return;
|
||||
}
|
||||
const input: MapEmbeddableInput = {
|
||||
id: htmlIdGenerator()(),
|
||||
attributes: { title: '' },
|
||||
filters: [],
|
||||
hidePanelTitles: true,
|
||||
refreshConfig: {
|
||||
value: 0,
|
||||
pause: false,
|
||||
},
|
||||
viewMode: ViewMode.VIEW,
|
||||
isLayerTOCOpen: false,
|
||||
hideFilterActions: true,
|
||||
// can use mapSettings to center map on anomalies
|
||||
mapSettings: {
|
||||
disableInteractive: false,
|
||||
hideToolbarOverlay: false,
|
||||
hideLayerControl: false,
|
||||
hideViewControl: false,
|
||||
initialLocation: INITIAL_LOCATION.AUTO_FIT_TO_BOUNDS, // this will startup based on data-extent
|
||||
autoFitToDataBounds: true, // this will auto-fit when there are changes to the filter and/or query
|
||||
},
|
||||
};
|
||||
|
||||
const embeddableObject = await factory.create(input);
|
||||
|
||||
if (embeddableObject && !isErrorEmbeddable(embeddableObject)) {
|
||||
const basemapLayerDescriptor = mapsPlugin
|
||||
? await mapsPlugin.createLayerDescriptors.createBasemapLayerDescriptor()
|
||||
: null;
|
||||
|
||||
if (basemapLayerDescriptor) {
|
||||
baseLayers.current = [basemapLayerDescriptor];
|
||||
await embeddableObject.setLayerList(baseLayers.current);
|
||||
}
|
||||
}
|
||||
|
||||
setEmbeddable(embeddableObject);
|
||||
}
|
||||
|
||||
setupEmbeddable();
|
||||
// we want this effect to execute exactly once after the component mounts
|
||||
// eslint-disable-next-line
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (embeddable && !isErrorEmbeddable(embeddable) && mapEmbeddableInput !== undefined) {
|
||||
embeddable.updateInput(mapEmbeddableInput);
|
||||
}
|
||||
}, [embeddable, mapEmbeddableInput]);
|
||||
|
||||
useEffect(() => {
|
||||
if (embeddable && !isErrorEmbeddable(embeddable) && renderTooltipContent !== undefined) {
|
||||
embeddable.setRenderTooltipContent(renderTooltipContent);
|
||||
}
|
||||
}, [embeddable, renderTooltipContent]);
|
||||
|
||||
// We can only render after embeddable has already initialized
|
||||
useEffect(() => {
|
||||
if (embeddableRoot.current && embeddable) {
|
||||
embeddable.render(embeddableRoot.current);
|
||||
}
|
||||
}, [embeddable, embeddableRoot]);
|
||||
|
||||
if (!embeddablePlugin) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('Embeddable start plugin not found');
|
||||
return null;
|
||||
}
|
||||
if (!mapsPlugin) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('Maps start plugin not found');
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
data-test-subj="mlEmbeddedMapContent"
|
||||
className="embeddedMapContent"
|
||||
ref={embeddableRoot}
|
||||
/>
|
||||
);
|
||||
}
|
|
@ -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 { EmbeddedMapComponent } from './embedded_map';
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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 } from 'react';
|
||||
|
||||
import { EuiListGroup, EuiListGroupItem } from '@elastic/eui';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { ExpandedRowFieldHeader } from '../stats_table/components/expanded_row_field_header';
|
||||
interface Props {
|
||||
examples: Array<string | object>;
|
||||
}
|
||||
|
||||
export const ExamplesList: FC<Props> = ({ examples }) => {
|
||||
if (examples === undefined || examples === null || !Array.isArray(examples)) {
|
||||
return null;
|
||||
}
|
||||
let examplesContent;
|
||||
if (examples.length === 0) {
|
||||
examplesContent = (
|
||||
<FormattedMessage
|
||||
id="xpack.fileDataVisualizer.fieldDataCard.examplesList.noExamplesMessage"
|
||||
defaultMessage="No examples were obtained for this field"
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
examplesContent = examples.map((example, i) => {
|
||||
return (
|
||||
<EuiListGroupItem
|
||||
className="fieldDataCard__codeContent"
|
||||
size="s"
|
||||
key={`example_${i}`}
|
||||
label={typeof example === 'string' ? example : JSON.stringify(example)}
|
||||
/>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div data-test-subj="mlFieldDataExamplesList">
|
||||
<ExpandedRowFieldHeader>
|
||||
<FormattedMessage
|
||||
id="xpack.fileDataVisualizer.fieldDataCard.examplesList.title"
|
||||
defaultMessage="{numExamples, plural, one {Value} other {Examples}}"
|
||||
values={{
|
||||
numExamples: examples.length,
|
||||
}}
|
||||
/>
|
||||
</ExpandedRowFieldHeader>
|
||||
<EuiListGroup showToolTips={true} maxWidth={'s'} gutterSize={'none'} flush={true}>
|
||||
{examplesContent}
|
||||
</EuiListGroup>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -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 { ExamplesList } from './examples_list';
|
|
@ -14,10 +14,10 @@ import {
|
|||
OtherContent,
|
||||
TextContent,
|
||||
NumberContent,
|
||||
} from '../../../stats_table/components/field_data_expanded_row';
|
||||
} from '../stats_table/components/field_data_expanded_row';
|
||||
import { GeoPointContent } from './geo_point_content/geo_point_content';
|
||||
import { ML_JOB_FIELD_TYPES } from '../../../../../../common/constants/field_types';
|
||||
import type { FileBasedFieldVisConfig } from '../../../stats_table/types/field_vis_config';
|
||||
import { JOB_FIELD_TYPES } from '../../../../common';
|
||||
import type { FileBasedFieldVisConfig } from '../stats_table/types/field_vis_config';
|
||||
|
||||
export const FileBasedDataVisualizerExpandedRow = ({ item }: { item: FileBasedFieldVisConfig }) => {
|
||||
const config = item;
|
||||
|
@ -25,25 +25,25 @@ export const FileBasedDataVisualizerExpandedRow = ({ item }: { item: FileBasedFi
|
|||
|
||||
function getCardContent() {
|
||||
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 JOB_FIELD_TYPES.GEO_POINT:
|
||||
return <GeoPointContent config={config} />;
|
||||
|
||||
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:
|
||||
|
@ -53,7 +53,7 @@ export const FileBasedDataVisualizerExpandedRow = ({ item }: { item: FileBasedFi
|
|||
|
||||
return (
|
||||
<div
|
||||
className="mlDataVisualizerFieldExpandedRow"
|
||||
className="dataVisualizerFieldExpandedRow"
|
||||
data-test-subj={`mlDataVisualizerFieldExpandedRow-${fieldName}`}
|
||||
>
|
||||
{getCardContent()}
|
|
@ -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
|
|
@ -9,12 +9,12 @@ import React, { FC, useMemo } from 'react';
|
|||
|
||||
import { EuiFlexItem } from '@elastic/eui';
|
||||
import { Feature, Point } from 'geojson';
|
||||
import type { FieldDataRowProps } from '../../../../stats_table/types/field_data_row';
|
||||
import { DocumentStatsTable } from '../../../../stats_table/components/field_data_expanded_row/document_stats';
|
||||
import { MlEmbeddedMapComponent } from '../../../../../components/ml_embedded_map';
|
||||
import type { FieldDataRowProps } from '../../stats_table/types/field_data_row';
|
||||
import { DocumentStatsTable } from '../../stats_table/components/field_data_expanded_row/document_stats';
|
||||
import { EmbeddedMapComponent } from '../../embedded_map';
|
||||
import { convertWKTGeoToLonLat, getGeoPointsLayer } from './format_utils';
|
||||
import { ExpandedRowContent } from '../../../../stats_table/components/field_data_expanded_row/expanded_row_content';
|
||||
import { ExamplesList } from '../../../../index_based/components/field_data_row/examples_list';
|
||||
import { ExpandedRowContent } from '../../stats_table/components/field_data_expanded_row/expanded_row_content';
|
||||
import { ExamplesList } from '../../examples_list';
|
||||
|
||||
export const DEFAULT_GEO_REGEX = RegExp('(?<lat>.+) (?<lon>.+)');
|
||||
|
||||
|
@ -38,7 +38,7 @@ export const GeoPointContent: FC<FieldDataRowProps> = ({ config }) => {
|
|||
|
||||
geoPointsFeatures.push({
|
||||
type: 'Feature',
|
||||
id: `ml-${config.fieldName}-${i}`,
|
||||
id: `fileDataVisualizer-${config.fieldName}-${i}`,
|
||||
geometry: {
|
||||
type: 'Point',
|
||||
coordinates: [coordinates.lat, coordinates.lon],
|
||||
|
@ -69,10 +69,10 @@ export const GeoPointContent: FC<FieldDataRowProps> = ({ config }) => {
|
|||
)}
|
||||
{formattedResults && Array.isArray(formattedResults.layerList) && (
|
||||
<EuiFlexItem
|
||||
className={'mlDataVisualizerMapWrapper'}
|
||||
className={'dataVisualizerMapWrapper'}
|
||||
data-test-subj={'mlDataVisualizerEmbeddedMap'}
|
||||
>
|
||||
<MlEmbeddedMapComponent layerList={formattedResults.layerList} />
|
||||
<EmbeddedMapComponent layerList={formattedResults.layerList} />
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</ExpandedRowContent>
|
|
@ -1,4 +1,4 @@
|
|||
.ml-experimental-badge.euiBetaBadge {
|
||||
.experimental-badge.euiBetaBadge {
|
||||
font-size: 10px;
|
||||
vertical-align: middle;
|
||||
margin-bottom: 5px;
|
|
@ -14,10 +14,10 @@ export const ExperimentalBadge: FC<{ tooltipContent: string }> = ({ tooltipConte
|
|||
return (
|
||||
<span>
|
||||
<EuiBetaBadge
|
||||
className="ml-experimental-badge"
|
||||
className="experimental-badge"
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.experimentalBadge.experimentalLabel"
|
||||
id="xpack.fileDataVisualizer.experimentalBadge.experimentalLabel"
|
||||
defaultMessage="Experimental"
|
||||
/>
|
||||
}
|
|
@ -20,7 +20,7 @@ import {
|
|||
EuiText,
|
||||
EuiSubSteps,
|
||||
} from '@elastic/eui';
|
||||
import { FindFileStructureResponse } from '../../../../../../../file_upload/common';
|
||||
import { FindFileStructureResponse } from '../../../../../file_upload/common';
|
||||
|
||||
interface Props {
|
||||
results: FindFileStructureResponse;
|
||||
|
@ -34,7 +34,7 @@ export const ExplanationFlyout: FC<Props> = ({ results, closeFlyout }) => {
|
|||
<EuiTitle size="m">
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.explanationFlyout.title"
|
||||
id="xpack.fileDataVisualizer.explanationFlyout.title"
|
||||
defaultMessage="Analysis explanation"
|
||||
/>
|
||||
</h2>
|
||||
|
@ -48,7 +48,7 @@ export const ExplanationFlyout: FC<Props> = ({ results, closeFlyout }) => {
|
|||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty iconType="cross" onClick={closeFlyout} flush="left">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.explanationFlyout.closeButton"
|
||||
id="xpack.fileDataVisualizer.explanationFlyout.closeButton"
|
||||
defaultMessage="Close"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
|
@ -63,7 +63,7 @@ const Content: FC<{ explanation: string[] }> = ({ explanation }) => (
|
|||
<>
|
||||
<EuiText size={'s'}>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.explanationFlyout.content"
|
||||
id="xpack.fileDataVisualizer.explanationFlyout.content"
|
||||
defaultMessage="The logical steps that have produced the analysis results."
|
||||
/>
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
import React from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import { FileBasedFieldVisConfig } from '../../../stats_table/types';
|
||||
import { FileBasedFieldVisConfig } from '../stats_table/types';
|
||||
|
||||
export const FileBasedNumberContentPreview = ({ config }: { config: FileBasedFieldVisConfig }) => {
|
||||
const stats = config.stats;
|
||||
|
@ -25,7 +25,7 @@ export const FileBasedNumberContentPreview = ({ config }: { config: FileBasedFie
|
|||
<EuiFlexItem>
|
||||
<b>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fieldStatsCard.minTitle"
|
||||
id="xpack.fileDataVisualizer.fieldStatsCard.minTitle"
|
||||
defaultMessage="min"
|
||||
/>
|
||||
</b>
|
||||
|
@ -33,7 +33,7 @@ export const FileBasedNumberContentPreview = ({ config }: { config: FileBasedFie
|
|||
<EuiFlexItem>
|
||||
<b>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fieldStatsCard.medianTitle"
|
||||
id="xpack.fileDataVisualizer.fieldStatsCard.medianTitle"
|
||||
defaultMessage="median"
|
||||
/>
|
||||
</b>
|
||||
|
@ -41,7 +41,7 @@ export const FileBasedNumberContentPreview = ({ config }: { config: FileBasedFie
|
|||
<EuiFlexItem>
|
||||
<b>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fieldStatsCard.maxTitle"
|
||||
id="xpack.fileDataVisualizer.fieldStatsCard.maxTitle"
|
||||
defaultMessage="max"
|
||||
/>
|
||||
</b>
|
|
@ -7,11 +7,11 @@
|
|||
|
||||
import React, { FC, useMemo } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { MultiSelectPicker } from '../../../../components/multi_select_picker';
|
||||
import { MultiSelectPicker } from '../multi_select_picker';
|
||||
import type {
|
||||
FileBasedFieldVisConfig,
|
||||
FileBasedUnknownFieldVisConfig,
|
||||
} from '../../../stats_table/types/field_vis_config';
|
||||
} from '../stats_table/types/field_vis_config';
|
||||
|
||||
interface Props {
|
||||
fields: Array<FileBasedFieldVisConfig | FileBasedUnknownFieldVisConfig>;
|
||||
|
@ -26,7 +26,7 @@ export const DataVisualizerFieldNamesFilter: FC<Props> = ({
|
|||
}) => {
|
||||
const fieldNameTitle = useMemo(
|
||||
() =>
|
||||
i18n.translate('xpack.ml.dataVisualizer.fileBased.fieldNameSelect', {
|
||||
i18n.translate('xpack.fileDataVisualizer.fieldNameSelect', {
|
||||
defaultMessage: 'Field name',
|
||||
}),
|
||||
[]
|
|
@ -0,0 +1,16 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`FieldTypeIcon render component when type matches a field type 1`] = `
|
||||
<EuiToolTip
|
||||
content="keyword type"
|
||||
delay="regular"
|
||||
position="left"
|
||||
>
|
||||
<FieldTypeIconContainer
|
||||
ariaLabel="keyword type"
|
||||
color="euiColorVis0"
|
||||
iconType="tokenText"
|
||||
needsAria={false}
|
||||
/>
|
||||
</EuiToolTip>
|
||||
`;
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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 from 'react';
|
||||
import { mount, shallow } from 'enzyme';
|
||||
|
||||
import { FieldTypeIcon } from './field_type_icon';
|
||||
import { JOB_FIELD_TYPES } from '../../../../common';
|
||||
|
||||
describe('FieldTypeIcon', () => {
|
||||
test(`render component when type matches a field type`, () => {
|
||||
const typeIconComponent = shallow(
|
||||
<FieldTypeIcon type={JOB_FIELD_TYPES.KEYWORD} tooltipEnabled={true} needsAria={false} />
|
||||
);
|
||||
expect(typeIconComponent).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test(`render with tooltip and test hovering`, () => {
|
||||
// Use fake timers so we don't have to wait for the EuiToolTip timeout
|
||||
jest.useFakeTimers();
|
||||
|
||||
const typeIconComponent = mount(
|
||||
<FieldTypeIcon type={JOB_FIELD_TYPES.KEYWORD} tooltipEnabled={true} needsAria={false} />
|
||||
);
|
||||
const container = typeIconComponent.find({ 'data-test-subj': 'fieldTypeIcon' });
|
||||
|
||||
expect(typeIconComponent.find('EuiToolTip').children()).toHaveLength(1);
|
||||
|
||||
container.simulate('mouseover');
|
||||
|
||||
// Run the timers so the EuiTooltip will be visible
|
||||
jest.runAllTimers();
|
||||
|
||||
typeIconComponent.update();
|
||||
expect(typeIconComponent.find('EuiToolTip').children()).toHaveLength(2);
|
||||
|
||||
container.simulate('mouseout');
|
||||
|
||||
// Run the timers so the EuiTooltip will be hidden again
|
||||
jest.runAllTimers();
|
||||
|
||||
typeIconComponent.update();
|
||||
expect(typeIconComponent.find('EuiToolTip').children()).toHaveLength(1);
|
||||
|
||||
// Clearing all mocks will also reset fake timers.
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* 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 } from 'react';
|
||||
|
||||
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';
|
||||
|
||||
interface FieldTypeIconProps {
|
||||
tooltipEnabled: boolean;
|
||||
type: JobFieldType;
|
||||
fieldName?: string;
|
||||
needsAria: boolean;
|
||||
}
|
||||
|
||||
interface FieldTypeIconContainerProps {
|
||||
ariaLabel: string | null;
|
||||
iconType: string;
|
||||
color: string;
|
||||
needsAria: boolean;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export const FieldTypeIcon: FC<FieldTypeIconProps> = ({
|
||||
tooltipEnabled = false,
|
||||
type,
|
||||
fieldName,
|
||||
needsAria = true,
|
||||
}) => {
|
||||
const ariaLabel = getJobTypeAriaLabel(type);
|
||||
|
||||
let iconType = 'questionInCircle';
|
||||
let color = 'euiColorVis6';
|
||||
|
||||
switch (type) {
|
||||
// Set icon types and colors
|
||||
case JOB_FIELD_TYPES.BOOLEAN:
|
||||
iconType = 'tokenBoolean';
|
||||
color = 'euiColorVis5';
|
||||
break;
|
||||
case JOB_FIELD_TYPES.DATE:
|
||||
iconType = 'tokenDate';
|
||||
color = 'euiColorVis7';
|
||||
break;
|
||||
case JOB_FIELD_TYPES.GEO_POINT:
|
||||
case JOB_FIELD_TYPES.GEO_SHAPE:
|
||||
iconType = 'tokenGeo';
|
||||
color = 'euiColorVis8';
|
||||
break;
|
||||
case JOB_FIELD_TYPES.TEXT:
|
||||
iconType = 'document';
|
||||
color = 'euiColorVis9';
|
||||
break;
|
||||
case JOB_FIELD_TYPES.IP:
|
||||
iconType = 'tokenIP';
|
||||
color = 'euiColorVis3';
|
||||
break;
|
||||
case JOB_FIELD_TYPES.KEYWORD:
|
||||
iconType = 'tokenText';
|
||||
color = 'euiColorVis0';
|
||||
break;
|
||||
case JOB_FIELD_TYPES.NUMBER:
|
||||
iconType = 'tokenNumber';
|
||||
color = fieldName !== undefined ? 'euiColorVis1' : 'euiColorVis2';
|
||||
break;
|
||||
case JOB_FIELD_TYPES.UNKNOWN:
|
||||
// Use defaults
|
||||
break;
|
||||
}
|
||||
|
||||
const containerProps = {
|
||||
ariaLabel,
|
||||
iconType,
|
||||
color,
|
||||
needsAria,
|
||||
};
|
||||
|
||||
if (tooltipEnabled === true) {
|
||||
// wrap the inner component inside <span> because EuiToolTip doesn't seem
|
||||
// to support having another component directly inside the tooltip anchor
|
||||
// see https://github.com/elastic/eui/issues/839
|
||||
return (
|
||||
<EuiToolTip
|
||||
position="left"
|
||||
content={i18n.translate('xpack.fileDataVisualizer.fieldTypeIcon.fieldTypeTooltip', {
|
||||
defaultMessage: '{type} type',
|
||||
values: { type },
|
||||
})}
|
||||
>
|
||||
<FieldTypeIconContainer {...containerProps} />
|
||||
</EuiToolTip>
|
||||
);
|
||||
}
|
||||
|
||||
return <FieldTypeIconContainer {...containerProps} />;
|
||||
};
|
||||
|
||||
// If the tooltip is used, it will apply its events to its first inner child.
|
||||
// To pass on its properties we apply `rest` to the outer `span` element.
|
||||
const FieldTypeIconContainer: FC<FieldTypeIconContainerProps> = ({
|
||||
ariaLabel,
|
||||
iconType,
|
||||
color,
|
||||
needsAria,
|
||||
...rest
|
||||
}) => {
|
||||
const wrapperProps: { className: string; 'aria-label'?: string } = {
|
||||
className: 'field-type-icon',
|
||||
};
|
||||
if (needsAria && ariaLabel) {
|
||||
wrapperProps['aria-label'] = ariaLabel;
|
||||
}
|
||||
|
||||
return (
|
||||
<span data-test-subj="fieldTypeIcon" {...rest}>
|
||||
<span {...wrapperProps}>
|
||||
<EuiToken iconType={iconType} shape="square" size="s" color={color} />
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
};
|
|
@ -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 { FieldTypeIcon } from './field_type_icon';
|
|
@ -8,13 +8,25 @@
|
|||
import React, { FC, useMemo } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import { MultiSelectPicker, Option } from '../../../../components/multi_select_picker';
|
||||
import { MultiSelectPicker, Option } from '../multi_select_picker';
|
||||
import type {
|
||||
FileBasedFieldVisConfig,
|
||||
FileBasedUnknownFieldVisConfig,
|
||||
} from '../../../stats_table/types/field_vis_config';
|
||||
import { FieldTypeIcon } from '../../../../components/field_type_icon';
|
||||
import { ML_JOB_FIELD_TYPES_OPTIONS } from '../../../index_based/components/search_panel/field_type_filter';
|
||||
} from '../stats_table/types/field_vis_config';
|
||||
import { FieldTypeIcon } from '../field_type_icon';
|
||||
import { JOB_FIELD_TYPES } from '../../../../common';
|
||||
|
||||
const JOB_FIELD_TYPES_OPTIONS = {
|
||||
[JOB_FIELD_TYPES.BOOLEAN]: { name: 'Boolean', icon: 'tokenBoolean' },
|
||||
[JOB_FIELD_TYPES.DATE]: { name: 'Date', icon: 'tokenDate' },
|
||||
[JOB_FIELD_TYPES.GEO_POINT]: { name: 'Geo point', icon: 'tokenGeo' },
|
||||
[JOB_FIELD_TYPES.GEO_SHAPE]: { name: 'Geo shape', icon: 'tokenGeo' },
|
||||
[JOB_FIELD_TYPES.IP]: { name: 'IP address', icon: 'tokenIP' },
|
||||
[JOB_FIELD_TYPES.KEYWORD]: { name: 'Keyword', icon: 'tokenKeyword' },
|
||||
[JOB_FIELD_TYPES.NUMBER]: { name: 'Number', icon: 'tokenNumber' },
|
||||
[JOB_FIELD_TYPES.TEXT]: { name: 'Text', icon: 'tokenString' },
|
||||
[JOB_FIELD_TYPES.UNKNOWN]: { name: 'Unknown' },
|
||||
};
|
||||
|
||||
interface Props {
|
||||
fields: Array<FileBasedFieldVisConfig | FileBasedUnknownFieldVisConfig>;
|
||||
|
@ -29,7 +41,7 @@ export const DataVisualizerFieldTypesFilter: FC<Props> = ({
|
|||
}) => {
|
||||
const fieldNameTitle = useMemo(
|
||||
() =>
|
||||
i18n.translate('xpack.ml.dataVisualizer.fileBased.fieldTypeSelect', {
|
||||
i18n.translate('xpack.fileDataVisualizer.fieldTypeSelect', {
|
||||
defaultMessage: 'Field type',
|
||||
}),
|
||||
[]
|
||||
|
@ -42,9 +54,9 @@ export const DataVisualizerFieldTypesFilter: FC<Props> = ({
|
|||
if (
|
||||
type !== undefined &&
|
||||
!fieldTypesTracker.has(type) &&
|
||||
ML_JOB_FIELD_TYPES_OPTIONS[type] !== undefined
|
||||
JOB_FIELD_TYPES_OPTIONS[type] !== undefined
|
||||
) {
|
||||
const item = ML_JOB_FIELD_TYPES_OPTIONS[type];
|
||||
const item = JOB_FIELD_TYPES_OPTIONS[type];
|
||||
|
||||
fieldTypesTracker.add(type);
|
||||
fieldTypes.push({
|
|
@ -5,11 +5,11 @@
|
|||
* 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 { ML_JOB_FIELD_TYPES } from '../../../../../../common/constants/field_types';
|
||||
import { roundToDecimalPlace } from '../../../../formatters/round_to_decimal_place';
|
||||
import { FileBasedFieldVisConfig } from '../stats_table/types';
|
||||
import { JOB_FIELD_TYPES } from '../../../../common';
|
||||
import { roundToDecimalPlace } from '../utils';
|
||||
|
||||
export function createFields(results: FindFileStructureResponse) {
|
||||
const {
|
||||
|
@ -28,20 +28,20 @@ export function createFields(results: FindFileStructureResponse) {
|
|||
if (fieldStats[name] !== undefined) {
|
||||
const field: FileBasedFieldVisConfig = {
|
||||
fieldName: name,
|
||||
type: ML_JOB_FIELD_TYPES.UNKNOWN,
|
||||
type: JOB_FIELD_TYPES.UNKNOWN,
|
||||
};
|
||||
const f = fieldStats[name];
|
||||
const m = mappings.properties[name];
|
||||
|
||||
// sometimes the timestamp field is not in the mappings, and so our
|
||||
// collection of fields will be missing a time field with a type of date
|
||||
if (name === timestampField && field.type === ML_JOB_FIELD_TYPES.UNKNOWN) {
|
||||
field.type = ML_JOB_FIELD_TYPES.DATE;
|
||||
if (name === timestampField && field.type === JOB_FIELD_TYPES.UNKNOWN) {
|
||||
field.type = JOB_FIELD_TYPES.DATE;
|
||||
}
|
||||
|
||||
if (m !== undefined) {
|
||||
field.type = getSupportedFieldType(m.type);
|
||||
if (field.type === ML_JOB_FIELD_TYPES.NUMBER) {
|
||||
if (field.type === JOB_FIELD_TYPES.NUMBER) {
|
||||
numericFieldsCount += 1;
|
||||
}
|
||||
if (m.format !== undefined) {
|
||||
|
@ -71,7 +71,7 @@ export function createFields(results: FindFileStructureResponse) {
|
|||
}
|
||||
|
||||
if (f.top_hits !== undefined) {
|
||||
if (field.type === ML_JOB_FIELD_TYPES.TEXT) {
|
||||
if (field.type === JOB_FIELD_TYPES.TEXT) {
|
||||
_stats = {
|
||||
..._stats,
|
||||
examples: f.top_hits.map((hit) => hit.value),
|
||||
|
@ -84,7 +84,7 @@ export function createFields(results: FindFileStructureResponse) {
|
|||
}
|
||||
}
|
||||
|
||||
if (field.type === ML_JOB_FIELD_TYPES.DATE) {
|
||||
if (field.type === JOB_FIELD_TYPES.DATE) {
|
||||
_stats = {
|
||||
..._stats,
|
||||
earliest: f.earliest,
|
||||
|
@ -99,9 +99,9 @@ export function createFields(results: FindFileStructureResponse) {
|
|||
// this could be the message field for a semi-structured log file or a
|
||||
// field which the endpoint has not been able to work out any information for
|
||||
const type =
|
||||
mappings.properties[name] && mappings.properties[name].type === ML_JOB_FIELD_TYPES.TEXT
|
||||
? ML_JOB_FIELD_TYPES.TEXT
|
||||
: ML_JOB_FIELD_TYPES.UNKNOWN;
|
||||
mappings.properties[name] && mappings.properties[name].type === JOB_FIELD_TYPES.TEXT
|
||||
? JOB_FIELD_TYPES.TEXT
|
||||
: JOB_FIELD_TYPES.UNKNOWN;
|
||||
|
||||
return {
|
||||
fieldName: name,
|
|
@ -5,29 +5,25 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useMemo, FC } from 'react';
|
||||
import React, { useMemo, FC, useState } from 'react';
|
||||
import { EuiFlexGroup, EuiSpacer } from '@elastic/eui';
|
||||
import type { FindFileStructureResponse } from '../../../../../../../file_upload/common';
|
||||
import { DataVisualizerTable, ItemIdToExpandedRowMap } from '../../../stats_table';
|
||||
import type { FileBasedFieldVisConfig } from '../../../stats_table/types/field_vis_config';
|
||||
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';
|
||||
|
||||
import { DataVisualizerFieldNamesFilter } from '../field_names_filter';
|
||||
import { DataVisualizerFieldTypesFilter } from '../field_types_filter';
|
||||
import { createFields } from './create_fields';
|
||||
import { filterFields } from './filter_fields';
|
||||
import { usePageUrlState } from '../../../../util/url_state';
|
||||
import { ML_PAGES } from '../../../../../../common/constants/ml_url_generator';
|
||||
import {
|
||||
MetricFieldsCount,
|
||||
TotalFieldsCount,
|
||||
} from '../../../stats_table/components/field_count_stats';
|
||||
import type { DataVisualizerFileBasedAppState } from '../../../../../../common/types/ml_url_generator';
|
||||
import { MetricFieldsCount, TotalFieldsCount } from '../stats_table/components/field_count_stats';
|
||||
|
||||
interface Props {
|
||||
results: FindFileStructureResponse;
|
||||
}
|
||||
export const getDefaultDataVisualizerListState = (): Required<DataVisualizerFileBasedAppState> => ({
|
||||
|
||||
export const getDefaultDataVisualizerListState = (): DataVisualizerTableState => ({
|
||||
pageIndex: 0,
|
||||
pageSize: 10,
|
||||
sortField: 'fieldName',
|
||||
|
@ -52,13 +48,11 @@ function getItemIdToExpandedRowMap(
|
|||
|
||||
export const FieldsStatsGrid: FC<Props> = ({ results }) => {
|
||||
const restorableDefaults = getDefaultDataVisualizerListState();
|
||||
const [
|
||||
dataVisualizerListState,
|
||||
setDataVisualizerListState,
|
||||
] = usePageUrlState<DataVisualizerFileBasedAppState>(
|
||||
ML_PAGES.DATA_VISUALIZER_FILE,
|
||||
|
||||
const [dataVisualizerListState, setDataVisualizerListState] = useState<DataVisualizerTableState>(
|
||||
restorableDefaults
|
||||
);
|
||||
|
||||
const visibleFieldTypes =
|
||||
dataVisualizerListState.visibleFieldTypes ?? restorableDefaults.visibleFieldTypes;
|
||||
const setVisibleFieldTypes = (values: string[]) => {
|
||||
|
@ -73,11 +67,11 @@ export const FieldsStatsGrid: FC<Props> = ({ results }) => {
|
|||
|
||||
const { fields, totalFieldsCount, totalMetricFieldsCount } = useMemo(
|
||||
() => createFields(results),
|
||||
[results, visibleFieldNames, visibleFieldTypes]
|
||||
[results]
|
||||
);
|
||||
const { filteredFields, visibleFieldsCount, visibleMetricsCount } = useMemo(
|
||||
() => filterFields(fields, visibleFieldNames, visibleFieldTypes),
|
||||
[results, visibleFieldNames, visibleFieldTypes]
|
||||
[fields, visibleFieldNames, visibleFieldTypes]
|
||||
);
|
||||
|
||||
const fieldsCountStats = { visibleFieldsCount, totalFieldsCount };
|
|
@ -5,11 +5,11 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ML_JOB_FIELD_TYPES } from '../../../../../../common/constants/field_types';
|
||||
import { JOB_FIELD_TYPES } from '../../../../common';
|
||||
import type {
|
||||
FileBasedFieldVisConfig,
|
||||
FileBasedUnknownFieldVisConfig,
|
||||
} from '../../../stats_table/types/field_vis_config';
|
||||
} from '../stats_table/types/field_vis_config';
|
||||
|
||||
export function filterFields(
|
||||
fields: Array<FileBasedFieldVisConfig | FileBasedUnknownFieldVisConfig>,
|
||||
|
@ -32,6 +32,6 @@ export function filterFields(
|
|||
return {
|
||||
filteredFields: items,
|
||||
visibleFieldsCount: items.length,
|
||||
visibleMetricsCount: items.filter((d) => d.type === ML_JOB_FIELD_TYPES.NUMBER).length,
|
||||
visibleMetricsCount: items.filter((d) => d.type === JOB_FIELD_TYPES.NUMBER).length,
|
||||
};
|
||||
}
|
|
@ -6,10 +6,10 @@
|
|||
*/
|
||||
|
||||
import { difference } from 'lodash';
|
||||
import type { FindFileStructureResponse } from '../../../../../../../file_upload/common';
|
||||
import { MlJobFieldType } from '../../../../../../common/types/field_types';
|
||||
import { ML_JOB_FIELD_TYPES } from '../../../../../../common/constants/field_types';
|
||||
import { ES_FIELD_TYPES } from '../../../../../../../../../src/plugins/data/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;
|
||||
|
||||
|
@ -34,7 +34,7 @@ export function getFieldNames(results: FindFileStructureResponse) {
|
|||
return tempFields;
|
||||
}
|
||||
|
||||
export function getSupportedFieldType(type: string): MlJobFieldType {
|
||||
export function getSupportedFieldType(type: string): JobFieldType {
|
||||
switch (type) {
|
||||
case ES_FIELD_TYPES.FLOAT:
|
||||
case ES_FIELD_TYPES.HALF_FLOAT:
|
||||
|
@ -44,13 +44,13 @@ export function getSupportedFieldType(type: string): MlJobFieldType {
|
|||
case ES_FIELD_TYPES.LONG:
|
||||
case ES_FIELD_TYPES.SHORT:
|
||||
case ES_FIELD_TYPES.UNSIGNED_LONG:
|
||||
return ML_JOB_FIELD_TYPES.NUMBER;
|
||||
return JOB_FIELD_TYPES.NUMBER;
|
||||
|
||||
case ES_FIELD_TYPES.DATE:
|
||||
case ES_FIELD_TYPES.DATE_NANOS:
|
||||
return ML_JOB_FIELD_TYPES.DATE;
|
||||
return JOB_FIELD_TYPES.DATE;
|
||||
|
||||
default:
|
||||
return type as MlJobFieldType;
|
||||
return type as JobFieldType;
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@ import React, { FC } from 'react';
|
|||
|
||||
import { EuiTitle, EuiSpacer } from '@elastic/eui';
|
||||
|
||||
import { MLJobEditor, ML_EDITOR_MODE } from '../../../../jobs/jobs_list/components/ml_job_editor';
|
||||
import { JsonEditor, EDITOR_MODE } from '../json_editor';
|
||||
|
||||
interface Props {
|
||||
data: string;
|
||||
|
@ -19,9 +19,9 @@ interface Props {
|
|||
}
|
||||
|
||||
export const FileContents: FC<Props> = ({ data, format, numberOfLines }) => {
|
||||
let mode = ML_EDITOR_MODE.TEXT;
|
||||
if (format === ML_EDITOR_MODE.JSON) {
|
||||
mode = ML_EDITOR_MODE.JSON;
|
||||
let mode = EDITOR_MODE.TEXT;
|
||||
if (format === EDITOR_MODE.JSON) {
|
||||
mode = EDITOR_MODE.JSON;
|
||||
}
|
||||
|
||||
const formattedData = limitByNumberOfLines(data, numberOfLines);
|
||||
|
@ -31,7 +31,7 @@ export const FileContents: FC<Props> = ({ data, format, numberOfLines }) => {
|
|||
<EuiTitle size="s">
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fileContents.fileContentsTitle"
|
||||
id="xpack.fileDataVisualizer.fileContents.fileContentsTitle"
|
||||
defaultMessage="File contents"
|
||||
/>
|
||||
</h2>
|
||||
|
@ -39,7 +39,7 @@ export const FileContents: FC<Props> = ({ data, format, numberOfLines }) => {
|
|||
|
||||
<div>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fileContents.firstLinesDescription"
|
||||
id="xpack.fileDataVisualizer.fileContents.firstLinesDescription"
|
||||
defaultMessage="First {numberOfLines, plural, zero {# line} one {# line} other {# lines}}"
|
||||
values={{
|
||||
numberOfLines,
|
||||
|
@ -49,7 +49,7 @@ export const FileContents: FC<Props> = ({ data, format, numberOfLines }) => {
|
|||
|
||||
<EuiSpacer size="s" />
|
||||
|
||||
<MLJobEditor
|
||||
<JsonEditor
|
||||
mode={mode}
|
||||
readOnly={true}
|
||||
value={formattedData}
|
|
@ -12,7 +12,6 @@ import { EuiSpacer } from '@elastic/eui';
|
|||
|
||||
import { isEqual } from 'lodash';
|
||||
|
||||
import { ml } from '../../../../services/ml_api_service';
|
||||
import { AboutPanel, LoadingPanel } from '../about_panel';
|
||||
import { BottomBar } from '../bottom_bar';
|
||||
import { ResultsView } from '../results_view';
|
||||
|
@ -21,7 +20,6 @@ import { EditFlyout } from '../edit_flyout';
|
|||
import { ExplanationFlyout } from '../explanation_flyout';
|
||||
import { ImportView } from '../import_view';
|
||||
import { DEFAULT_LINES_TO_SAMPLE, readFile, createUrlOverrides, processResults } from '../utils';
|
||||
import { getFileUpload } from '../../../../util/dependency_cache';
|
||||
|
||||
import { MODE } from './constants';
|
||||
|
||||
|
@ -54,14 +52,16 @@ export class FileDataVisualizerView extends Component {
|
|||
this.originalSettings = {
|
||||
linesToSample: DEFAULT_LINES_TO_SAMPLE,
|
||||
};
|
||||
this.maxFileUploadBytes = getFileUpload().getMaxBytes();
|
||||
|
||||
this.savedObjectsClient = props.savedObjectsClient;
|
||||
this.maxFileUploadBytes = props.fileUpload.getMaxBytes();
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
// check the user has the correct permission to import data.
|
||||
// note, calling hasImportPermission with no arguments just checks the
|
||||
// cluster privileges, the user will still need index privileges to create and ingest
|
||||
const hasPermissionToImport = await getFileUpload().hasImportPermission({
|
||||
const hasPermissionToImport = await this.props.fileUpload.hasImportPermission({
|
||||
checkCreateIndexPattern: false,
|
||||
checkHasManagePipeline: true,
|
||||
});
|
||||
|
@ -126,7 +126,7 @@ export class FileDataVisualizerView extends Component {
|
|||
|
||||
async analyzeFile(fileContents, overrides, isRetry = false) {
|
||||
try {
|
||||
const resp = await ml.fileDatavisualizer.analyzeFile(fileContents, overrides);
|
||||
const resp = await this.props.fileUpload.analyzeFile(fileContents, overrides);
|
||||
const serverSettings = processResults(resp);
|
||||
const serverOverrides = resp.overrides;
|
||||
|
||||
|
@ -137,7 +137,7 @@ export class FileDataVisualizerView extends Component {
|
|||
throw {
|
||||
message: (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fileDatavisualizerView.xmlNotCurrentlySupportedErrorMessage"
|
||||
id="xpack.fileDataVisualizer.fileDatavisualizerView.xmlNotCurrentlySupportedErrorMessage"
|
||||
defaultMessage="XML not currently supported"
|
||||
/>
|
||||
),
|
||||
|
@ -345,9 +345,10 @@ export class FileDataVisualizerView extends Component {
|
|||
fileContents={fileContents}
|
||||
data={data}
|
||||
indexPatterns={this.props.indexPatterns}
|
||||
kibanaConfig={this.props.kibanaConfig}
|
||||
showBottomBar={this.showBottomBar}
|
||||
hideBottomBar={this.hideBottomBar}
|
||||
savedObjectsClient={this.savedObjectsClient}
|
||||
fileUpload={this.props.fileUpload}
|
||||
/>
|
||||
|
||||
{bottomBarVisible && (
|
|
@ -11,8 +11,8 @@ import React, { FC } from 'react';
|
|||
import { EuiCallOut, EuiSpacer, EuiButtonEmpty, EuiHorizontalRule } from '@elastic/eui';
|
||||
|
||||
import numeral from '@elastic/numeral';
|
||||
import { ErrorResponse } from '../../../../../../common/types/errors';
|
||||
import { FILE_SIZE_DISPLAY_FORMAT } from '../../../../../../../file_upload/public';
|
||||
import { FILE_SIZE_DISPLAY_FORMAT } from '../../../../common';
|
||||
import { FindFileStructureErrorResponse } from '../../../../../file_upload/common';
|
||||
|
||||
interface FileTooLargeProps {
|
||||
fileSize: number;
|
||||
|
@ -31,7 +31,7 @@ export const FileTooLarge: FC<FileTooLargeProps> = ({ fileSize, maxFileSize }) =
|
|||
errorText = (
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fileErrorCallouts.fileSizeExceedsAllowedSizeErrorMessage"
|
||||
id="xpack.fileDataVisualizer.fileErrorCallouts.fileSizeExceedsAllowedSizeErrorMessage"
|
||||
defaultMessage="The size of the file you selected for upload is {fileSizeFormatted} which
|
||||
exceeds the maximum permitted size of {maxFileSizeFormatted}"
|
||||
values={{
|
||||
|
@ -46,7 +46,7 @@ export const FileTooLarge: FC<FileTooLargeProps> = ({ fileSize, maxFileSize }) =
|
|||
errorText = (
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fileErrorCallouts.fileSizeExceedsAllowedSizeByDiffFormatErrorMessage"
|
||||
id="xpack.fileDataVisualizer.fileErrorCallouts.fileSizeExceedsAllowedSizeByDiffFormatErrorMessage"
|
||||
defaultMessage="The size of the file you selected for upload exceeds the maximum
|
||||
permitted size of {maxFileSizeFormatted} by {diffFormatted}"
|
||||
values={{
|
||||
|
@ -62,7 +62,7 @@ export const FileTooLarge: FC<FileTooLargeProps> = ({ fileSize, maxFileSize }) =
|
|||
<EuiCallOut
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fileErrorCallouts.fileSizeTooLargeTitle"
|
||||
id="xpack.fileDataVisualizer.fileErrorCallouts.fileSizeTooLargeTitle"
|
||||
defaultMessage="File size is too large"
|
||||
/>
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ export const FileTooLarge: FC<FileTooLargeProps> = ({ fileSize, maxFileSize }) =
|
|||
};
|
||||
|
||||
interface FileCouldNotBeReadProps {
|
||||
error: ErrorResponse;
|
||||
error: FindFileStructureErrorResponse;
|
||||
loaded: boolean;
|
||||
showEditFlyout(): void;
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ export const FileCouldNotBeRead: FC<FileCouldNotBeReadProps> = ({
|
|||
<EuiCallOut
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fileErrorCallouts.fileCouldNotBeReadTitle"
|
||||
id="xpack.fileDataVisualizer.fileErrorCallouts.fileCouldNotBeReadTitle"
|
||||
defaultMessage="File structure cannot be determined"
|
||||
/>
|
||||
}
|
||||
|
@ -103,13 +103,13 @@ export const FileCouldNotBeRead: FC<FileCouldNotBeReadProps> = ({
|
|||
{loaded === false && (
|
||||
<>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fileErrorCallouts.applyOverridesDescription"
|
||||
id="xpack.fileDataVisualizer.fileErrorCallouts.applyOverridesDescription"
|
||||
defaultMessage="If you know something about this data, such as the file format or timestamp format, adding initial overrides may help us to infer the rest of the structure."
|
||||
/>
|
||||
<br />
|
||||
<EuiButtonEmpty onClick={showEditFlyout} flush="left" size="xs">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fileErrorCallouts.overrideButton"
|
||||
id="xpack.fileDataVisualizer.fileErrorCallouts.overrideButton"
|
||||
defaultMessage="Apply override settings"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
|
@ -122,7 +122,7 @@ export const FileCouldNotBeRead: FC<FileCouldNotBeReadProps> = ({
|
|||
<>
|
||||
<EuiSpacer size="s" />
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fileErrorCallouts.revertingToPreviousSettingsDescription"
|
||||
id="xpack.fileDataVisualizer.fileErrorCallouts.revertingToPreviousSettingsDescription"
|
||||
defaultMessage="Reverting to previous settings"
|
||||
/>
|
||||
</>
|
||||
|
@ -132,11 +132,11 @@ export const FileCouldNotBeRead: FC<FileCouldNotBeReadProps> = ({
|
|||
);
|
||||
};
|
||||
|
||||
export const Explanation: FC<{ error: ErrorResponse }> = ({ error }) => {
|
||||
export const Explanation: FC<{ error: FindFileStructureErrorResponse }> = ({ error }) => {
|
||||
if (!error?.body?.attributes?.body?.error?.suppressed?.length) {
|
||||
return null;
|
||||
}
|
||||
const reason: string = error.body.attributes.body.error.suppressed[0].reason;
|
||||
const reason = error.body.attributes.body.error.suppressed[0].reason;
|
||||
return (
|
||||
<>
|
||||
<EuiSpacer size="s" />
|
|
@ -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.ml.fileDatavisualizer.fileBeatConfig.paths', {
|
||||
const txt = i18n.translate('xpack.fileDataVisualizer.fileBeatConfig.paths', {
|
||||
defaultMessage: 'add path to your files here',
|
||||
});
|
||||
return [' paths:', ` - '<${txt}>'`];
|
|
@ -22,8 +22,8 @@ import {
|
|||
EuiCopy,
|
||||
} from '@elastic/eui';
|
||||
import { createFilebeatConfig } from './filebeat_config';
|
||||
import { useMlKibana } from '../../../../contexts/kibana';
|
||||
import { FindFileStructureResponse } from '../../../../../../../file_upload/common';
|
||||
import { useFileDataVisualizerKibana } 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 },
|
||||
} = useMlKibana();
|
||||
} = useFileDataVisualizerKibana();
|
||||
|
||||
useEffect(() => {
|
||||
if (security !== undefined) {
|
||||
|
@ -56,12 +56,12 @@ export const FilebeatConfigFlyout: FC<Props> = ({
|
|||
setUsername(user.username === undefined ? null : user.username);
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
}, [security]);
|
||||
|
||||
useEffect(() => {
|
||||
const config = createFilebeatConfig(index, results, ingestPipelineId, username);
|
||||
setFileBeatConfig(config);
|
||||
}, [username]);
|
||||
}, [username, index, ingestPipelineId, results]);
|
||||
|
||||
return (
|
||||
<EuiFlyout onClose={closeFlyout} hideCloseButton size={'m'}>
|
||||
|
@ -75,7 +75,7 @@ export const FilebeatConfigFlyout: FC<Props> = ({
|
|||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty iconType="cross" onClick={closeFlyout} flush="left">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fileBeatConfigFlyout.closeButton"
|
||||
id="xpack.fileDataVisualizer.fileBeatConfigFlyout.closeButton"
|
||||
defaultMessage="Close"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
|
@ -85,7 +85,7 @@ export const FilebeatConfigFlyout: FC<Props> = ({
|
|||
{(copy) => (
|
||||
<EuiButton onClick={copy}>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fileBeatConfigFlyout.copyButton"
|
||||
id="xpack.fileDataVisualizer.fileBeatConfigFlyout.copyButton"
|
||||
defaultMessage="Copy to clipboard"
|
||||
/>
|
||||
</EuiButton>
|
||||
|
@ -108,7 +108,7 @@ const Contents: FC<{
|
|||
<EuiTitle size="s">
|
||||
<h5>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.resultsLinks.fileBeatConfigTitle"
|
||||
id="xpack.fileDataVisualizer.resultsLinks.fileBeatConfigTitle"
|
||||
defaultMessage="Filebeat configuration"
|
||||
/>
|
||||
</h5>
|
||||
|
@ -116,14 +116,14 @@ const Contents: FC<{
|
|||
<EuiSpacer size="s" />
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.resultsLinks.fileBeatConfigTopText1"
|
||||
id="xpack.fileDataVisualizer.resultsLinks.fileBeatConfigTopText1"
|
||||
defaultMessage="Additional data can be uploaded to the {index} index using Filebeat."
|
||||
values={{ index: <EuiCode>{index}</EuiCode> }}
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.resultsLinks.fileBeatConfigTopText2"
|
||||
id="xpack.fileDataVisualizer.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.ml.fileDatavisualizer.resultsLinks.fileBeatConfigBottomTextNoUsername"
|
||||
id="xpack.fileDataVisualizer.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.ml.fileDatavisualizer.resultsLinks.fileBeatConfigBottomText"
|
||||
id="xpack.fileDataVisualizer.resultsLinks.fileBeatConfigBottomText"
|
||||
defaultMessage="Where {password} is the password of the {user} user, {esUrl} is the URL of Elasticsearch."
|
||||
values={{
|
||||
user: <EuiCode>{username}</EuiCode>,
|
|
@ -38,56 +38,56 @@ function title(statuses: Statuses) {
|
|||
case statuses.readStatus:
|
||||
return (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importErrors.readingFileErrorMessage"
|
||||
id="xpack.fileDataVisualizer.importErrors.readingFileErrorMessage"
|
||||
defaultMessage="Error reading file"
|
||||
/>
|
||||
);
|
||||
case statuses.parseJSONStatus:
|
||||
return (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importErrors.parsingJSONErrorMessage"
|
||||
id="xpack.fileDataVisualizer.importErrors.parsingJSONErrorMessage"
|
||||
defaultMessage="Error parsing JSON"
|
||||
/>
|
||||
);
|
||||
case statuses.indexCreatedStatus:
|
||||
return (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importErrors.creatingIndexErrorMessage"
|
||||
id="xpack.fileDataVisualizer.importErrors.creatingIndexErrorMessage"
|
||||
defaultMessage="Error creating index"
|
||||
/>
|
||||
);
|
||||
case statuses.ingestPipelineCreatedStatus:
|
||||
return (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importErrors.creatingIngestPipelineErrorMessage"
|
||||
id="xpack.fileDataVisualizer.importErrors.creatingIngestPipelineErrorMessage"
|
||||
defaultMessage="Error creating ingest pipeline"
|
||||
/>
|
||||
);
|
||||
case statuses.uploadStatus:
|
||||
return (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importErrors.uploadingDataErrorMessage"
|
||||
id="xpack.fileDataVisualizer.importErrors.uploadingDataErrorMessage"
|
||||
defaultMessage="Error uploading data"
|
||||
/>
|
||||
);
|
||||
case statuses.indexPatternCreatedStatus:
|
||||
return (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importErrors.creatingIndexPatternErrorMessage"
|
||||
id="xpack.fileDataVisualizer.importErrors.creatingIndexPatternErrorMessage"
|
||||
defaultMessage="Error creating index pattern"
|
||||
/>
|
||||
);
|
||||
case statuses.permissionCheckStatus:
|
||||
return (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importErrors.checkingPermissionErrorMessage"
|
||||
id="xpack.fileDataVisualizer.importErrors.checkingPermissionErrorMessage"
|
||||
defaultMessage="Import permissions error"
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importErrors.defaultErrorMessage"
|
||||
id="xpack.fileDataVisualizer.importErrors.defaultErrorMessage"
|
||||
defaultMessage="Error"
|
||||
/>
|
||||
);
|
||||
|
@ -105,7 +105,7 @@ const ImportError: FC<{ error: any }> = ({ error }) => {
|
|||
id="more"
|
||||
buttonContent={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importErrors.moreButtonLabel"
|
||||
id="xpack.fileDataVisualizer.importErrors.moreButtonLabel"
|
||||
defaultMessage="More"
|
||||
/>
|
||||
}
|
||||
|
@ -151,7 +151,7 @@ function toString(error: any): ImportError {
|
|||
}
|
||||
|
||||
return {
|
||||
msg: i18n.translate('xpack.ml.fileDatavisualizer.importErrors.unknownErrorMessage', {
|
||||
msg: i18n.translate('xpack.fileDataVisualizer.importErrors.unknownErrorMessage', {
|
||||
defaultMessage: 'Unknown error',
|
||||
}),
|
||||
};
|
|
@ -80,31 +80,31 @@ export const ImportProgress: FC<{ statuses: Statuses }> = ({ statuses }) => {
|
|||
}
|
||||
|
||||
let processFileTitle = i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.importProgress.processFileTitle',
|
||||
'xpack.fileDataVisualizer.importProgress.processFileTitle',
|
||||
{
|
||||
defaultMessage: 'Process file',
|
||||
}
|
||||
);
|
||||
let createIndexTitle = i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.importProgress.createIndexTitle',
|
||||
'xpack.fileDataVisualizer.importProgress.createIndexTitle',
|
||||
{
|
||||
defaultMessage: 'Create index',
|
||||
}
|
||||
);
|
||||
let createIngestPipelineTitle = i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.importProgress.createIngestPipelineTitle',
|
||||
'xpack.fileDataVisualizer.importProgress.createIngestPipelineTitle',
|
||||
{
|
||||
defaultMessage: 'Create ingest pipeline',
|
||||
}
|
||||
);
|
||||
let uploadingDataTitle = i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.importProgress.uploadDataTitle',
|
||||
'xpack.fileDataVisualizer.importProgress.uploadDataTitle',
|
||||
{
|
||||
defaultMessage: 'Upload data',
|
||||
}
|
||||
);
|
||||
let createIndexPatternTitle = i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.importProgress.createIndexPatternTitle',
|
||||
'xpack.fileDataVisualizer.importProgress.createIndexPatternTitle',
|
||||
{
|
||||
defaultMessage: 'Create index pattern',
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ export const ImportProgress: FC<{ statuses: Statuses }> = ({ statuses }) => {
|
|||
const creatingIndexStatus = (
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importProgress.stepTwoCreatingIndexDescription"
|
||||
id="xpack.fileDataVisualizer.importProgress.stepTwoCreatingIndexDescription"
|
||||
defaultMessage="Creating index"
|
||||
/>
|
||||
</p>
|
||||
|
@ -122,7 +122,7 @@ export const ImportProgress: FC<{ statuses: Statuses }> = ({ statuses }) => {
|
|||
const creatingIndexAndIngestPipelineStatus = (
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importProgress.stepTwoCreatingIndexIngestPipelineDescription"
|
||||
id="xpack.fileDataVisualizer.importProgress.stepTwoCreatingIndexIngestPipelineDescription"
|
||||
defaultMessage="Creating index and ingest pipeline"
|
||||
/>
|
||||
</p>
|
||||
|
@ -130,7 +130,7 @@ export const ImportProgress: FC<{ statuses: Statuses }> = ({ statuses }) => {
|
|||
|
||||
if (completedStep >= 0) {
|
||||
processFileTitle = i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.importProgress.processingFileTitle',
|
||||
'xpack.fileDataVisualizer.importProgress.processingFileTitle',
|
||||
{
|
||||
defaultMessage: 'Processing file',
|
||||
}
|
||||
|
@ -138,7 +138,7 @@ export const ImportProgress: FC<{ statuses: Statuses }> = ({ statuses }) => {
|
|||
statusInfo = (
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importProgress.processingImportedFileDescription"
|
||||
id="xpack.fileDataVisualizer.importProgress.processingImportedFileDescription"
|
||||
defaultMessage="Processing file for import"
|
||||
/>
|
||||
</p>
|
||||
|
@ -146,13 +146,13 @@ export const ImportProgress: FC<{ statuses: Statuses }> = ({ statuses }) => {
|
|||
}
|
||||
if (completedStep >= 1) {
|
||||
processFileTitle = i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.importProgress.fileProcessedTitle',
|
||||
'xpack.fileDataVisualizer.importProgress.fileProcessedTitle',
|
||||
{
|
||||
defaultMessage: 'File processed',
|
||||
}
|
||||
);
|
||||
createIndexTitle = i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.importProgress.creatingIndexTitle',
|
||||
'xpack.fileDataVisualizer.importProgress.creatingIndexTitle',
|
||||
{
|
||||
defaultMessage: 'Creating index',
|
||||
}
|
||||
|
@ -161,14 +161,11 @@ export const ImportProgress: FC<{ statuses: Statuses }> = ({ statuses }) => {
|
|||
createPipeline === true ? creatingIndexAndIngestPipelineStatus : creatingIndexStatus;
|
||||
}
|
||||
if (completedStep >= 2) {
|
||||
createIndexTitle = i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.importProgress.indexCreatedTitle',
|
||||
{
|
||||
defaultMessage: 'Index created',
|
||||
}
|
||||
);
|
||||
createIndexTitle = i18n.translate('xpack.fileDataVisualizer.importProgress.indexCreatedTitle', {
|
||||
defaultMessage: 'Index created',
|
||||
});
|
||||
createIngestPipelineTitle = i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.importProgress.creatingIngestPipelineTitle',
|
||||
'xpack.fileDataVisualizer.importProgress.creatingIngestPipelineTitle',
|
||||
{
|
||||
defaultMessage: 'Creating ingest pipeline',
|
||||
}
|
||||
|
@ -178,13 +175,13 @@ export const ImportProgress: FC<{ statuses: Statuses }> = ({ statuses }) => {
|
|||
}
|
||||
if (completedStep >= 3) {
|
||||
createIngestPipelineTitle = i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.importProgress.ingestPipelineCreatedTitle',
|
||||
'xpack.fileDataVisualizer.importProgress.ingestPipelineCreatedTitle',
|
||||
{
|
||||
defaultMessage: 'Ingest pipeline created',
|
||||
}
|
||||
);
|
||||
uploadingDataTitle = i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.importProgress.uploadingDataTitle',
|
||||
'xpack.fileDataVisualizer.importProgress.uploadingDataTitle',
|
||||
{
|
||||
defaultMessage: 'Uploading data',
|
||||
}
|
||||
|
@ -193,14 +190,14 @@ export const ImportProgress: FC<{ statuses: Statuses }> = ({ statuses }) => {
|
|||
}
|
||||
if (completedStep >= 4) {
|
||||
uploadingDataTitle = i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.importProgress.dataUploadedTitle',
|
||||
'xpack.fileDataVisualizer.importProgress.dataUploadedTitle',
|
||||
{
|
||||
defaultMessage: 'Data uploaded',
|
||||
}
|
||||
);
|
||||
if (createIndexPattern === true) {
|
||||
createIndexPatternTitle = i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.importProgress.creatingIndexPatternTitle',
|
||||
'xpack.fileDataVisualizer.importProgress.creatingIndexPatternTitle',
|
||||
{
|
||||
defaultMessage: 'Creating index pattern',
|
||||
}
|
||||
|
@ -208,7 +205,7 @@ export const ImportProgress: FC<{ statuses: Statuses }> = ({ statuses }) => {
|
|||
statusInfo = (
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importProgress.creatingIndexPatternDescription"
|
||||
id="xpack.fileDataVisualizer.importProgress.creatingIndexPatternDescription"
|
||||
defaultMessage="Creating index pattern"
|
||||
/>
|
||||
</p>
|
||||
|
@ -219,7 +216,7 @@ export const ImportProgress: FC<{ statuses: Statuses }> = ({ statuses }) => {
|
|||
}
|
||||
if (completedStep >= 5) {
|
||||
createIndexPatternTitle = i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.importProgress.indexPatternCreatedTitle',
|
||||
'xpack.fileDataVisualizer.importProgress.indexPatternCreatedTitle',
|
||||
{
|
||||
defaultMessage: 'Index pattern created',
|
||||
}
|
||||
|
@ -293,7 +290,7 @@ const UploadFunctionProgress: FC<{ progress: number }> = ({ progress }) => {
|
|||
<React.Fragment>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importProgress.uploadingDataDescription"
|
||||
id="xpack.fileDataVisualizer.importProgress.uploadingDataDescription"
|
||||
defaultMessage="Uploading data"
|
||||
/>
|
||||
</p>
|
|
@ -19,8 +19,8 @@ import {
|
|||
} from '@elastic/eui';
|
||||
|
||||
import { CombinedField, CombinedFieldsForm } from '../combined_fields';
|
||||
import { MLJobEditor, ML_EDITOR_MODE } from '../../../../jobs/jobs_list/components/ml_job_editor';
|
||||
import { FindFileStructureResponse } from '../../../../../../../file_upload/common';
|
||||
import { JsonEditor, EDITOR_MODE } from '../json_editor';
|
||||
import { FindFileStructureResponse } from '../../../../../file_upload/common';
|
||||
const EDITOR_HEIGHT = '300px';
|
||||
|
||||
interface Props {
|
||||
|
@ -69,7 +69,7 @@ export const AdvancedSettings: FC<Props> = ({
|
|||
<EuiFormRow
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.advancedImportSettings.indexNameLabel"
|
||||
id="xpack.fileDataVisualizer.advancedImportSettings.indexNameLabel"
|
||||
defaultMessage="Index name"
|
||||
/>
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ export const AdvancedSettings: FC<Props> = ({
|
|||
>
|
||||
<EuiFieldText
|
||||
placeholder={i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.advancedImportSettings.indexNamePlaceholder',
|
||||
'xpack.fileDataVisualizer.advancedImportSettings.indexNamePlaceholder',
|
||||
{
|
||||
defaultMessage: 'index name',
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ export const AdvancedSettings: FC<Props> = ({
|
|||
onChange={onIndexChange}
|
||||
isInvalid={indexNameError !== ''}
|
||||
aria-label={i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.advancedImportSettings.indexNameAriaLabel',
|
||||
'xpack.fileDataVisualizer.advancedImportSettings.indexNameAriaLabel',
|
||||
{
|
||||
defaultMessage: 'Index name, required field',
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ export const AdvancedSettings: FC<Props> = ({
|
|||
id="createIndexPattern"
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.advancedImportSettings.createIndexPatternLabel"
|
||||
id="xpack.fileDataVisualizer.advancedImportSettings.createIndexPatternLabel"
|
||||
defaultMessage="Create index pattern"
|
||||
/>
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ export const AdvancedSettings: FC<Props> = ({
|
|||
<EuiFormRow
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.advancedImportSettings.indexPatternNameLabel"
|
||||
id="xpack.fileDataVisualizer.advancedImportSettings.indexPatternNameLabel"
|
||||
defaultMessage="Index pattern name"
|
||||
/>
|
||||
}
|
||||
|
@ -184,14 +184,14 @@ const IndexSettings: FC<JsonEditorProps> = ({ initialized, data, onChange }) =>
|
|||
<EuiFormRow
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.advancedImportSettings.indexSettingsLabel"
|
||||
id="xpack.fileDataVisualizer.advancedImportSettings.indexSettingsLabel"
|
||||
defaultMessage="Index settings"
|
||||
/>
|
||||
}
|
||||
fullWidth
|
||||
>
|
||||
<MLJobEditor
|
||||
mode={ML_EDITOR_MODE.JSON}
|
||||
<JsonEditor
|
||||
mode={EDITOR_MODE.JSON}
|
||||
readOnly={initialized === true}
|
||||
value={data}
|
||||
height={EDITOR_HEIGHT}
|
||||
|
@ -209,14 +209,14 @@ const Mappings: FC<JsonEditorProps> = ({ initialized, data, onChange }) => {
|
|||
<EuiFormRow
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.advancedImportSettings.mappingsLabel"
|
||||
id="xpack.fileDataVisualizer.advancedImportSettings.mappingsLabel"
|
||||
defaultMessage="Mappings"
|
||||
/>
|
||||
}
|
||||
fullWidth
|
||||
>
|
||||
<MLJobEditor
|
||||
mode={ML_EDITOR_MODE.JSON}
|
||||
<JsonEditor
|
||||
mode={EDITOR_MODE.JSON}
|
||||
readOnly={initialized === true}
|
||||
value={data}
|
||||
height={EDITOR_HEIGHT}
|
||||
|
@ -234,14 +234,14 @@ const IngestPipeline: FC<JsonEditorProps> = ({ initialized, data, onChange }) =>
|
|||
<EuiFormRow
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.advancedImportSettings.ingestPipelineLabel"
|
||||
id="xpack.fileDataVisualizer.advancedImportSettings.ingestPipelineLabel"
|
||||
defaultMessage="Ingest pipeline"
|
||||
/>
|
||||
}
|
||||
fullWidth
|
||||
>
|
||||
<MLJobEditor
|
||||
mode={ML_EDITOR_MODE.JSON}
|
||||
<JsonEditor
|
||||
mode={EDITOR_MODE.JSON}
|
||||
readOnly={initialized === true}
|
||||
value={data}
|
||||
height={EDITOR_HEIGHT}
|
|
@ -13,7 +13,7 @@ import { EuiTabbedContent, EuiSpacer } from '@elastic/eui';
|
|||
import { SimpleSettings } from './simple';
|
||||
import { AdvancedSettings } from './advanced';
|
||||
import { CombinedField } from '../combined_fields';
|
||||
import { FindFileStructureResponse } from '../../../../../../../file_upload/common';
|
||||
import { FindFileStructureResponse } from '../../../../../file_upload/common';
|
||||
|
||||
interface Props {
|
||||
index: string;
|
||||
|
@ -59,7 +59,7 @@ export const ImportSettings: FC<Props> = ({
|
|||
const tabs = [
|
||||
{
|
||||
id: 'simple-settings',
|
||||
name: i18n.translate('xpack.ml.fileDatavisualizer.importSettings.simpleTabName', {
|
||||
name: i18n.translate('xpack.fileDataVisualizer.importSettings.simpleTabName', {
|
||||
defaultMessage: 'Simple',
|
||||
}),
|
||||
content: (
|
||||
|
@ -80,7 +80,7 @@ export const ImportSettings: FC<Props> = ({
|
|||
},
|
||||
{
|
||||
id: 'advanced-settings',
|
||||
name: i18n.translate('xpack.ml.fileDatavisualizer.importSettings.advancedTabName', {
|
||||
name: i18n.translate('xpack.fileDataVisualizer.importSettings.advancedTabName', {
|
||||
defaultMessage: 'Advanced',
|
||||
}),
|
||||
content: (
|
|
@ -36,7 +36,7 @@ export const SimpleSettings: FC<Props> = ({
|
|||
<EuiFormRow
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.simpleImportSettings.indexNameFormRowLabel"
|
||||
id="xpack.fileDataVisualizer.simpleImportSettings.indexNameFormRowLabel"
|
||||
defaultMessage="Index name"
|
||||
/>
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ export const SimpleSettings: FC<Props> = ({
|
|||
>
|
||||
<EuiFieldText
|
||||
placeholder={i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.simpleImportSettings.indexNamePlaceholder',
|
||||
'xpack.fileDataVisualizer.simpleImportSettings.indexNamePlaceholder',
|
||||
{
|
||||
defaultMessage: 'index name',
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ export const SimpleSettings: FC<Props> = ({
|
|||
onChange={onIndexChange}
|
||||
isInvalid={indexNameError !== ''}
|
||||
aria-label={i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.simpleImportSettings.indexNameAriaLabel',
|
||||
'xpack.fileDataVisualizer.simpleImportSettings.indexNameAriaLabel',
|
||||
{
|
||||
defaultMessage: 'Index name, required field',
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ export const SimpleSettings: FC<Props> = ({
|
|||
id="createIndexPattern"
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.simpleImportSettings.createIndexPatternLabel"
|
||||
id="xpack.fileDataVisualizer.simpleImportSettings.createIndexPatternLabel"
|
||||
defaultMessage="Create index pattern"
|
||||
/>
|
||||
}
|
|
@ -51,7 +51,7 @@ export class Failures extends Component<Props, State> {
|
|||
id="failureList"
|
||||
buttonContent={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importSummary.failedDocumentsButtonLabel"
|
||||
id="xpack.fileDataVisualizer.importSummary.failedDocumentsButtonLabel"
|
||||
defaultMessage="Failed documents"
|
||||
/>
|
||||
}
|
|
@ -45,7 +45,7 @@ export const ImportSummary: FC<Props> = ({
|
|||
<EuiCallOut
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importSummary.importCompleteTitle"
|
||||
id="xpack.fileDataVisualizer.importSummary.importCompleteTitle"
|
||||
defaultMessage="Import complete"
|
||||
/>
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ export const ImportSummary: FC<Props> = ({
|
|||
<EuiCallOut
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importSummary.documentsCouldNotBeImportedTitle"
|
||||
id="xpack.fileDataVisualizer.importSummary.documentsCouldNotBeImportedTitle"
|
||||
defaultMessage="Some documents could not be imported"
|
||||
/>
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ export const ImportSummary: FC<Props> = ({
|
|||
>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importSummary.documentsCouldNotBeImportedDescription"
|
||||
id="xpack.fileDataVisualizer.importSummary.documentsCouldNotBeImportedDescription"
|
||||
defaultMessage="{importFailuresLength} out of {docCount} documents could not be imported.
|
||||
This could be due to lines not matching the Grok pattern."
|
||||
values={{
|
||||
|
@ -102,7 +102,7 @@ function createDisplayItems(
|
|||
{
|
||||
title: (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importSummary.indexTitle"
|
||||
id="xpack.fileDataVisualizer.importSummary.indexTitle"
|
||||
defaultMessage="Index"
|
||||
/>
|
||||
),
|
||||
|
@ -111,7 +111,7 @@ function createDisplayItems(
|
|||
{
|
||||
title: (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importSummary.documentsIngestedTitle"
|
||||
id="xpack.fileDataVisualizer.importSummary.documentsIngestedTitle"
|
||||
defaultMessage="Documents ingested"
|
||||
/>
|
||||
),
|
||||
|
@ -123,7 +123,7 @@ function createDisplayItems(
|
|||
items.splice(1, 0, {
|
||||
title: (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importSummary.ingestPipelineTitle"
|
||||
id="xpack.fileDataVisualizer.importSummary.ingestPipelineTitle"
|
||||
defaultMessage="Ingest pipeline"
|
||||
/>
|
||||
),
|
||||
|
@ -135,7 +135,7 @@ function createDisplayItems(
|
|||
items.splice(1, 0, {
|
||||
title: (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importSummary.indexPatternTitle"
|
||||
id="xpack.fileDataVisualizer.importSummary.indexPatternTitle"
|
||||
defaultMessage="Index pattern"
|
||||
/>
|
||||
),
|
||||
|
@ -147,7 +147,7 @@ function createDisplayItems(
|
|||
items.push({
|
||||
title: (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importSummary.failedDocumentsTitle"
|
||||
id="xpack.fileDataVisualizer.importSummary.failedDocumentsTitle"
|
||||
defaultMessage="Failed documents"
|
||||
/>
|
||||
),
|
|
@ -20,7 +20,6 @@ import {
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { debounce } from 'lodash';
|
||||
import { getFileUpload } from '../../../../util/dependency_cache';
|
||||
import { ResultsLinks } from '../results_links';
|
||||
import { FilebeatConfigFlyout } from '../filebeat_config_flyout';
|
||||
import { ImportProgress, IMPORT_STATUS } from '../import_progress';
|
||||
|
@ -33,8 +32,6 @@ import {
|
|||
getDefaultCombinedFields,
|
||||
} from '../combined_fields';
|
||||
import { ExperimentalBadge } from '../experimental_badge';
|
||||
import { getIndexPatternNames, loadIndexPatterns } from '../../../../util/index_utils';
|
||||
import { ml } from '../../../../services/ml_api_service';
|
||||
|
||||
const DEFAULT_TIME_FIELD = '@timestamp';
|
||||
const DEFAULT_INDEX_SETTINGS = { number_of_shards: 1 };
|
||||
|
@ -81,6 +78,7 @@ export class ImportView extends Component {
|
|||
super(props);
|
||||
|
||||
this.state = getDefaultState(DEFAULT_STATE, this.props.results);
|
||||
this.savedObjectsClient = props.savedObjectsClient;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
@ -100,7 +98,7 @@ export class ImportView extends Component {
|
|||
|
||||
// TODO - sort this function out. it's a mess
|
||||
async import() {
|
||||
const { data, results, indexPatterns, kibanaConfig, showBottomBar } = this.props;
|
||||
const { data, results, indexPatterns, showBottomBar, fileUpload } = this.props;
|
||||
|
||||
const { format } = results;
|
||||
let { timeFieldName } = this.state;
|
||||
|
@ -124,14 +122,14 @@ export class ImportView extends Component {
|
|||
async () => {
|
||||
// check to see if the user has permission to create and ingest data into the specified index
|
||||
if (
|
||||
(await getFileUpload().hasImportPermission({
|
||||
(await fileUpload.hasImportPermission({
|
||||
checkCreateIndexPattern: createIndexPattern,
|
||||
checkHasManagePipeline: true,
|
||||
indexName: index,
|
||||
})) === false
|
||||
) {
|
||||
errors.push(
|
||||
i18n.translate('xpack.ml.fileDatavisualizer.importView.importPermissionError', {
|
||||
i18n.translate('xpack.fileDataVisualizer.importView.importPermissionError', {
|
||||
defaultMessage:
|
||||
'You do not have permission to create or import data into index {index}.',
|
||||
values: {
|
||||
|
@ -171,7 +169,7 @@ export class ImportView extends Component {
|
|||
} catch (error) {
|
||||
success = false;
|
||||
const parseError = i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.importView.parseSettingsError',
|
||||
'xpack.fileDataVisualizer.importView.parseSettingsError',
|
||||
{
|
||||
defaultMessage: 'Error parsing settings:',
|
||||
}
|
||||
|
@ -184,7 +182,7 @@ export class ImportView extends Component {
|
|||
} catch (error) {
|
||||
success = false;
|
||||
const parseError = i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.importView.parseMappingsError',
|
||||
'xpack.fileDataVisualizer.importView.parseMappingsError',
|
||||
{
|
||||
defaultMessage: 'Error parsing mappings:',
|
||||
}
|
||||
|
@ -199,7 +197,7 @@ export class ImportView extends Component {
|
|||
} catch (error) {
|
||||
success = false;
|
||||
const parseError = i18n.translate(
|
||||
'xpack.ml.fileDatavisualizer.importView.parsePipelineError',
|
||||
'xpack.fileDataVisualizer.importView.parsePipelineError',
|
||||
{
|
||||
defaultMessage: 'Error parsing ingest pipeline:',
|
||||
}
|
||||
|
@ -221,7 +219,7 @@ export class ImportView extends Component {
|
|||
}
|
||||
|
||||
if (success) {
|
||||
const importer = await getFileUpload().importerFactory(format, {
|
||||
const importer = await fileUpload.importerFactory(format, {
|
||||
excludeLinesPattern: results.exclude_lines_pattern,
|
||||
multilineStartPattern: results.multiline_start_pattern,
|
||||
});
|
||||
|
@ -294,8 +292,7 @@ export class ImportView extends Component {
|
|||
const indexPatternResp = await createKibanaIndexPattern(
|
||||
indexPatternName,
|
||||
indexPatterns,
|
||||
timeFieldName,
|
||||
kibanaConfig
|
||||
timeFieldName
|
||||
);
|
||||
success = indexPatternResp.success;
|
||||
this.setState({
|
||||
|
@ -354,16 +351,15 @@ export class ImportView extends Component {
|
|||
return;
|
||||
}
|
||||
|
||||
const { exists } = await ml.checkIndexExists({ index });
|
||||
const exists = await this.props.fileUpload.checkIndexExists(index);
|
||||
const indexNameError = exists ? (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importView.indexNameAlreadyExistsErrorMessage"
|
||||
id="xpack.fileDataVisualizer.importView.indexNameAlreadyExistsErrorMessage"
|
||||
defaultMessage="Index name already exists"
|
||||
/>
|
||||
) : (
|
||||
isIndexNameValid(index)
|
||||
);
|
||||
|
||||
this.setState({ checkingValidIndex: false, indexNameError });
|
||||
}, 500);
|
||||
|
||||
|
@ -427,9 +423,19 @@ export class ImportView extends Component {
|
|||
};
|
||||
|
||||
async loadIndexPatternNames() {
|
||||
await loadIndexPatterns(this.props.indexPatterns);
|
||||
const indexPatternNames = getIndexPatternNames();
|
||||
this.setState({ indexPatternNames });
|
||||
try {
|
||||
const indexPatternNames = (
|
||||
await this.savedObjectsClient.find({
|
||||
type: 'index-pattern',
|
||||
fields: ['title'],
|
||||
perPage: 10000,
|
||||
})
|
||||
).savedObjects.map(({ attributes }) => attributes && attributes.title);
|
||||
|
||||
this.setState({ indexPatternNames });
|
||||
} catch (error) {
|
||||
console.error('failed to load index patterns', error);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -501,14 +507,14 @@ export class ImportView extends Component {
|
|||
<EuiTitle size="s">
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importView.importDataTitle"
|
||||
id="xpack.fileDataVisualizer.importView.importDataTitle"
|
||||
defaultMessage="Import data"
|
||||
/>
|
||||
|
||||
<ExperimentalBadge
|
||||
tooltipContent={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importView.experimentalFeatureTooltip"
|
||||
id="xpack.fileDataVisualizer.importView.experimentalFeatureTooltip"
|
||||
defaultMessage="Experimental feature. We'd love to hear your feedback."
|
||||
/>
|
||||
}
|
||||
|
@ -549,7 +555,7 @@ export class ImportView extends Component {
|
|||
data-test-subj="mlFileDataVisImportButton"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importView.importButtonLabel"
|
||||
id="xpack.fileDataVisualizer.importView.importButtonLabel"
|
||||
defaultMessage="Import"
|
||||
/>
|
||||
</EuiButton>
|
||||
|
@ -558,7 +564,7 @@ export class ImportView extends Component {
|
|||
{initialized === true && importing === false && (
|
||||
<EuiButton onClick={this.clickReset}>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importView.resetButtonLabel"
|
||||
id="xpack.fileDataVisualizer.importView.resetButtonLabel"
|
||||
defaultMessage="Reset"
|
||||
/>
|
||||
</EuiButton>
|
||||
|
@ -690,7 +696,7 @@ function isIndexNameValid(name) {
|
|||
) {
|
||||
return (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importView.indexNameContainsIllegalCharactersErrorMessage"
|
||||
id="xpack.fileDataVisualizer.importView.indexNameContainsIllegalCharactersErrorMessage"
|
||||
defaultMessage="Index name contains illegal characters"
|
||||
/>
|
||||
);
|
||||
|
@ -707,7 +713,7 @@ function isIndexPatternNameValid(name, indexPatternNames, index) {
|
|||
if (indexPatternNames.find((i) => i === name)) {
|
||||
return (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importView.indexPatternNameAlreadyExistsErrorMessage"
|
||||
id="xpack.fileDataVisualizer.importView.indexPatternNameAlreadyExistsErrorMessage"
|
||||
defaultMessage="Index pattern name already exists"
|
||||
/>
|
||||
);
|
||||
|
@ -723,7 +729,7 @@ function isIndexPatternNameValid(name, indexPatternNames, index) {
|
|||
// name should match index
|
||||
return (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.importView.indexPatternDoesNotMatchIndexNameErrorMessage"
|
||||
id="xpack.fileDataVisualizer.importView.indexPatternDoesNotMatchIndexNameErrorMessage"
|
||||
defaultMessage="Index pattern does not match index name"
|
||||
/>
|
||||
);
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue