mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[ML] Add override for data which doesn't contain a time field (#147504)
Adds a checkbox to the overrides flyout to allow the user to tell the find structure endpoint that the data does not contain a time field.  If the original analysis of the data does not find a time field, this checkbox is unchecked by default. Closes https://github.com/elastic/kibana/issues/146700 Also removes the jest snapshot test for the override flyout as it isn't very useful.
This commit is contained in:
parent
5047b05b7c
commit
d14bf59730
5 changed files with 91 additions and 434 deletions
|
@ -19,6 +19,8 @@ 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';
|
||||
|
||||
export const NO_TIME_FORMAT = 'null';
|
||||
|
||||
// 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';
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import { isEqual } from 'lodash';
|
||||
import type { AnalysisResult, InputOverrides } from '@kbn/file-upload-plugin/common';
|
||||
import { MB, FILE_FORMATS } from '../../../../../common/constants';
|
||||
import { MB, FILE_FORMATS, NO_TIME_FORMAT } from '../../../../../common/constants';
|
||||
|
||||
export const DEFAULT_LINES_TO_SAMPLE = 1000;
|
||||
const UPLOAD_SIZE_MB = 5;
|
||||
|
@ -117,10 +117,15 @@ export function createUrlOverrides(overrides: InputOverrides, originalSettings:
|
|||
}
|
||||
|
||||
export function processResults({ results, overrides }: AnalysisResult) {
|
||||
const timestampFormat =
|
||||
results.java_timestamp_formats !== undefined && results.java_timestamp_formats.length
|
||||
? results.java_timestamp_formats[0]
|
||||
: undefined;
|
||||
let timestampFormat;
|
||||
if (
|
||||
(overrides && overrides.timestamp_format === NO_TIME_FORMAT) ||
|
||||
results.java_timestamp_formats === undefined
|
||||
) {
|
||||
timestampFormat = NO_TIME_FORMAT;
|
||||
} else if (results.java_timestamp_formats.length) {
|
||||
timestampFormat = results.java_timestamp_formats[0];
|
||||
}
|
||||
|
||||
const linesToSample =
|
||||
overrides !== undefined && overrides.lines_to_sample !== undefined
|
||||
|
|
|
@ -1,363 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Overrides render overrides 1`] = `
|
||||
<EuiForm>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
error="Value must be greater than 3 and less than or equal to 1000000"
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
isInvalid={false}
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Number of lines to sample"
|
||||
id="xpack.dataVisualizer.file.editFlyout.overrides.linesToSampleFormRowLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
labelType="label"
|
||||
>
|
||||
<EuiFieldNumber
|
||||
isInvalid={false}
|
||||
onChange={[Function]}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Data format"
|
||||
id="xpack.dataVisualizer.file.editFlyout.overrides.dataFormatFormRowLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
labelType="label"
|
||||
>
|
||||
<EuiComboBox
|
||||
async={false}
|
||||
compressed={false}
|
||||
fullWidth={false}
|
||||
isClearable={false}
|
||||
onChange={[Function]}
|
||||
options={
|
||||
Array [
|
||||
Object {
|
||||
"label": "delimited",
|
||||
},
|
||||
Object {
|
||||
"label": "ndjson",
|
||||
},
|
||||
Object {
|
||||
"label": "semi_structured_text",
|
||||
},
|
||||
]
|
||||
}
|
||||
selectedOptions={
|
||||
Array [
|
||||
Object {
|
||||
"label": "",
|
||||
},
|
||||
]
|
||||
}
|
||||
singleSelection={
|
||||
Object {
|
||||
"asPlainText": true,
|
||||
}
|
||||
}
|
||||
sortMatchesBy="none"
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
helpText={
|
||||
<EuiText
|
||||
size="xs"
|
||||
>
|
||||
<EuiLink
|
||||
href="jest-metadata-mock-url"
|
||||
target="_blank"
|
||||
>
|
||||
See more on accepted formats
|
||||
</EuiLink>
|
||||
</EuiText>
|
||||
}
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Timestamp format"
|
||||
id="xpack.dataVisualizer.file.editFlyout.overrides.timestampFormatFormRowLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
labelType="label"
|
||||
>
|
||||
<EuiComboBox
|
||||
async={false}
|
||||
compressed={false}
|
||||
fullWidth={false}
|
||||
isClearable={false}
|
||||
onChange={[Function]}
|
||||
options={
|
||||
Array [
|
||||
Object {
|
||||
"label": "custom",
|
||||
},
|
||||
Object {
|
||||
"label": "dd/MMM/yyyy:HH:mm:ss XX",
|
||||
},
|
||||
Object {
|
||||
"label": "EEE MMM dd HH:mm zzz yyyy",
|
||||
},
|
||||
Object {
|
||||
"label": "EEE MMM dd HH:mm:ss yyyy",
|
||||
},
|
||||
Object {
|
||||
"label": "EEE MMM dd HH:mm:ss zzz yyyy",
|
||||
},
|
||||
Object {
|
||||
"label": "EEE MMM dd yyyy HH:mm zzz",
|
||||
},
|
||||
Object {
|
||||
"label": "EEE MMM dd yyyy HH:mm:ss zzz",
|
||||
},
|
||||
Object {
|
||||
"label": "EEE, dd MMM yyyy HH:mm XX",
|
||||
},
|
||||
Object {
|
||||
"label": "EEE, dd MMM yyyy HH:mm XXX",
|
||||
},
|
||||
Object {
|
||||
"label": "EEE, dd MMM yyyy HH:mm:ss XX",
|
||||
},
|
||||
Object {
|
||||
"label": "EEE, dd MMM yyyy HH:mm:ss XXX",
|
||||
},
|
||||
Object {
|
||||
"label": "ISO8601",
|
||||
},
|
||||
Object {
|
||||
"label": "MMM dd HH:mm:ss",
|
||||
},
|
||||
Object {
|
||||
"label": "MMM dd HH:mm:ss,SSS",
|
||||
},
|
||||
Object {
|
||||
"label": "MMM dd HH:mm:ss,SSSSSS",
|
||||
},
|
||||
Object {
|
||||
"label": "MMM dd HH:mm:ss,SSSSSSSSS",
|
||||
},
|
||||
Object {
|
||||
"label": "MMM dd HH:mm:ss.SSS",
|
||||
},
|
||||
Object {
|
||||
"label": "MMM dd HH:mm:ss.SSSSSS",
|
||||
},
|
||||
Object {
|
||||
"label": "MMM dd HH:mm:ss.SSSSSSSSS",
|
||||
},
|
||||
Object {
|
||||
"label": "MMM dd HH:mm:ss:SSS",
|
||||
},
|
||||
Object {
|
||||
"label": "MMM dd HH:mm:ss:SSSSSS",
|
||||
},
|
||||
Object {
|
||||
"label": "MMM dd HH:mm:ss:SSSSSSSSS",
|
||||
},
|
||||
Object {
|
||||
"label": "MMM dd yyyy HH:mm:ss",
|
||||
},
|
||||
Object {
|
||||
"label": "MMM dd, yyyy h:mm:ss a",
|
||||
},
|
||||
Object {
|
||||
"label": "TAI64N",
|
||||
},
|
||||
Object {
|
||||
"label": "UNIX",
|
||||
},
|
||||
Object {
|
||||
"label": "UNIX_MS",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss,SSS",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss,SSSSSS",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss,SSSSSSSSS",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss.SSS",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss.SSSSSS",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss.SSSSSSSSS",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss:SSS",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss:SSSSSS",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss:SSSSSSSSS",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss,SSS XX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss,SSSSSS XX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss,SSSSSSSSS XX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss.SSS XX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss.SSSSSS XX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss.SSSSSSSSS XX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss:SSS XX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss:SSSSSS XX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss:SSSSSSSSS XX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss,SSSXX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss,SSSSSSXX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss,SSSSSSSSSXX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss.SSSXX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss.SSSSSSXX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss.SSSSSSSSSXX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss:SSSXX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss:SSSSSSXX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss:SSSSSSSSSXX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss,SSSXXX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss,SSSSSSXXX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss,SSSSSSSSSXXX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss.SSSXXX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss.SSSSSSXXX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss.SSSSSSSSSXXX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss:SSSXXX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss:SSSSSSXXX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ss:SSSSSSSSSXXX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ssXX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyy-MM-dd HH:mm:ssXXX",
|
||||
},
|
||||
Object {
|
||||
"label": "yyyyMMddHHmmss",
|
||||
},
|
||||
]
|
||||
}
|
||||
selectedOptions={
|
||||
Array [
|
||||
Object {
|
||||
"label": "",
|
||||
},
|
||||
]
|
||||
}
|
||||
singleSelection={
|
||||
Object {
|
||||
"asPlainText": true,
|
||||
}
|
||||
}
|
||||
sortMatchesBy="none"
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
describedByIds={Array []}
|
||||
display="row"
|
||||
hasChildLabel={true}
|
||||
hasEmptyLabelSpace={false}
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Time field"
|
||||
id="xpack.dataVisualizer.file.editFlyout.overrides.timeFieldFormRowLabel"
|
||||
values={Object {}}
|
||||
/>
|
||||
}
|
||||
labelType="label"
|
||||
>
|
||||
<EuiComboBox
|
||||
async={false}
|
||||
compressed={false}
|
||||
fullWidth={false}
|
||||
isClearable={false}
|
||||
onChange={[Function]}
|
||||
options={Array []}
|
||||
selectedOptions={
|
||||
Array [
|
||||
Object {
|
||||
"label": "",
|
||||
},
|
||||
]
|
||||
}
|
||||
singleSelection={
|
||||
Object {
|
||||
"asPlainText": true,
|
||||
}
|
||||
}
|
||||
sortMatchesBy="none"
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiForm>
|
||||
`;
|
|
@ -23,7 +23,7 @@ import {
|
|||
EuiTextArea,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { FILE_FORMATS } from '../../../../../common/constants';
|
||||
import { FILE_FORMATS, NO_TIME_FORMAT } from '../../../../../common/constants';
|
||||
|
||||
import {
|
||||
getFormatOptions,
|
||||
|
@ -129,6 +129,7 @@ class OverridesUI extends Component {
|
|||
linesToSampleValid: true,
|
||||
timestampFormatValid: true,
|
||||
timestampFormatError: null,
|
||||
containsTimeField: overrides.timestampFormat !== NO_TIME_FORMAT,
|
||||
overrides,
|
||||
...state,
|
||||
};
|
||||
|
@ -203,6 +204,17 @@ class OverridesUI extends Component {
|
|||
this.setOverride({ timestampField });
|
||||
};
|
||||
|
||||
onContainsTimeFieldChange = (e) => {
|
||||
this.setState({ containsTimeField: e.target.checked });
|
||||
if (e.target.checked === false) {
|
||||
this.setOverride({ timestampFormat: NO_TIME_FORMAT });
|
||||
} else {
|
||||
this.setOverride({
|
||||
timestampFormat: this.props.originalSettings.timestampFormat,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onDelimiterChange = ([opt]) => {
|
||||
const delimiter = opt ? opt.label : '';
|
||||
this.setOverride({ delimiter });
|
||||
|
@ -272,6 +284,7 @@ class OverridesUI extends Component {
|
|||
linesToSampleValid,
|
||||
timestampFormatError,
|
||||
timestampFormatValid,
|
||||
containsTimeField,
|
||||
overrides,
|
||||
} = this.state;
|
||||
|
||||
|
@ -437,69 +450,77 @@ class OverridesUI extends Component {
|
|||
</EuiFormRow>
|
||||
</React.Fragment>
|
||||
)}
|
||||
<EuiFormRow
|
||||
helpText={timestampFormatHelp}
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.dataVisualizer.file.editFlyout.overrides.timestampFormatFormRowLabel"
|
||||
defaultMessage="Timestamp format"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiComboBox
|
||||
options={timestampFormatOptions}
|
||||
selectedOptions={selectedOption(timestampFormat)}
|
||||
onChange={this.onTimestampFormatChange}
|
||||
singleSelection={{ asPlainText: true }}
|
||||
isClearable={false}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
{timestampFormat === CUSTOM_DROPDOWN_OPTION && (
|
||||
<EuiFormRow
|
||||
error={timestampFormatErrorsList}
|
||||
isInvalid={timestampFormatValid === false}
|
||||
|
||||
<EuiFormRow>
|
||||
<EuiCheckbox
|
||||
id={'shouldTrimFields'}
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.dataVisualizer.file.editFlyout.overrides.customTimestampFormatFormRowLabel"
|
||||
defaultMessage="Custom timestamp format"
|
||||
id="xpack.dataVisualizer.file.editFlyout.overrides.containsTimeFieldLabel"
|
||||
defaultMessage="Contains time field"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiFieldText
|
||||
value={customTimestampFormat}
|
||||
onChange={this.onCustomTimestampFormatChange}
|
||||
isInvalid={timestampFormatValid === false}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
)}
|
||||
|
||||
<EuiFormRow
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.dataVisualizer.file.editFlyout.overrides.timeFieldFormRowLabel"
|
||||
defaultMessage="Time field"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiComboBox
|
||||
options={fieldOptions}
|
||||
selectedOptions={selectedOption(timestampField)}
|
||||
onChange={this.onTimestampFieldChange}
|
||||
singleSelection={{ asPlainText: true }}
|
||||
isClearable={false}
|
||||
checked={containsTimeField}
|
||||
onChange={this.onContainsTimeFieldChange}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
||||
{/* <EuiFormRow
|
||||
label="Charset"
|
||||
>
|
||||
<EuiComboBox
|
||||
options={charsetOptions}
|
||||
selectedOptions={selectedOption(charset)}
|
||||
singleSelection={{ asPlainText: true }}
|
||||
isClearable={false}
|
||||
/>
|
||||
</EuiFormRow> */}
|
||||
{containsTimeField ? (
|
||||
<>
|
||||
<EuiFormRow
|
||||
helpText={timestampFormatHelp}
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.dataVisualizer.file.editFlyout.overrides.timestampFormatFormRowLabel"
|
||||
defaultMessage="Timestamp format"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiComboBox
|
||||
options={timestampFormatOptions}
|
||||
selectedOptions={selectedOption(timestampFormat)}
|
||||
onChange={this.onTimestampFormatChange}
|
||||
singleSelection={{ asPlainText: true }}
|
||||
isClearable={false}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
{timestampFormat === CUSTOM_DROPDOWN_OPTION && (
|
||||
<EuiFormRow
|
||||
error={timestampFormatErrorsList}
|
||||
isInvalid={timestampFormatValid === false}
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.dataVisualizer.file.editFlyout.overrides.customTimestampFormatFormRowLabel"
|
||||
defaultMessage="Custom timestamp format"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiFieldText
|
||||
value={customTimestampFormat}
|
||||
onChange={this.onCustomTimestampFormatChange}
|
||||
isInvalid={timestampFormatValid === false}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
)}
|
||||
<EuiFormRow
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.dataVisualizer.file.editFlyout.overrides.timeFieldFormRowLabel"
|
||||
defaultMessage="Time field"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiComboBox
|
||||
options={fieldOptions}
|
||||
selectedOptions={selectedOption(timestampField)}
|
||||
onChange={this.onTimestampFieldChange}
|
||||
singleSelection={{ asPlainText: true }}
|
||||
isClearable={false}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{format === FILE_FORMATS.DELIMITED && originalColumnNames.length > 0 && (
|
||||
<React.Fragment>
|
||||
<EuiSpacer />
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { mountWithIntl, shallowWithIntl } from '@kbn/test-jest-helpers';
|
||||
import { mountWithIntl } from '@kbn/test-jest-helpers';
|
||||
import React from 'react';
|
||||
import { FILE_FORMATS } from '../../../../../common/constants';
|
||||
|
||||
|
@ -40,14 +40,6 @@ function getProps() {
|
|||
}
|
||||
|
||||
describe('Overrides', () => {
|
||||
test('render overrides', () => {
|
||||
const props = getProps();
|
||||
|
||||
const component = shallowWithIntl(<Overrides {...props} />);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('render overrides and trigger a state change', () => {
|
||||
const FORMAT_1 = FILE_FORMATS.DELIMITED;
|
||||
const FORMAT_2 = FILE_FORMATS.NDJSON;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue