mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
This PR renames directories and variables of occurrences of job in the context of data frames to transform across the code.
This commit is contained in:
parent
630affedb9
commit
0344e92b16
158 changed files with 1602 additions and 1461 deletions
|
@ -29,11 +29,11 @@ export interface Privileges {
|
|||
// File Data Visualizer
|
||||
canFindFileStructure: boolean;
|
||||
// Data Frames
|
||||
canGetDataFrameJobs: boolean;
|
||||
canDeleteDataFrameJob: boolean;
|
||||
canPreviewDataFrameJob: boolean;
|
||||
canCreateDataFrameJob: boolean;
|
||||
canStartStopDataFrameJob: boolean;
|
||||
canGetDataFrame: boolean;
|
||||
canDeleteDataFrame: boolean;
|
||||
canPreviewDataFrame: boolean;
|
||||
canCreateDataFrame: boolean;
|
||||
canStartStopDataFrame: boolean;
|
||||
}
|
||||
|
||||
export function getDefaultPrivileges(): Privileges {
|
||||
|
@ -61,10 +61,10 @@ export function getDefaultPrivileges(): Privileges {
|
|||
// File Data Visualizer
|
||||
canFindFileStructure: false,
|
||||
// Data Frames
|
||||
canGetDataFrameJobs: false,
|
||||
canDeleteDataFrameJob: false,
|
||||
canPreviewDataFrameJob: false,
|
||||
canCreateDataFrameJob: false,
|
||||
canStartStopDataFrameJob: false,
|
||||
canGetDataFrame: false,
|
||||
canDeleteDataFrame: false,
|
||||
canPreviewDataFrame: false,
|
||||
canCreateDataFrame: false,
|
||||
canStartStopDataFrame: false,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
@import 'components/aggregation_list/index';
|
||||
@import 'components/group_by_list/index';
|
||||
@import 'pages/job_management/components/job_list/index';
|
||||
@import 'pages/data_frame_new_pivot/components/aggregation_list/index';
|
||||
@import 'pages/data_frame_new_pivot/components/group_by_list/index';
|
||||
@import 'pages/transform_management/components/transform_list/index';
|
||||
|
|
|
@ -4,4 +4,76 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export type FieldName = string;
|
||||
import { Dictionary } from '../../../common/types/common';
|
||||
|
||||
export type EsId = string;
|
||||
export type EsDocSource = Dictionary<any>;
|
||||
export type EsFieldName = string;
|
||||
|
||||
export interface EsDoc extends Dictionary<any> {
|
||||
_id: EsId;
|
||||
_source: EsDocSource;
|
||||
}
|
||||
|
||||
export const MAX_COLUMNS = 5;
|
||||
|
||||
export function getFlattenedFields(obj: EsDocSource): EsFieldName[] {
|
||||
const flatDocFields: EsFieldName[] = [];
|
||||
const newDocFields = Object.keys(obj);
|
||||
newDocFields.forEach(f => {
|
||||
const fieldValue = obj[f];
|
||||
if (typeof fieldValue !== 'object' || fieldValue === null || Array.isArray(fieldValue)) {
|
||||
flatDocFields.push(f);
|
||||
} else {
|
||||
const innerFields = getFlattenedFields(fieldValue);
|
||||
const flattenedFields = innerFields.map(d => `${f}.${d}`);
|
||||
flatDocFields.push(...flattenedFields);
|
||||
}
|
||||
});
|
||||
return flatDocFields;
|
||||
}
|
||||
|
||||
export const getSelectableFields = (docs: EsDoc[]): EsFieldName[] => {
|
||||
if (docs.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const newDocFields = getFlattenedFields(docs[0]._source);
|
||||
newDocFields.sort();
|
||||
return newDocFields;
|
||||
};
|
||||
|
||||
export const getDefaultSelectableFields = (docs: EsDoc[]): EsFieldName[] => {
|
||||
if (docs.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const newDocFields = getFlattenedFields(docs[0]._source);
|
||||
newDocFields.sort();
|
||||
return newDocFields
|
||||
.filter(k => {
|
||||
let value = false;
|
||||
docs.forEach(row => {
|
||||
const source = row._source;
|
||||
if (source[k] !== null) {
|
||||
value = true;
|
||||
}
|
||||
});
|
||||
return value;
|
||||
})
|
||||
.slice(0, MAX_COLUMNS);
|
||||
};
|
||||
|
||||
export const toggleSelectedField = (
|
||||
selectedFields: EsFieldName[],
|
||||
column: EsFieldName
|
||||
): EsFieldName[] => {
|
||||
const index = selectedFields.indexOf(column);
|
||||
if (index === -1) {
|
||||
selectedFields.push(column);
|
||||
} else {
|
||||
selectedFields.splice(index, 1);
|
||||
}
|
||||
selectedFields.sort();
|
||||
return selectedFields;
|
||||
};
|
||||
|
|
|
@ -4,12 +4,82 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export * from './aggregations';
|
||||
export * from './fields';
|
||||
export * from './dropdown';
|
||||
export * from './kibana_context';
|
||||
export * from './job';
|
||||
export * from './navigation';
|
||||
export * from './pivot_aggs';
|
||||
export * from './pivot_group_by';
|
||||
export * from './request';
|
||||
export { AggName, isAggName } from './aggregations';
|
||||
export {
|
||||
getDefaultSelectableFields,
|
||||
getFlattenedFields,
|
||||
getSelectableFields,
|
||||
toggleSelectedField,
|
||||
EsDoc,
|
||||
EsDocSource,
|
||||
EsFieldName,
|
||||
MAX_COLUMNS,
|
||||
} from './fields';
|
||||
export { DropDownLabel, DropDownOption, Label } from './dropdown';
|
||||
export {
|
||||
KibanaContext,
|
||||
KibanaContextValue,
|
||||
isKibanaContext,
|
||||
NullableKibanaContextValue,
|
||||
SavedSearchQuery,
|
||||
} from './kibana_context';
|
||||
export {
|
||||
isTransformIdValid,
|
||||
refreshTransformList$,
|
||||
useRefreshTransformList,
|
||||
CreateRequestBody,
|
||||
PreviewRequestBody,
|
||||
DataFrameTransformId,
|
||||
DataFrameTransformPivotConfig,
|
||||
delayFormatRegex,
|
||||
IndexName,
|
||||
IndexPattern,
|
||||
REFRESH_TRANSFORM_LIST_STATE,
|
||||
} from './transform';
|
||||
export { moveToDataFrameTransformList, moveToDataFrameWizard, moveToDiscover } from './navigation';
|
||||
export {
|
||||
getEsAggFromAggConfig,
|
||||
isPivotAggsConfigWithUiSupport,
|
||||
PivotAgg,
|
||||
PivotAggDict,
|
||||
PivotAggsConfig,
|
||||
PivotAggsConfigDict,
|
||||
PivotAggsConfigBase,
|
||||
PivotAggsConfigWithUiSupport,
|
||||
PivotAggsConfigWithUiSupportDict,
|
||||
pivotAggsFieldSupport,
|
||||
PIVOT_SUPPORTED_AGGS,
|
||||
} from './pivot_aggs';
|
||||
export {
|
||||
dateHistogramIntervalFormatRegex,
|
||||
getEsAggFromGroupByConfig,
|
||||
histogramIntervalFormatRegex,
|
||||
isPivotGroupByConfigWithUiSupport,
|
||||
isGroupByDateHistogram,
|
||||
isGroupByHistogram,
|
||||
isGroupByTerms,
|
||||
pivotGroupByFieldSupport,
|
||||
DateHistogramAgg,
|
||||
GenericAgg,
|
||||
GroupByConfigWithInterval,
|
||||
GroupByConfigWithUiSupport,
|
||||
HistogramAgg,
|
||||
PivotGroupBy,
|
||||
PivotGroupByConfig,
|
||||
PivotGroupByDict,
|
||||
PivotGroupByConfigDict,
|
||||
PivotGroupByConfigWithUiSupportDict,
|
||||
PivotSupportedGroupByAggs,
|
||||
PivotSupportedGroupByAggsWithInterval,
|
||||
PIVOT_SUPPORTED_GROUP_BY_AGGS,
|
||||
TermsAgg,
|
||||
} from './pivot_group_by';
|
||||
export {
|
||||
getPreviewRequestBody,
|
||||
getCreateRequestBody,
|
||||
getPivotQuery,
|
||||
isDefaultQuery,
|
||||
isSimpleQuery,
|
||||
PivotQuery,
|
||||
SimpleQuery,
|
||||
} from './request';
|
||||
|
|
|
@ -9,10 +9,10 @@ import rison from 'rison-node';
|
|||
import chrome from 'ui/chrome';
|
||||
|
||||
export function moveToDataFrameWizard() {
|
||||
window.location.href = '#/data_frames/new_job';
|
||||
window.location.href = '#/data_frames/new_transform';
|
||||
}
|
||||
|
||||
export function moveToDataFrameJobsList() {
|
||||
export function moveToDataFrameTransformList() {
|
||||
window.location.href = '#/data_frames';
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import { Dictionary } from '../../../common/types/common';
|
|||
import { KBN_FIELD_TYPES } from '../../../common/constants/field_types';
|
||||
|
||||
import { AggName } from './aggregations';
|
||||
import { FieldName } from './fields';
|
||||
import { EsFieldName } from './fields';
|
||||
|
||||
export enum PIVOT_SUPPORTED_AGGS {
|
||||
AVG = 'avg',
|
||||
|
@ -19,15 +19,6 @@ export enum PIVOT_SUPPORTED_AGGS {
|
|||
VALUE_COUNT = 'value_count',
|
||||
}
|
||||
|
||||
export const pivotSupportedAggs: PIVOT_SUPPORTED_AGGS[] = [
|
||||
PIVOT_SUPPORTED_AGGS.AVG,
|
||||
PIVOT_SUPPORTED_AGGS.CARDINALITY,
|
||||
PIVOT_SUPPORTED_AGGS.MAX,
|
||||
PIVOT_SUPPORTED_AGGS.MIN,
|
||||
PIVOT_SUPPORTED_AGGS.SUM,
|
||||
PIVOT_SUPPORTED_AGGS.VALUE_COUNT,
|
||||
];
|
||||
|
||||
export const pivotAggsFieldSupport = {
|
||||
[KBN_FIELD_TYPES.ATTACHMENT]: [PIVOT_SUPPORTED_AGGS.VALUE_COUNT],
|
||||
[KBN_FIELD_TYPES.BOOLEAN]: [PIVOT_SUPPORTED_AGGS.VALUE_COUNT],
|
||||
|
@ -56,7 +47,7 @@ export const pivotAggsFieldSupport = {
|
|||
|
||||
export type PivotAgg = {
|
||||
[key in PIVOT_SUPPORTED_AGGS]?: {
|
||||
field: FieldName;
|
||||
field: EsFieldName;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -70,7 +61,7 @@ export interface PivotAggsConfigBase {
|
|||
}
|
||||
|
||||
export interface PivotAggsConfigWithUiSupport extends PivotAggsConfigBase {
|
||||
field: FieldName;
|
||||
field: EsFieldName;
|
||||
}
|
||||
|
||||
export function isPivotAggsConfigWithUiSupport(arg: any): arg is PivotAggsConfigWithUiSupport {
|
||||
|
@ -79,7 +70,7 @@ export function isPivotAggsConfigWithUiSupport(arg: any): arg is PivotAggsConfig
|
|||
arg.hasOwnProperty('aggName') &&
|
||||
arg.hasOwnProperty('dropDownName') &&
|
||||
arg.hasOwnProperty('field') &&
|
||||
pivotSupportedAggs.includes(arg.agg)
|
||||
Object.values(PIVOT_SUPPORTED_AGGS).includes(arg.agg)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import { Dictionary } from '../../../common/types/common';
|
|||
import { KBN_FIELD_TYPES } from '../../../common/constants/field_types';
|
||||
|
||||
import { AggName } from './aggregations';
|
||||
import { FieldName } from './fields';
|
||||
import { EsFieldName } from './fields';
|
||||
|
||||
export enum PIVOT_SUPPORTED_GROUP_BY_AGGS {
|
||||
DATE_HISTOGRAM = 'date_histogram',
|
||||
|
@ -16,16 +16,7 @@ export enum PIVOT_SUPPORTED_GROUP_BY_AGGS {
|
|||
TERMS = 'terms',
|
||||
}
|
||||
|
||||
export type PivotSupportedGroupByAggs =
|
||||
| PIVOT_SUPPORTED_GROUP_BY_AGGS.DATE_HISTOGRAM
|
||||
| PIVOT_SUPPORTED_GROUP_BY_AGGS.HISTOGRAM
|
||||
| PIVOT_SUPPORTED_GROUP_BY_AGGS.TERMS;
|
||||
|
||||
export const pivotSupportedGroupByAggs: PivotSupportedGroupByAggs[] = [
|
||||
PIVOT_SUPPORTED_GROUP_BY_AGGS.DATE_HISTOGRAM,
|
||||
PIVOT_SUPPORTED_GROUP_BY_AGGS.HISTOGRAM,
|
||||
PIVOT_SUPPORTED_GROUP_BY_AGGS.TERMS,
|
||||
];
|
||||
export type PivotSupportedGroupByAggs = PIVOT_SUPPORTED_GROUP_BY_AGGS;
|
||||
|
||||
export type PivotSupportedGroupByAggsWithInterval =
|
||||
| PIVOT_SUPPORTED_GROUP_BY_AGGS.HISTOGRAM
|
||||
|
@ -59,19 +50,19 @@ export const dateHistogramIntervalFormatRegex = /^[1-9][0-9]*(ms|s|m|h|d|w|M|q|y
|
|||
|
||||
interface GroupByDateHistogram extends GroupByConfigBase {
|
||||
agg: PIVOT_SUPPORTED_GROUP_BY_AGGS.DATE_HISTOGRAM;
|
||||
field: FieldName;
|
||||
field: EsFieldName;
|
||||
calendar_interval: string;
|
||||
}
|
||||
|
||||
interface GroupByHistogram extends GroupByConfigBase {
|
||||
agg: PIVOT_SUPPORTED_GROUP_BY_AGGS.HISTOGRAM;
|
||||
field: FieldName;
|
||||
field: EsFieldName;
|
||||
interval: string;
|
||||
}
|
||||
|
||||
interface GroupByTerms extends GroupByConfigBase {
|
||||
agg: PIVOT_SUPPORTED_GROUP_BY_AGGS.TERMS;
|
||||
field: FieldName;
|
||||
field: EsFieldName;
|
||||
}
|
||||
|
||||
export type GroupByConfigWithInterval = GroupByDateHistogram | GroupByHistogram;
|
||||
|
@ -119,20 +110,20 @@ export type GenericAgg = object;
|
|||
|
||||
export interface TermsAgg {
|
||||
terms: {
|
||||
field: FieldName;
|
||||
field: EsFieldName;
|
||||
};
|
||||
}
|
||||
|
||||
export interface HistogramAgg {
|
||||
histogram: {
|
||||
field: FieldName;
|
||||
field: EsFieldName;
|
||||
interval: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface DateHistogramAgg {
|
||||
date_histogram: {
|
||||
field: FieldName;
|
||||
field: EsFieldName;
|
||||
calendar_interval: string;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
|
||||
import { PivotGroupByConfig } from '../common';
|
||||
|
||||
import { JobDetailsExposedState } from '../components/job_details/job_details_form';
|
||||
import { DefinePivotExposedState } from '../components/define_pivot/define_pivot_form';
|
||||
import { StepDefineExposedState } from '../pages/data_frame_new_pivot/components/step_define/step_define_form';
|
||||
import { StepDetailsExposedState } from '../pages/data_frame_new_pivot/components/step_details/step_details_form';
|
||||
|
||||
import { PIVOT_SUPPORTED_GROUP_BY_AGGS } from './pivot_group_by';
|
||||
import { PivotAggsConfig, PIVOT_SUPPORTED_AGGS } from './pivot_aggs';
|
||||
import {
|
||||
getDataFramePreviewRequest,
|
||||
getDataFrameRequest,
|
||||
getPreviewRequestBody,
|
||||
getCreateRequestBody,
|
||||
getPivotQuery,
|
||||
isDefaultQuery,
|
||||
isSimpleQuery,
|
||||
|
@ -48,7 +48,7 @@ describe('Data Frame: Common', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('getDataFramePreviewRequest()', () => {
|
||||
test('getPreviewRequestBody()', () => {
|
||||
const query = getPivotQuery('the-query');
|
||||
const groupBy: PivotGroupByConfig[] = [
|
||||
{
|
||||
|
@ -66,7 +66,7 @@ describe('Data Frame: Common', () => {
|
|||
dropDownName: 'the-agg-drop-down-name',
|
||||
},
|
||||
];
|
||||
const request = getDataFramePreviewRequest('the-index-pattern-title', query, groupBy, aggs);
|
||||
const request = getPreviewRequestBody('the-index-pattern-title', query, groupBy, aggs);
|
||||
|
||||
expect(request).toEqual({
|
||||
pivot: {
|
||||
|
@ -80,7 +80,7 @@ describe('Data Frame: Common', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('getDataFramePreviewRequest() with comma-separated index pattern', () => {
|
||||
test('getPreviewRequestBody() with comma-separated index pattern', () => {
|
||||
const query = getPivotQuery('the-query');
|
||||
const groupBy: PivotGroupByConfig[] = [
|
||||
{
|
||||
|
@ -98,7 +98,7 @@ describe('Data Frame: Common', () => {
|
|||
dropDownName: 'the-agg-drop-down-name',
|
||||
},
|
||||
];
|
||||
const request = getDataFramePreviewRequest(
|
||||
const request = getPreviewRequestBody(
|
||||
'the-index-pattern-title,the-other-title',
|
||||
query,
|
||||
groupBy,
|
||||
|
@ -117,7 +117,7 @@ describe('Data Frame: Common', () => {
|
|||
});
|
||||
});
|
||||
|
||||
test('getDataFrameRequest()', () => {
|
||||
test('getCreateRequestBody()', () => {
|
||||
const groupBy: PivotGroupByConfig = {
|
||||
agg: PIVOT_SUPPORTED_GROUP_BY_AGGS.TERMS,
|
||||
field: 'the-group-by-field',
|
||||
|
@ -130,29 +130,33 @@ describe('Data Frame: Common', () => {
|
|||
aggName: 'the-agg-agg-name',
|
||||
dropDownName: 'the-agg-drop-down-name',
|
||||
};
|
||||
const pivotState: DefinePivotExposedState = {
|
||||
const pivotState: StepDefineExposedState = {
|
||||
aggList: { 'the-agg-name': agg },
|
||||
groupByList: { 'the-group-by-name': groupBy },
|
||||
isAdvancedEditorEnabled: false,
|
||||
search: 'the-query',
|
||||
valid: true,
|
||||
};
|
||||
const jobDetailsState: JobDetailsExposedState = {
|
||||
const transformDetailsState: StepDetailsExposedState = {
|
||||
continuousModeDateField: 'the-continuous-mode-date-field',
|
||||
continuousModeDelay: 'the-continuous-mode-delay',
|
||||
createIndexPattern: false,
|
||||
isContinuousModeEnabled: false,
|
||||
jobId: 'the-job-id',
|
||||
jobDescription: 'the-job-description',
|
||||
transformId: 'the-transform-id',
|
||||
transformDescription: 'the-transform-description',
|
||||
destinationIndex: 'the-destination-index',
|
||||
touched: true,
|
||||
valid: true,
|
||||
};
|
||||
|
||||
const request = getDataFrameRequest('the-index-pattern-title', pivotState, jobDetailsState);
|
||||
const request = getCreateRequestBody(
|
||||
'the-index-pattern-title',
|
||||
pivotState,
|
||||
transformDetailsState
|
||||
);
|
||||
|
||||
expect(request).toEqual({
|
||||
description: 'the-job-description',
|
||||
description: 'the-transform-description',
|
||||
dest: { index: 'the-destination-index' },
|
||||
pivot: {
|
||||
aggregations: { 'the-agg-agg-name': { avg: { field: 'the-agg-field' } } },
|
||||
|
|
|
@ -10,8 +10,8 @@ import { IndexPattern } from 'ui/index_patterns';
|
|||
|
||||
import { dictionaryToArray } from '../../../common/types/common';
|
||||
|
||||
import { DefinePivotExposedState } from '../components/define_pivot/define_pivot_form';
|
||||
import { JobDetailsExposedState } from '../components/job_details/job_details_form';
|
||||
import { StepDefineExposedState } from '../pages/data_frame_new_pivot/components/step_define/step_define_form';
|
||||
import { StepDetailsExposedState } from '../pages/data_frame_new_pivot/components/step_details/step_details_form';
|
||||
|
||||
import {
|
||||
getEsAggFromAggConfig,
|
||||
|
@ -22,31 +22,10 @@ import {
|
|||
PivotGroupByConfig,
|
||||
} from '../common';
|
||||
|
||||
import { PivotAggDict, PivotAggsConfig } from './pivot_aggs';
|
||||
import { DateHistogramAgg, HistogramAgg, PivotGroupByDict, TermsAgg } from './pivot_group_by';
|
||||
import { PivotAggsConfig } from './pivot_aggs';
|
||||
import { DateHistogramAgg, HistogramAgg, TermsAgg } from './pivot_group_by';
|
||||
import { SavedSearchQuery } from './kibana_context';
|
||||
import { IndexPattern as Index } from './job';
|
||||
|
||||
export interface DataFramePreviewRequest {
|
||||
pivot: {
|
||||
group_by: PivotGroupByDict;
|
||||
aggregations: PivotAggDict;
|
||||
};
|
||||
source: {
|
||||
index: Index | Index[];
|
||||
query?: any;
|
||||
};
|
||||
}
|
||||
|
||||
export interface DataFrameRequest extends DataFramePreviewRequest {
|
||||
dest: {
|
||||
index: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface DataFrameJobConfig extends DataFrameRequest {
|
||||
id: string;
|
||||
}
|
||||
import { PreviewRequestBody, CreateRequestBody } from './transform';
|
||||
|
||||
export interface SimpleQuery {
|
||||
query_string: {
|
||||
|
@ -78,15 +57,15 @@ export function isDefaultQuery(query: PivotQuery): boolean {
|
|||
return isSimpleQuery(query) && query.query_string.query === '*';
|
||||
}
|
||||
|
||||
export function getDataFramePreviewRequest(
|
||||
export function getPreviewRequestBody(
|
||||
indexPatternTitle: IndexPattern['title'],
|
||||
query: PivotQuery,
|
||||
groupBy: PivotGroupByConfig[],
|
||||
aggs: PivotAggsConfig[]
|
||||
): DataFramePreviewRequest {
|
||||
): PreviewRequestBody {
|
||||
const index = indexPatternTitle.split(',').map((name: string) => name.trim());
|
||||
|
||||
const request: DataFramePreviewRequest = {
|
||||
const request: PreviewRequestBody = {
|
||||
source: {
|
||||
index,
|
||||
},
|
||||
|
@ -136,32 +115,32 @@ export function getDataFramePreviewRequest(
|
|||
return request;
|
||||
}
|
||||
|
||||
export function getDataFrameRequest(
|
||||
export function getCreateRequestBody(
|
||||
indexPatternTitle: IndexPattern['title'],
|
||||
pivotState: DefinePivotExposedState,
|
||||
jobDetailsState: JobDetailsExposedState
|
||||
): DataFrameRequest {
|
||||
const request: DataFrameRequest = {
|
||||
...getDataFramePreviewRequest(
|
||||
pivotState: StepDefineExposedState,
|
||||
transformDetailsState: StepDetailsExposedState
|
||||
): CreateRequestBody {
|
||||
const request: CreateRequestBody = {
|
||||
...getPreviewRequestBody(
|
||||
indexPatternTitle,
|
||||
getPivotQuery(pivotState.search),
|
||||
dictionaryToArray(pivotState.groupByList),
|
||||
dictionaryToArray(pivotState.aggList)
|
||||
),
|
||||
// conditionally add optional description
|
||||
...(jobDetailsState.jobDescription !== ''
|
||||
? { description: jobDetailsState.jobDescription }
|
||||
...(transformDetailsState.transformDescription !== ''
|
||||
? { description: transformDetailsState.transformDescription }
|
||||
: {}),
|
||||
dest: {
|
||||
index: jobDetailsState.destinationIndex,
|
||||
index: transformDetailsState.destinationIndex,
|
||||
},
|
||||
// conditionally add continuous mode config
|
||||
...(jobDetailsState.isContinuousModeEnabled
|
||||
...(transformDetailsState.isContinuousModeEnabled
|
||||
? {
|
||||
sync: {
|
||||
time: {
|
||||
field: jobDetailsState.continuousModeDateField,
|
||||
delay: jobDetailsState.continuousModeDelay,
|
||||
field: transformDetailsState.continuousModeDateField,
|
||||
delay: transformDetailsState.continuousModeDelay,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -9,20 +9,33 @@ import { BehaviorSubject } from 'rxjs';
|
|||
import { filter, distinctUntilChanged } from 'rxjs/operators';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
// @ts-ignore
|
||||
import { isJobIdValid } from '../../../common/util/job_utils';
|
||||
|
||||
import { PivotAggDict } from './pivot_aggs';
|
||||
import { PivotGroupByDict } from './pivot_group_by';
|
||||
|
||||
export const isTransformIdValid = isJobIdValid;
|
||||
|
||||
export type IndexName = string;
|
||||
export type IndexPattern = string;
|
||||
export type JobId = string;
|
||||
export type DataFrameTransformId = string;
|
||||
|
||||
export interface DataFrameJob {
|
||||
description?: string;
|
||||
dest: {
|
||||
index: IndexName;
|
||||
export interface PreviewRequestBody {
|
||||
pivot: {
|
||||
group_by: PivotGroupByDict;
|
||||
aggregations: PivotAggDict;
|
||||
};
|
||||
source: {
|
||||
index: IndexPattern | IndexPattern[];
|
||||
query?: any;
|
||||
};
|
||||
}
|
||||
|
||||
export interface CreateRequestBody extends PreviewRequestBody {
|
||||
description?: string;
|
||||
dest: {
|
||||
index: IndexName;
|
||||
};
|
||||
sync?: {
|
||||
time: {
|
||||
|
@ -32,15 +45,8 @@ export interface DataFrameJob {
|
|||
};
|
||||
}
|
||||
|
||||
export interface DataFrameTransform extends DataFrameJob {
|
||||
pivot: {
|
||||
aggregations: PivotAggDict;
|
||||
group_by: PivotGroupByDict;
|
||||
};
|
||||
}
|
||||
|
||||
export interface DataFrameTransformWithId extends DataFrameTransform {
|
||||
id: string;
|
||||
export interface DataFrameTransformPivotConfig extends CreateRequestBody {
|
||||
id: DataFrameTransformId;
|
||||
}
|
||||
|
||||
// Don't allow intervals of '0', don't allow floating intervals.
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { Dictionary } from '../../../../common/types/common';
|
||||
|
||||
import { PivotQuery } from '../../common';
|
||||
|
||||
export type EsFieldName = string;
|
||||
|
||||
type EsId = string;
|
||||
type EsDocSource = Dictionary<any>;
|
||||
|
||||
export interface EsDoc extends Dictionary<any> {
|
||||
_id: EsId;
|
||||
_source: EsDocSource;
|
||||
}
|
||||
|
||||
export const MAX_COLUMNS = 5;
|
||||
|
||||
export function getFlattenedFields(obj: EsDocSource): EsFieldName[] {
|
||||
const flatDocFields: EsFieldName[] = [];
|
||||
const newDocFields = Object.keys(obj);
|
||||
newDocFields.forEach(f => {
|
||||
const fieldValue = obj[f];
|
||||
if (typeof fieldValue !== 'object' || fieldValue === null || Array.isArray(fieldValue)) {
|
||||
flatDocFields.push(f);
|
||||
} else {
|
||||
const innerFields = getFlattenedFields(fieldValue);
|
||||
const flattenedFields = innerFields.map(d => `${f}.${d}`);
|
||||
flatDocFields.push(...flattenedFields);
|
||||
}
|
||||
});
|
||||
return flatDocFields;
|
||||
}
|
||||
|
||||
export const getSelectableFields = (docs: EsDoc[]): EsFieldName[] => {
|
||||
if (docs.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const newDocFields = getFlattenedFields(docs[0]._source);
|
||||
newDocFields.sort();
|
||||
return newDocFields;
|
||||
};
|
||||
|
||||
export const getDefaultSelectableFields = (docs: EsDoc[]): EsFieldName[] => {
|
||||
if (docs.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const newDocFields = getFlattenedFields(docs[0]._source);
|
||||
newDocFields.sort();
|
||||
return newDocFields
|
||||
.filter(k => {
|
||||
let value = false;
|
||||
docs.forEach(row => {
|
||||
const source = row._source;
|
||||
if (source[k] !== null) {
|
||||
value = true;
|
||||
}
|
||||
});
|
||||
return value;
|
||||
})
|
||||
.slice(0, MAX_COLUMNS);
|
||||
};
|
||||
|
||||
export const toggleSelectedField = (
|
||||
selectedFields: EsFieldName[],
|
||||
column: EsFieldName
|
||||
): EsFieldName[] => {
|
||||
const index = selectedFields.indexOf(column);
|
||||
if (index === -1) {
|
||||
selectedFields.push(column);
|
||||
} else {
|
||||
selectedFields.splice(index, 1);
|
||||
}
|
||||
selectedFields.sort();
|
||||
return selectedFields;
|
||||
};
|
||||
|
||||
export const getSourceIndexDevConsoleStatement = (query: PivotQuery, indexPatternTitle: string) => {
|
||||
return `GET ${indexPatternTitle}/_search\n${JSON.stringify(
|
||||
{
|
||||
query,
|
||||
},
|
||||
null,
|
||||
2
|
||||
)}\n`;
|
||||
};
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import './pages/access_denied/directive';
|
||||
import './pages/access_denied/route';
|
||||
import './pages/job_management/directive';
|
||||
import './pages/job_management/route';
|
||||
import './pages/transform_management/directive';
|
||||
import './pages/transform_management/route';
|
||||
import './pages/data_frame_new_pivot/directive';
|
||||
import './pages/data_frame_new_pivot/route';
|
||||
|
|
|
@ -4,4 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { DataFrameJobList } from './job_list';
|
||||
export { DropDown } from './dropdown';
|
|
@ -7,7 +7,7 @@
|
|||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
|
||||
import { AggName, PivotAggsConfig, PIVOT_SUPPORTED_AGGS } from '../../common';
|
||||
import { AggName, PivotAggsConfig, PIVOT_SUPPORTED_AGGS } from '../../../../common';
|
||||
|
||||
import { AggLabelForm } from './agg_label_form';
|
||||
|
|
@ -10,7 +10,7 @@ import { i18n } from '@kbn/i18n';
|
|||
|
||||
import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiPopover } from '@elastic/eui';
|
||||
|
||||
import { AggName, PivotAggsConfig, PivotAggsConfigWithUiSupportDict } from '../../common';
|
||||
import { AggName, PivotAggsConfig, PivotAggsConfigWithUiSupportDict } from '../../../../common';
|
||||
|
||||
import { PopoverForm } from './popover_form';
|
||||
|
|
@ -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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { AggListForm, AggListProps } from './list_form';
|
||||
export { AggListSummary, AggListSummaryProps } from './list_summary';
|
|
@ -7,9 +7,9 @@
|
|||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
|
||||
import { PivotAggsConfig, PIVOT_SUPPORTED_AGGS } from '../../common';
|
||||
import { PivotAggsConfig, PIVOT_SUPPORTED_AGGS } from '../../../../common';
|
||||
|
||||
import { AggListForm, ListProps } from './list_form';
|
||||
import { AggListForm, AggListProps } from './list_form';
|
||||
|
||||
describe('Data Frame: <AggListForm />', () => {
|
||||
test('Minimal initialization', () => {
|
||||
|
@ -19,7 +19,7 @@ describe('Data Frame: <AggListForm />', () => {
|
|||
aggName: 'the-group-by-agg-name',
|
||||
dropDownName: 'the-group-by-drop-down-name',
|
||||
};
|
||||
const props: ListProps = {
|
||||
const props: AggListProps = {
|
||||
list: { 'the-agg': item },
|
||||
options: {},
|
||||
deleteHandler() {},
|
|
@ -13,18 +13,23 @@ import {
|
|||
PivotAggsConfig,
|
||||
PivotAggsConfigDict,
|
||||
PivotAggsConfigWithUiSupportDict,
|
||||
} from '../../common';
|
||||
} from '../../../../common';
|
||||
|
||||
import { AggLabelForm } from './agg_label_form';
|
||||
|
||||
export interface ListProps {
|
||||
export interface AggListProps {
|
||||
list: PivotAggsConfigDict;
|
||||
options: PivotAggsConfigWithUiSupportDict;
|
||||
deleteHandler(l: string): void;
|
||||
onChange(previousAggName: AggName, item: PivotAggsConfig): void;
|
||||
}
|
||||
|
||||
export const AggListForm: React.SFC<ListProps> = ({ deleteHandler, list, onChange, options }) => {
|
||||
export const AggListForm: React.SFC<AggListProps> = ({
|
||||
deleteHandler,
|
||||
list,
|
||||
onChange,
|
||||
options,
|
||||
}) => {
|
||||
const listKeys = Object.keys(list);
|
||||
return (
|
||||
<Fragment>
|
|
@ -7,7 +7,7 @@
|
|||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
|
||||
import { PivotAggsConfig, PIVOT_SUPPORTED_AGGS } from '../../common';
|
||||
import { PivotAggsConfig, PIVOT_SUPPORTED_AGGS } from '../../../../common';
|
||||
|
||||
import { AggListSummary, AggListSummaryProps } from './list_summary';
|
||||
|
|
@ -8,7 +8,7 @@ import React, { Fragment } from 'react';
|
|||
|
||||
import { EuiForm, EuiPanel, EuiSpacer } from '@elastic/eui';
|
||||
|
||||
import { AggName, PivotAggsConfigDict } from '../../common';
|
||||
import { AggName, PivotAggsConfigDict } from '../../../../common';
|
||||
|
||||
export interface AggListSummaryProps {
|
||||
list: PivotAggsConfigDict;
|
|
@ -7,7 +7,7 @@
|
|||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
|
||||
import { AggName, PIVOT_SUPPORTED_AGGS, PivotAggsConfig } from '../../common';
|
||||
import { AggName, PIVOT_SUPPORTED_AGGS, PivotAggsConfig } from '../../../../common';
|
||||
|
||||
import { PopoverForm } from './popover_form';
|
||||
|
|
@ -17,7 +17,7 @@ import {
|
|||
EuiSelect,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { dictionaryToArray } from '../../../../common/types/common';
|
||||
import { dictionaryToArray } from '../../../../../../common/types/common';
|
||||
|
||||
import {
|
||||
AggName,
|
||||
|
@ -27,7 +27,7 @@ import {
|
|||
PivotAggsConfig,
|
||||
PivotAggsConfigWithUiSupportDict,
|
||||
PIVOT_SUPPORTED_AGGS,
|
||||
} from '../../common';
|
||||
} from '../../../../common';
|
||||
|
||||
interface SelectOption {
|
||||
text: string;
|
|
@ -7,7 +7,7 @@
|
|||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
|
||||
import { PivotGroupByConfig, PIVOT_SUPPORTED_GROUP_BY_AGGS } from '../../common';
|
||||
import { PivotGroupByConfig, PIVOT_SUPPORTED_GROUP_BY_AGGS } from '../../../../common';
|
||||
|
||||
import { GroupByLabelForm } from './group_by_label_form';
|
||||
|
|
@ -16,7 +16,7 @@ import {
|
|||
isGroupByHistogram,
|
||||
PivotGroupByConfig,
|
||||
PivotGroupByConfigWithUiSupportDict,
|
||||
} from '../../common';
|
||||
} from '../../../../common';
|
||||
|
||||
import { PopoverForm } from './popover_form';
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
|
||||
import { PivotGroupByConfig, PIVOT_SUPPORTED_GROUP_BY_AGGS } from '../../common';
|
||||
import { PivotGroupByConfig, PIVOT_SUPPORTED_GROUP_BY_AGGS } from '../../../../common';
|
||||
|
||||
import { GroupByLabelSummary } from './group_by_label_summary';
|
||||
|
|
@ -8,7 +8,7 @@ import React from 'react';
|
|||
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiTextColor } from '@elastic/eui';
|
||||
|
||||
import { isGroupByDateHistogram, isGroupByHistogram, PivotGroupByConfig } from '../../common';
|
||||
import { isGroupByDateHistogram, isGroupByHistogram, PivotGroupByConfig } from '../../../../common';
|
||||
|
||||
interface Props {
|
||||
item: PivotGroupByConfig;
|
|
@ -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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { GroupByListForm } from './list_form';
|
||||
export { GroupByListSummary } from './list_summary';
|
|
@ -7,7 +7,7 @@
|
|||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
|
||||
import { PivotGroupByConfig, PIVOT_SUPPORTED_GROUP_BY_AGGS } from '../../common';
|
||||
import { PivotGroupByConfig, PIVOT_SUPPORTED_GROUP_BY_AGGS } from '../../../../common';
|
||||
|
||||
import { GroupByListForm } from './list_form';
|
||||
|
|
@ -13,7 +13,7 @@ import {
|
|||
PivotGroupByConfig,
|
||||
PivotGroupByConfigDict,
|
||||
PivotGroupByConfigWithUiSupportDict,
|
||||
} from '../../common';
|
||||
} from '../../../../common';
|
||||
|
||||
import { GroupByLabelForm } from './group_by_label_form';
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
|
||||
import { PivotGroupByConfig, PIVOT_SUPPORTED_GROUP_BY_AGGS } from '../../common';
|
||||
import { PivotGroupByConfig, PIVOT_SUPPORTED_GROUP_BY_AGGS } from '../../../../common';
|
||||
|
||||
import { GroupByListSummary } from './list_summary';
|
||||
|
|
@ -8,7 +8,7 @@ import React, { Fragment } from 'react';
|
|||
|
||||
import { EuiPanel, EuiSpacer } from '@elastic/eui';
|
||||
|
||||
import { PivotGroupByConfigDict } from '../../common';
|
||||
import { PivotGroupByConfigDict } from '../../../../common';
|
||||
|
||||
import { GroupByLabelSummary } from './group_by_label_summary';
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
|
||||
import { AggName, PIVOT_SUPPORTED_GROUP_BY_AGGS, PivotGroupByConfig } from '../../common';
|
||||
import { AggName, PIVOT_SUPPORTED_GROUP_BY_AGGS, PivotGroupByConfig } from '../../../../common';
|
||||
|
||||
import { isIntervalValid, PopoverForm } from './popover_form';
|
||||
|
|
@ -17,7 +17,7 @@ import {
|
|||
EuiSelect,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { dictionaryToArray } from '../../../../common/types/common';
|
||||
import { dictionaryToArray } from '../../../../../../common/types/common';
|
||||
|
||||
import {
|
||||
AggName,
|
||||
|
@ -33,7 +33,7 @@ import {
|
|||
PivotSupportedGroupByAggs,
|
||||
PivotSupportedGroupByAggsWithInterval,
|
||||
PIVOT_SUPPORTED_GROUP_BY_AGGS,
|
||||
} from '../../common';
|
||||
} from '../../../../common';
|
||||
|
||||
export function isIntervalValid(
|
||||
interval: optionalInterval,
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { SimpleQuery } from '../../common';
|
||||
import { SimpleQuery } from '../../../../common';
|
||||
|
||||
import { getSourceIndexDevConsoleStatement } from './common';
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { PivotQuery } from '../../../../common';
|
||||
|
||||
export const getSourceIndexDevConsoleStatement = (query: PivotQuery, indexPatternTitle: string) => {
|
||||
return `GET ${indexPatternTitle}/_search\n${JSON.stringify(
|
||||
{
|
||||
query,
|
||||
},
|
||||
null,
|
||||
2
|
||||
)}\n`;
|
||||
};
|
|
@ -10,9 +10,7 @@ import React from 'react';
|
|||
|
||||
import { EuiBadge, EuiText } from '@elastic/eui';
|
||||
|
||||
import { EsDoc } from './common';
|
||||
|
||||
import { getSelectableFields } from './common';
|
||||
import { getSelectableFields, EsDoc } from '../../../../common';
|
||||
|
||||
interface ExpandedRowProps {
|
||||
item: EsDoc;
|
|
@ -7,7 +7,7 @@
|
|||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
|
||||
import { getPivotQuery, KibanaContext } from '../../common';
|
||||
import { getPivotQuery, KibanaContext } from '../../../../common';
|
||||
|
||||
import { SourceIndexPreview } from './source_index_preview';
|
||||
|
|
@ -39,19 +39,21 @@ interface ExpandableTableProps extends EuiInMemoryTableProps {
|
|||
|
||||
const ExpandableTable = (EuiInMemoryTable as any) as FunctionComponent<ExpandableTableProps>;
|
||||
|
||||
import { KBN_FIELD_TYPES } from '../../../../common/constants/field_types';
|
||||
import { Dictionary } from '../../../../common/types/common';
|
||||
import { formatHumanReadableDateTimeSeconds } from '../../../util/date_utils';
|
||||
|
||||
import { isKibanaContext, KibanaContext, PivotQuery } from '../../common';
|
||||
import { KBN_FIELD_TYPES } from '../../../../../../common/constants/field_types';
|
||||
import { Dictionary } from '../../../../../../common/types/common';
|
||||
import { formatHumanReadableDateTimeSeconds } from '../../../../../util/date_utils';
|
||||
|
||||
import {
|
||||
isKibanaContext,
|
||||
toggleSelectedField,
|
||||
EsDoc,
|
||||
EsFieldName,
|
||||
getSourceIndexDevConsoleStatement,
|
||||
MAX_COLUMNS,
|
||||
toggleSelectedField,
|
||||
} from './common';
|
||||
KibanaContext,
|
||||
PivotQuery,
|
||||
} from '../../../../common';
|
||||
|
||||
import { getSourceIndexDevConsoleStatement } from './common';
|
||||
import { ExpandedRow } from './expanded_row';
|
||||
import { SOURCE_INDEX_STATUS, useSourceIndexData } from './use_source_index_data';
|
||||
|
|
@ -8,15 +8,15 @@ import React, { SFC } from 'react';
|
|||
import ReactDOM from 'react-dom';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
|
||||
import { ml } from '../../../services/ml_api_service';
|
||||
import { SimpleQuery } from '../../common';
|
||||
import { ml } from '../../../../../services/ml_api_service';
|
||||
import { SimpleQuery } from '../../../../common';
|
||||
import {
|
||||
SOURCE_INDEX_STATUS,
|
||||
useSourceIndexData,
|
||||
UseSourceIndexDataReturnType,
|
||||
} from './use_source_index_data';
|
||||
|
||||
jest.mock('../../../services/ml_api_service');
|
||||
jest.mock('../../../../../services/ml_api_service');
|
||||
|
||||
type Callback = () => void;
|
||||
interface TestHookProps {
|
|
@ -12,10 +12,16 @@ import { SearchResponse } from 'elasticsearch';
|
|||
|
||||
import { IndexPattern } from 'ui/index_patterns';
|
||||
|
||||
import { ml } from '../../../services/ml_api_service';
|
||||
import { ml } from '../../../../../services/ml_api_service';
|
||||
|
||||
import { isDefaultQuery, PivotQuery } from '../../common';
|
||||
import { EsDoc, EsFieldName, getDefaultSelectableFields, getFlattenedFields } from './common';
|
||||
import {
|
||||
getDefaultSelectableFields,
|
||||
getFlattenedFields,
|
||||
isDefaultQuery,
|
||||
EsDoc,
|
||||
EsFieldName,
|
||||
PivotQuery,
|
||||
} from '../../../../common';
|
||||
|
||||
const SEARCH_SIZE = 1000;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Data Frame: <JobCreateForm /> Minimal initialization 1`] = `
|
||||
exports[`Data Frame: <StepCreateForm /> Minimal initialization 1`] = `
|
||||
<div>
|
||||
<ContextProvider
|
||||
value={
|
||||
|
@ -20,8 +20,6 @@ exports[`Data Frame: <JobCreateForm /> Minimal initialization 1`] = `
|
|||
>
|
||||
<Component
|
||||
createIndexPattern={false}
|
||||
jobConfig={Object {}}
|
||||
jobId="the-job-id"
|
||||
onChange={[Function]}
|
||||
overrides={
|
||||
Object {
|
||||
|
@ -30,6 +28,8 @@ exports[`Data Frame: <JobCreateForm /> Minimal initialization 1`] = `
|
|||
"started": false,
|
||||
}
|
||||
}
|
||||
transformConfig={Object {}}
|
||||
transformId="the-transform-id"
|
||||
/>
|
||||
</ContextProvider>
|
||||
</div>
|
|
@ -4,6 +4,5 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { JobCreateForm, getDefaultJobCreateState } from './job_create_form';
|
||||
|
||||
export { JobCreateSummary } from './job_create_summary';
|
||||
export { StepCreateForm, getDefaultStepCreateState } from './step_create_form';
|
||||
export { StepCreateSummary } from './step_create_summary';
|
|
@ -7,9 +7,9 @@
|
|||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
|
||||
import { KibanaContext } from '../../common';
|
||||
import { KibanaContext } from '../../../../common';
|
||||
|
||||
import { JobCreateForm } from './job_create_form';
|
||||
import { StepCreateForm } from './step_create_form';
|
||||
|
||||
// workaround to make React.memo() work with enzyme
|
||||
jest.mock('react', () => {
|
||||
|
@ -17,12 +17,12 @@ jest.mock('react', () => {
|
|||
return { ...r, memo: (x: any) => x };
|
||||
});
|
||||
|
||||
describe('Data Frame: <JobCreateForm />', () => {
|
||||
describe('Data Frame: <StepCreateForm />', () => {
|
||||
test('Minimal initialization', () => {
|
||||
const props = {
|
||||
createIndexPattern: false,
|
||||
jobId: 'the-job-id',
|
||||
jobConfig: {},
|
||||
transformId: 'the-transform-id',
|
||||
transformConfig: {},
|
||||
overrides: { created: false, started: false, indexPatternId: undefined },
|
||||
onChange() {},
|
||||
};
|
||||
|
@ -47,7 +47,7 @@ describe('Data Frame: <JobCreateForm />', () => {
|
|||
kibanaConfig: {},
|
||||
}}
|
||||
>
|
||||
<JobCreateForm {...props} />
|
||||
<StepCreateForm {...props} />
|
||||
</KibanaContext.Provider>
|
||||
</div>
|
||||
);
|
|
@ -29,20 +29,23 @@ import {
|
|||
EuiText,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { ml } from '../../../services/ml_api_service';
|
||||
import { PROGRESS_JOBS_REFRESH_INTERVAL_MS } from '../../../../common/constants/jobs_list';
|
||||
import { ml } from '../../../../../services/ml_api_service';
|
||||
import { PROGRESS_JOBS_REFRESH_INTERVAL_MS } from '../../../../../../common/constants/jobs_list';
|
||||
|
||||
import { moveToDataFrameJobsList, moveToDiscover } from '../../common';
|
||||
import {
|
||||
isKibanaContext,
|
||||
KibanaContext,
|
||||
moveToDataFrameTransformList,
|
||||
moveToDiscover,
|
||||
} from '../../../../common';
|
||||
|
||||
import { KibanaContext, isKibanaContext } from '../../common';
|
||||
|
||||
export interface JobDetailsExposedState {
|
||||
export interface StepDetailsExposedState {
|
||||
created: boolean;
|
||||
started: boolean;
|
||||
indexPatternId: string | undefined;
|
||||
}
|
||||
|
||||
export function getDefaultJobCreateState(): JobDetailsExposedState {
|
||||
export function getDefaultStepCreateState(): StepDetailsExposedState {
|
||||
return {
|
||||
created: false,
|
||||
started: false,
|
||||
|
@ -52,15 +55,15 @@ export function getDefaultJobCreateState(): JobDetailsExposedState {
|
|||
|
||||
interface Props {
|
||||
createIndexPattern: boolean;
|
||||
jobId: string;
|
||||
jobConfig: any;
|
||||
overrides: JobDetailsExposedState;
|
||||
onChange(s: JobDetailsExposedState): void;
|
||||
transformId: string;
|
||||
transformConfig: any;
|
||||
overrides: StepDetailsExposedState;
|
||||
onChange(s: StepDetailsExposedState): void;
|
||||
}
|
||||
|
||||
export const JobCreateForm: SFC<Props> = React.memo(
|
||||
({ createIndexPattern, jobConfig, jobId, onChange, overrides }) => {
|
||||
const defaults = { ...getDefaultJobCreateState(), ...overrides };
|
||||
export const StepCreateForm: SFC<Props> = React.memo(
|
||||
({ createIndexPattern, transformConfig, transformId, onChange, overrides }) => {
|
||||
const defaults = { ...getDefaultStepCreateState(), ...overrides };
|
||||
|
||||
const [created, setCreated] = useState(defaults.created);
|
||||
const [started, setStarted] = useState(defaults.started);
|
||||
|
@ -83,19 +86,20 @@ export const JobCreateForm: SFC<Props> = React.memo(
|
|||
setCreated(true);
|
||||
|
||||
try {
|
||||
await ml.dataFrame.createDataFrameTransformsJob(jobId, jobConfig);
|
||||
await ml.dataFrame.createDataFrameTransform(transformId, transformConfig);
|
||||
toastNotifications.addSuccess(
|
||||
i18n.translate('xpack.ml.dataframe.jobCreateForm.createJobSuccessMessage', {
|
||||
defaultMessage: 'Data frame transform {jobId} created successfully.',
|
||||
values: { jobId },
|
||||
i18n.translate('xpack.ml.dataframe.stepCreateForm.createTransformSuccessMessage', {
|
||||
defaultMessage: 'Data frame transform {transformId} created successfully.',
|
||||
values: { transformId },
|
||||
})
|
||||
);
|
||||
} catch (e) {
|
||||
setCreated(false);
|
||||
toastNotifications.addDanger(
|
||||
i18n.translate('xpack.ml.dataframe.jobCreateForm.createJobErrorMessage', {
|
||||
defaultMessage: 'An error occurred creating the data frame transform {jobId}: {error}',
|
||||
values: { jobId, error: JSON.stringify(e) },
|
||||
i18n.translate('xpack.ml.dataframe.stepCreateForm.createTransformErrorMessage', {
|
||||
defaultMessage:
|
||||
'An error occurred creating the data frame transform {transformId}: {error}',
|
||||
values: { transformId, error: JSON.stringify(e) },
|
||||
})
|
||||
);
|
||||
return false;
|
||||
|
@ -112,19 +116,20 @@ export const JobCreateForm: SFC<Props> = React.memo(
|
|||
setStarted(true);
|
||||
|
||||
try {
|
||||
await ml.dataFrame.startDataFrameTransformsJob(jobId);
|
||||
await ml.dataFrame.startDataFrameTransform(transformId);
|
||||
toastNotifications.addSuccess(
|
||||
i18n.translate('xpack.ml.dataframe.jobCreateForm.startJobSuccessMessage', {
|
||||
defaultMessage: 'Data frame transform {jobId} started successfully.',
|
||||
values: { jobId },
|
||||
i18n.translate('xpack.ml.dataframe.stepCreateForm.startTransformSuccessMessage', {
|
||||
defaultMessage: 'Data frame transform {transformId} started successfully.',
|
||||
values: { transformId },
|
||||
})
|
||||
);
|
||||
} catch (e) {
|
||||
setStarted(false);
|
||||
toastNotifications.addDanger(
|
||||
i18n.translate('xpack.ml.dataframe.jobCreateForm.startJobErrorMessage', {
|
||||
defaultMessage: 'An error occurred starting the data frame transform {jobId}: {error}',
|
||||
values: { jobId, error: JSON.stringify(e) },
|
||||
i18n.translate('xpack.ml.dataframe.stepCreateForm.startTransformErrorMessage', {
|
||||
defaultMessage:
|
||||
'An error occurred starting the data frame transform {transformId}: {error}',
|
||||
values: { transformId, error: JSON.stringify(e) },
|
||||
})
|
||||
);
|
||||
}
|
||||
|
@ -138,7 +143,7 @@ export const JobCreateForm: SFC<Props> = React.memo(
|
|||
}
|
||||
|
||||
const createKibanaIndexPattern = async () => {
|
||||
const indexPatternName = jobConfig.dest.index;
|
||||
const indexPatternName = transformConfig.dest.index;
|
||||
|
||||
try {
|
||||
const newIndexPattern = await kibanaContext.indexPatterns.get();
|
||||
|
@ -157,7 +162,7 @@ export const JobCreateForm: SFC<Props> = React.memo(
|
|||
}
|
||||
|
||||
toastNotifications.addSuccess(
|
||||
i18n.translate('xpack.ml.dataframe.jobCreateForm.reateIndexPatternSuccessMessage', {
|
||||
i18n.translate('xpack.ml.dataframe.stepCreateForm.reateIndexPatternSuccessMessage', {
|
||||
defaultMessage: 'Kibana index pattern {indexPatternName} created successfully.',
|
||||
values: { indexPatternName },
|
||||
})
|
||||
|
@ -167,7 +172,7 @@ export const JobCreateForm: SFC<Props> = React.memo(
|
|||
return true;
|
||||
} catch (e) {
|
||||
toastNotifications.addDanger(
|
||||
i18n.translate('xpack.ml.dataframe.jobCreateForm.createIndexPatternErrorMessage', {
|
||||
i18n.translate('xpack.ml.dataframe.stepCreateForm.createIndexPatternErrorMessage', {
|
||||
defaultMessage:
|
||||
'An error occurred creating the Kibana index pattern {indexPatternName}: {error}',
|
||||
values: { indexPatternName, error: JSON.stringify(e) },
|
||||
|
@ -177,14 +182,14 @@ export const JobCreateForm: SFC<Props> = React.memo(
|
|||
}
|
||||
};
|
||||
|
||||
const isBatchTransform = typeof jobConfig.sync === 'undefined';
|
||||
const isBatchTransform = typeof transformConfig.sync === 'undefined';
|
||||
|
||||
if (started === true && progressPercentComplete === undefined && isBatchTransform) {
|
||||
// wrapping in function so we can keep the interval id in local scope
|
||||
function startProgressBar() {
|
||||
const interval = setInterval(async () => {
|
||||
try {
|
||||
const stats = await ml.dataFrame.getDataFrameTransformsStats(jobId);
|
||||
const stats = await ml.dataFrame.getDataFrameTransformsStats(transformId);
|
||||
if (stats && Array.isArray(stats.transforms) && stats.transforms.length > 0) {
|
||||
const percent = Math.round(stats.transforms[0].state.progress.percent_complete);
|
||||
setProgressPercentComplete(percent);
|
||||
|
@ -194,7 +199,7 @@ export const JobCreateForm: SFC<Props> = React.memo(
|
|||
}
|
||||
} catch (e) {
|
||||
toastNotifications.addDanger(
|
||||
i18n.translate('xpack.ml.dataframe.jobCreateForm.progressErrorMessage', {
|
||||
i18n.translate('xpack.ml.dataframe.stepCreateForm.progressErrorMessage', {
|
||||
defaultMessage: 'An error occurred getting the progress percentage: {error}',
|
||||
values: { error: JSON.stringify(e) },
|
||||
})
|
||||
|
@ -208,8 +213,12 @@ export const JobCreateForm: SFC<Props> = React.memo(
|
|||
startProgressBar();
|
||||
}
|
||||
|
||||
function getJobConfigDevConsoleStatement() {
|
||||
return `PUT _data_frame/transforms/${jobId}\n${JSON.stringify(jobConfig, null, 2)}\n\n`;
|
||||
function getTransformConfigDevConsoleStatement() {
|
||||
return `PUT _data_frame/transforms/${transformId}\n${JSON.stringify(
|
||||
transformConfig,
|
||||
null,
|
||||
2
|
||||
)}\n\n`;
|
||||
}
|
||||
|
||||
// TODO move this to SASS
|
||||
|
@ -223,7 +232,7 @@ export const JobCreateForm: SFC<Props> = React.memo(
|
|||
<EuiFlexGroup alignItems="center" style={FLEX_GROUP_STYLE}>
|
||||
<EuiFlexItem grow={false} style={FLEX_ITEM_STYLE}>
|
||||
<EuiButton fill isDisabled={created && started} onClick={createAndStartDataFrame}>
|
||||
{i18n.translate('xpack.ml.dataframe.jobCreateForm.createAndStartDataFrameButton', {
|
||||
{i18n.translate('xpack.ml.dataframe.stepCreateForm.createAndStartDataFrameButton', {
|
||||
defaultMessage: 'Create and start',
|
||||
})}
|
||||
</EuiButton>
|
||||
|
@ -231,7 +240,7 @@ export const JobCreateForm: SFC<Props> = React.memo(
|
|||
<EuiFlexItem>
|
||||
<EuiText color="subdued" size="s">
|
||||
{i18n.translate(
|
||||
'xpack.ml.dataframe.jobCreateForm.createAndStartDataFrameDescription',
|
||||
'xpack.ml.dataframe.stepCreateForm.createAndStartDataFrameDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'Creates and starts the data frame transform. A data frame transform will increase search and indexing load in your cluster. Please stop the transform if excessive load is experienced. After the transform is started, you will be offered options to continue exploring the data frame transform.',
|
||||
|
@ -245,14 +254,14 @@ export const JobCreateForm: SFC<Props> = React.memo(
|
|||
<EuiFlexGroup alignItems="center" style={FLEX_GROUP_STYLE}>
|
||||
<EuiFlexItem grow={false} style={FLEX_ITEM_STYLE}>
|
||||
<EuiButton fill isDisabled={created && started} onClick={startDataFrame}>
|
||||
{i18n.translate('xpack.ml.dataframe.jobCreateForm.startDataFrameButton', {
|
||||
{i18n.translate('xpack.ml.dataframe.stepCreateForm.startDataFrameButton', {
|
||||
defaultMessage: 'Start',
|
||||
})}
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiText color="subdued" size="s">
|
||||
{i18n.translate('xpack.ml.dataframe.jobCreateForm.startDataFrameDescription', {
|
||||
{i18n.translate('xpack.ml.dataframe.stepCreateForm.startDataFrameDescription', {
|
||||
defaultMessage:
|
||||
'Starts the data frame transform. A data frame transform will increase search and indexing load in your cluster. Please stop the transform if excessive load is experienced. After the transform is started, you will be offered options to continue exploring the data frame transform.',
|
||||
})}
|
||||
|
@ -263,14 +272,14 @@ export const JobCreateForm: SFC<Props> = React.memo(
|
|||
<EuiFlexGroup alignItems="center" style={FLEX_GROUP_STYLE}>
|
||||
<EuiFlexItem grow={false} style={FLEX_ITEM_STYLE}>
|
||||
<EuiButton isDisabled={created} onClick={createDataFrame}>
|
||||
{i18n.translate('xpack.ml.dataframe.jobCreateForm.createDataFrameButton', {
|
||||
{i18n.translate('xpack.ml.dataframe.stepCreateForm.createDataFrameButton', {
|
||||
defaultMessage: 'Create',
|
||||
})}
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiText color="subdued" size="s">
|
||||
{i18n.translate('xpack.ml.dataframe.jobCreateForm.createDataFrameDescription', {
|
||||
{i18n.translate('xpack.ml.dataframe.stepCreateForm.createDataFrameDescription', {
|
||||
defaultMessage:
|
||||
'Create the data frame transform without starting it. You will be able to start the transform later by returning to the data frame transforms list.',
|
||||
})}
|
||||
|
@ -279,11 +288,11 @@ export const JobCreateForm: SFC<Props> = React.memo(
|
|||
</EuiFlexGroup>
|
||||
<EuiFlexGroup alignItems="center" style={FLEX_GROUP_STYLE}>
|
||||
<EuiFlexItem grow={false} style={FLEX_ITEM_STYLE}>
|
||||
<EuiCopy textToCopy={getJobConfigDevConsoleStatement()}>
|
||||
<EuiCopy textToCopy={getTransformConfigDevConsoleStatement()}>
|
||||
{(copy: () => void) => (
|
||||
<EuiButton onClick={copy} style={{ width: '100%' }}>
|
||||
{i18n.translate(
|
||||
'xpack.ml.dataframe.jobCreateForm.copyJobConfigToClipBoardButton',
|
||||
'xpack.ml.dataframe.stepCreateForm.copyTransformConfigToClipboardButton',
|
||||
{
|
||||
defaultMessage: 'Copy to clipboard',
|
||||
}
|
||||
|
@ -295,7 +304,7 @@ export const JobCreateForm: SFC<Props> = React.memo(
|
|||
<EuiFlexItem>
|
||||
<EuiText color="subdued" size="s">
|
||||
{i18n.translate(
|
||||
'xpack.ml.dataframe.jobCreateForm.copyJobConfigToClipBoardDescription',
|
||||
'xpack.ml.dataframe.stepCreateForm.copyTransformConfigToClipboardDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'Copies to the clipboard the Kibana Dev Console command for creating the transform.',
|
||||
|
@ -309,7 +318,7 @@ export const JobCreateForm: SFC<Props> = React.memo(
|
|||
<EuiSpacer size="m" />
|
||||
<EuiText size="xs">
|
||||
<strong>
|
||||
{i18n.translate('xpack.ml.dataframe.jobCreateForm.progressTitle', {
|
||||
{i18n.translate('xpack.ml.dataframe.stepCreateForm.progressTitle', {
|
||||
defaultMessage: 'Progress',
|
||||
})}
|
||||
</strong>
|
||||
|
@ -331,16 +340,19 @@ export const JobCreateForm: SFC<Props> = React.memo(
|
|||
<EuiFlexItem style={PANEL_ITEM_STYLE}>
|
||||
<EuiCard
|
||||
icon={<EuiIcon size="xxl" type="list" />}
|
||||
title={i18n.translate('xpack.ml.dataframe.jobCreateForm.jobsListCardTitle', {
|
||||
defaultMessage: 'Data frame transforms',
|
||||
})}
|
||||
title={i18n.translate(
|
||||
'xpack.ml.dataframe.stepCreateForm.transformListCardTitle',
|
||||
{
|
||||
defaultMessage: 'Data frame transforms',
|
||||
}
|
||||
)}
|
||||
description={i18n.translate(
|
||||
'xpack.ml.dataframe.jobCreateForm.jobManagementCardDescription',
|
||||
'xpack.ml.dataframe.stepCreateForm.transformListCardDescription',
|
||||
{
|
||||
defaultMessage: 'Return to the data frame transform management page.',
|
||||
}
|
||||
)}
|
||||
onClick={moveToDataFrameJobsList}
|
||||
onClick={moveToDataFrameTransformList}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
{started === true && createIndexPattern === true && indexPatternId === undefined && (
|
||||
|
@ -350,7 +362,7 @@ export const JobCreateForm: SFC<Props> = React.memo(
|
|||
<EuiText color="subdued" size="s">
|
||||
<p>
|
||||
{i18n.translate(
|
||||
'xpack.ml.dataframe.jobCreateForm.creatingIndexPatternMessage',
|
||||
'xpack.ml.dataframe.stepCreateForm.creatingIndexPatternMessage',
|
||||
{
|
||||
defaultMessage: 'Creating Kibana index pattern ...',
|
||||
}
|
||||
|
@ -364,11 +376,11 @@ export const JobCreateForm: SFC<Props> = React.memo(
|
|||
<EuiFlexItem style={PANEL_ITEM_STYLE}>
|
||||
<EuiCard
|
||||
icon={<EuiIcon size="xxl" type="discoverApp" />}
|
||||
title={i18n.translate('xpack.ml.dataframe.jobCreateForm.discoverCardTitle', {
|
||||
title={i18n.translate('xpack.ml.dataframe.stepCreateForm.discoverCardTitle', {
|
||||
defaultMessage: 'Discover',
|
||||
})}
|
||||
description={i18n.translate(
|
||||
'xpack.ml.dataframe.jobCreateForm.discoverCardDescription',
|
||||
'xpack.ml.dataframe.stepCreateForm.discoverCardDescription',
|
||||
{
|
||||
defaultMessage: 'Use Discover to explore the data frame pivot.',
|
||||
}
|
|
@ -6,6 +6,6 @@
|
|||
|
||||
import React, { SFC } from 'react';
|
||||
|
||||
export const JobCreateSummary: SFC = React.memo(() => {
|
||||
export const StepCreateSummary: SFC = React.memo(() => {
|
||||
return null;
|
||||
});
|
|
@ -18,7 +18,7 @@ exports[`Data Frame: <DefinePivotSummary /> Minimal initialization 1`] = `
|
|||
}
|
||||
}
|
||||
>
|
||||
<DefinePivotSummary
|
||||
<StepDefineSummary
|
||||
aggList={
|
||||
Object {
|
||||
"the-agg-name": Object {
|
|
@ -7,13 +7,13 @@
|
|||
import { IndexPattern } from 'ui/index_patterns';
|
||||
|
||||
import {
|
||||
getDataFramePreviewRequest,
|
||||
getPreviewRequestBody,
|
||||
PivotAggsConfig,
|
||||
PivotGroupByConfig,
|
||||
PIVOT_SUPPORTED_AGGS,
|
||||
PIVOT_SUPPORTED_GROUP_BY_AGGS,
|
||||
SimpleQuery,
|
||||
} from '../../common';
|
||||
} from '../../../../common';
|
||||
|
||||
import { getPivotPreviewDevConsoleStatement, getPivotDropdownOptions } from './common';
|
||||
|
||||
|
@ -122,7 +122,7 @@ describe('Data Frame: Define Pivot Common', () => {
|
|||
aggName: 'the-agg-agg-name',
|
||||
dropDownName: 'the-agg-drop-down-name',
|
||||
};
|
||||
const request = getDataFramePreviewRequest('the-index-pattern-title', query, [groupBy], [agg]);
|
||||
const request = getPreviewRequestBody('the-index-pattern-title', query, [groupBy], [agg]);
|
||||
const pivotPreviewDevConsoleStatement = getPivotPreviewDevConsoleStatement(request);
|
||||
|
||||
expect(pivotPreviewDevConsoleStatement).toBe(`POST _data_frame/transforms/_preview
|
|
@ -8,30 +8,30 @@ import { EuiComboBoxOptionProps } from '@elastic/eui';
|
|||
|
||||
import { IndexPattern } from 'ui/index_patterns';
|
||||
|
||||
import { KBN_FIELD_TYPES } from '../../../../common/constants/field_types';
|
||||
import { KBN_FIELD_TYPES } from '../../../../../../common/constants/field_types';
|
||||
|
||||
import {
|
||||
DataFramePreviewRequest,
|
||||
PreviewRequestBody,
|
||||
DropDownLabel,
|
||||
DropDownOption,
|
||||
FieldName,
|
||||
EsFieldName,
|
||||
GroupByConfigWithUiSupport,
|
||||
PivotAggsConfigWithUiSupportDict,
|
||||
pivotAggsFieldSupport,
|
||||
PivotGroupByConfigWithUiSupportDict,
|
||||
pivotGroupByFieldSupport,
|
||||
PIVOT_SUPPORTED_GROUP_BY_AGGS,
|
||||
} from '../../common';
|
||||
} from '../../../../common';
|
||||
|
||||
export interface Field {
|
||||
name: FieldName;
|
||||
name: EsFieldName;
|
||||
type: KBN_FIELD_TYPES;
|
||||
}
|
||||
|
||||
function getDefaultGroupByConfig(
|
||||
aggName: string,
|
||||
dropDownName: string,
|
||||
fieldName: FieldName,
|
||||
fieldName: EsFieldName,
|
||||
groupByAgg: PIVOT_SUPPORTED_GROUP_BY_AGGS
|
||||
): GroupByConfigWithUiSupport {
|
||||
switch (groupByAgg) {
|
||||
|
@ -121,6 +121,6 @@ export function getPivotDropdownOptions(indexPattern: IndexPattern) {
|
|||
};
|
||||
}
|
||||
|
||||
export const getPivotPreviewDevConsoleStatement = (request: DataFramePreviewRequest) => {
|
||||
export const getPivotPreviewDevConsoleStatement = (request: PreviewRequestBody) => {
|
||||
return `POST _data_frame/transforms/_preview\n${JSON.stringify(request, null, 2)}\n`;
|
||||
};
|
|
@ -5,9 +5,8 @@
|
|||
*/
|
||||
|
||||
export {
|
||||
DefinePivotExposedState,
|
||||
DefinePivotForm,
|
||||
getDefaultPivotState,
|
||||
} from './define_pivot_form';
|
||||
|
||||
export { DefinePivotSummary } from './define_pivot_summary';
|
||||
StepDefineExposedState,
|
||||
StepDefineForm,
|
||||
getDefaultStepDefineState,
|
||||
} from './step_define_form';
|
||||
export { StepDefineSummary } from './step_define_summary';
|
|
@ -14,7 +14,7 @@ import {
|
|||
PivotGroupByConfig,
|
||||
PIVOT_SUPPORTED_AGGS,
|
||||
PIVOT_SUPPORTED_GROUP_BY_AGGS,
|
||||
} from '../../common';
|
||||
} from '../../../../common';
|
||||
|
||||
import { PivotPreview } from './pivot_preview';
|
||||
|
|
@ -24,21 +24,20 @@ import {
|
|||
SortDirection,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { Dictionary, dictionaryToArray } from '../../../../common/types/common';
|
||||
import { ES_FIELD_TYPES } from '../../../../common/constants/field_types';
|
||||
import { formatHumanReadableDateTimeSeconds } from '../../../util/date_utils';
|
||||
import { Dictionary, dictionaryToArray } from '../../../../../../common/types/common';
|
||||
import { ES_FIELD_TYPES } from '../../../../../../common/constants/field_types';
|
||||
import { formatHumanReadableDateTimeSeconds } from '../../../../../util/date_utils';
|
||||
|
||||
import {
|
||||
DataFramePreviewRequest,
|
||||
getFlattenedFields,
|
||||
isKibanaContext,
|
||||
PreviewRequestBody,
|
||||
KibanaContext,
|
||||
PivotAggsConfigDict,
|
||||
PivotGroupByConfig,
|
||||
PivotGroupByConfigDict,
|
||||
PivotQuery,
|
||||
} from '../../common';
|
||||
|
||||
import { getFlattenedFields } from '../source_index_preview/common';
|
||||
} from '../../../../common';
|
||||
|
||||
import { getPivotPreviewDevConsoleStatement } from './common';
|
||||
import { PIVOT_PREVIEW_STATUS, usePivotPreviewData } from './use_pivot_preview_data';
|
||||
|
@ -75,7 +74,7 @@ function usePrevious(value: any) {
|
|||
}
|
||||
|
||||
interface PreviewTitleProps {
|
||||
previewRequest: DataFramePreviewRequest;
|
||||
previewRequest: PreviewRequestBody;
|
||||
}
|
||||
|
||||
const PreviewTitle: SFC<PreviewTitleProps> = ({ previewRequest }) => {
|
|
@ -13,8 +13,8 @@ import {
|
|||
PivotGroupByConfigDict,
|
||||
PIVOT_SUPPORTED_AGGS,
|
||||
PIVOT_SUPPORTED_GROUP_BY_AGGS,
|
||||
} from '../../common';
|
||||
import { DefinePivotForm, isAggNameConflict } from './define_pivot_form';
|
||||
} from '../../../../common';
|
||||
import { StepDefineForm, isAggNameConflict } from './step_define_form';
|
||||
|
||||
// workaround to make React.memo() work with enzyme
|
||||
jest.mock('react', () => {
|
||||
|
@ -44,7 +44,7 @@ describe('Data Frame: <DefinePivotForm />', () => {
|
|||
kibanaConfig: {},
|
||||
}}
|
||||
>
|
||||
<DefinePivotForm onChange={() => {}} />
|
||||
<StepDefineForm onChange={() => {}} />
|
||||
</KibanaContext.Provider>
|
||||
</div>
|
||||
);
|
|
@ -29,18 +29,18 @@ import {
|
|||
EuiSwitch,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { dictionaryToArray } from '../../../../common/types/common';
|
||||
import { DropDown } from '../../components/aggregation_dropdown/dropdown';
|
||||
import { AggListForm } from '../../components/aggregation_list';
|
||||
import { GroupByListForm } from '../../components/group_by_list';
|
||||
import { SourceIndexPreview } from '../../components/source_index_preview';
|
||||
import { dictionaryToArray } from '../../../../../../common/types/common';
|
||||
import { DropDown } from '../aggregation_dropdown';
|
||||
import { AggListForm } from '../aggregation_list';
|
||||
import { GroupByListForm } from '../group_by_list';
|
||||
import { SourceIndexPreview } from '../source_index_preview';
|
||||
import { PivotPreview } from './pivot_preview';
|
||||
|
||||
import {
|
||||
AggName,
|
||||
DropDownLabel,
|
||||
getPivotQuery,
|
||||
getDataFramePreviewRequest,
|
||||
getPreviewRequestBody,
|
||||
isKibanaContext,
|
||||
KibanaContext,
|
||||
KibanaContextValue,
|
||||
|
@ -53,11 +53,11 @@ import {
|
|||
PivotSupportedGroupByAggs,
|
||||
PIVOT_SUPPORTED_AGGS,
|
||||
SavedSearchQuery,
|
||||
} from '../../common';
|
||||
} from '../../../../common';
|
||||
|
||||
import { getPivotDropdownOptions } from './common';
|
||||
|
||||
export interface DefinePivotExposedState {
|
||||
export interface StepDefineExposedState {
|
||||
aggList: PivotAggsConfigDict;
|
||||
groupByList: PivotGroupByConfigDict;
|
||||
isAdvancedEditorEnabled: boolean;
|
||||
|
@ -68,7 +68,9 @@ export interface DefinePivotExposedState {
|
|||
const defaultSearch = '*';
|
||||
const emptySearch = '';
|
||||
|
||||
export function getDefaultPivotState(kibanaContext: KibanaContextValue): DefinePivotExposedState {
|
||||
export function getDefaultStepDefineState(
|
||||
kibanaContext: KibanaContextValue
|
||||
): StepDefineExposedState {
|
||||
return {
|
||||
aggList: {} as PivotAggsConfigDict,
|
||||
groupByList: {} as PivotGroupByConfigDict,
|
||||
|
@ -87,7 +89,7 @@ export function isAggNameConflict(
|
|||
) {
|
||||
if (aggList[aggName] !== undefined) {
|
||||
toastNotifications.addDanger(
|
||||
i18n.translate('xpack.ml.dataframe.definePivot.aggExistsErrorMessage', {
|
||||
i18n.translate('xpack.ml.dataframe.stepDefineForm.aggExistsErrorMessage', {
|
||||
defaultMessage: `An aggregation configuration with the name '{aggName}' already exists.`,
|
||||
values: { aggName },
|
||||
})
|
||||
|
@ -97,7 +99,7 @@ export function isAggNameConflict(
|
|||
|
||||
if (groupByList[aggName] !== undefined) {
|
||||
toastNotifications.addDanger(
|
||||
i18n.translate('xpack.ml.dataframe.definePivot.groupByExistsErrorMessage', {
|
||||
i18n.translate('xpack.ml.dataframe.stepDefineForm.groupByExistsErrorMessage', {
|
||||
defaultMessage: `A group by configuration with the name '{aggName}' already exists.`,
|
||||
values: { aggName },
|
||||
})
|
||||
|
@ -114,7 +116,7 @@ export function isAggNameConflict(
|
|||
aggNameCheck = aggNameCheck === undefined ? aggNamePart : `${aggNameCheck}.${aggNamePart}`;
|
||||
if (aggList[aggNameCheck] !== undefined || groupByList[aggNameCheck] !== undefined) {
|
||||
toastNotifications.addDanger(
|
||||
i18n.translate('xpack.ml.dataframe.definePivot.nestedConflictErrorMessage', {
|
||||
i18n.translate('xpack.ml.dataframe.stepDefineForm.nestedConflictErrorMessage', {
|
||||
defaultMessage: `Couldn't add configuration '{aggName}' because of a nesting conflict with '{aggNameCheck}'.`,
|
||||
values: { aggName, aggNameCheck },
|
||||
})
|
||||
|
@ -136,7 +138,7 @@ export function isAggNameConflict(
|
|||
aggListNameCheck === undefined ? aggListNamePart : `${aggListNameCheck}.${aggListNamePart}`;
|
||||
if (aggListNameCheck === aggName) {
|
||||
toastNotifications.addDanger(
|
||||
i18n.translate('xpack.ml.dataframe.definePivot.nestedAggListConflictErrorMessage', {
|
||||
i18n.translate('xpack.ml.dataframe.stepDefineForm.nestedAggListConflictErrorMessage', {
|
||||
defaultMessage: `Couldn't add configuration '{aggName}' because of a nesting conflict with '{aggListName}'.`,
|
||||
values: { aggName, aggListName },
|
||||
})
|
||||
|
@ -162,10 +164,13 @@ export function isAggNameConflict(
|
|||
: `${groupByListNameCheck}.${groupByListNamePart}`;
|
||||
if (groupByListNameCheck === aggName) {
|
||||
toastNotifications.addDanger(
|
||||
i18n.translate('xpack.ml.dataframe.definePivot.nestedGroupByListConflictErrorMessage', {
|
||||
defaultMessage: `Couldn't add configuration '{aggName}' because of a nesting conflict with '{groupByListName}'.`,
|
||||
values: { aggName, groupByListName },
|
||||
})
|
||||
i18n.translate(
|
||||
'xpack.ml.dataframe.stepDefineForm.nestedGroupByListConflictErrorMessage',
|
||||
{
|
||||
defaultMessage: `Couldn't add configuration '{aggName}' because of a nesting conflict with '{groupByListName}'.`,
|
||||
values: { aggName, groupByListName },
|
||||
}
|
||||
)
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
@ -177,11 +182,11 @@ export function isAggNameConflict(
|
|||
}
|
||||
|
||||
interface Props {
|
||||
overrides?: DefinePivotExposedState;
|
||||
onChange(s: DefinePivotExposedState): void;
|
||||
overrides?: StepDefineExposedState;
|
||||
onChange(s: StepDefineExposedState): void;
|
||||
}
|
||||
|
||||
export const DefinePivotForm: SFC<Props> = React.memo(({ overrides = {}, onChange }) => {
|
||||
export const StepDefineForm: SFC<Props> = React.memo(({ overrides = {}, onChange }) => {
|
||||
const kibanaContext = useContext(KibanaContext);
|
||||
|
||||
if (!isKibanaContext(kibanaContext)) {
|
||||
|
@ -190,7 +195,7 @@ export const DefinePivotForm: SFC<Props> = React.memo(({ overrides = {}, onChang
|
|||
|
||||
const indexPattern = kibanaContext.currentIndexPattern;
|
||||
|
||||
const defaults = { ...getDefaultPivotState(kibanaContext), ...overrides };
|
||||
const defaults = { ...getDefaultStepDefineState(kibanaContext), ...overrides };
|
||||
|
||||
// The search filter
|
||||
const [search, setSearch] = useState(defaults.search);
|
||||
|
@ -289,7 +294,7 @@ export const DefinePivotForm: SFC<Props> = React.memo(({ overrides = {}, onChang
|
|||
defaults.isAdvancedEditorEnabled
|
||||
);
|
||||
|
||||
const previewRequest = getDataFramePreviewRequest(
|
||||
const previewRequest = getPreviewRequestBody(
|
||||
indexPattern.title,
|
||||
pivotQuery,
|
||||
pivotGroupByArr,
|
||||
|
@ -357,12 +362,12 @@ export const DefinePivotForm: SFC<Props> = React.memo(({ overrides = {}, onChang
|
|||
const docsUrl = `https://www.elastic.co/guide/en/elasticsearch/reference/${metadata.branch}/data-frame-transform-pivot.html`;
|
||||
const advancedEditorHelpText = (
|
||||
<Fragment>
|
||||
{i18n.translate('xpack.ml.dataframe.definePivotForm.advancedEditorHelpText', {
|
||||
{i18n.translate('xpack.ml.dataframe.stepDefineForm.advancedEditorHelpText', {
|
||||
defaultMessage:
|
||||
'The advanced editor allows you to edit the pivot configuration of the data frame transform.',
|
||||
})}{' '}
|
||||
<EuiLink href={docsUrl} target="_blank">
|
||||
{i18n.translate('xpack.ml.dataframe.definePivotForm.advancedEditorHelpTextLink', {
|
||||
{i18n.translate('xpack.ml.dataframe.stepDefineForm.advancedEditorHelpTextLink', {
|
||||
defaultMessage: 'Learn more about available options.',
|
||||
})}
|
||||
</EuiLink>
|
||||
|
@ -372,7 +377,7 @@ export const DefinePivotForm: SFC<Props> = React.memo(({ overrides = {}, onChang
|
|||
const valid = pivotGroupByArr.length > 0 && pivotAggsArr.length > 0;
|
||||
|
||||
useEffect(() => {
|
||||
const previewRequestUpdate = getDataFramePreviewRequest(
|
||||
const previewRequestUpdate = getPreviewRequestBody(
|
||||
indexPattern.title,
|
||||
pivotQuery,
|
||||
pivotGroupByArr,
|
||||
|
@ -409,12 +414,12 @@ export const DefinePivotForm: SFC<Props> = React.memo(({ overrides = {}, onChang
|
|||
{kibanaContext.currentSavedSearch.id === undefined && typeof search === 'string' && (
|
||||
<Fragment>
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.ml.dataframe.definePivotForm.indexPatternLabel', {
|
||||
label={i18n.translate('xpack.ml.dataframe.stepDefineForm.indexPatternLabel', {
|
||||
defaultMessage: 'Index pattern',
|
||||
})}
|
||||
helpText={
|
||||
disabledQuery
|
||||
? i18n.translate('xpack.ml.dataframe.definePivotForm.indexPatternHelpText', {
|
||||
? i18n.translate('xpack.ml.dataframe.stepDefineForm.indexPatternHelpText', {
|
||||
defaultMessage:
|
||||
'An optional query for this index pattern is not supported. The number of supported index fields is {maxIndexFields} whereas this index has {numIndexFields} fields.',
|
||||
values: {
|
||||
|
@ -429,10 +434,10 @@ export const DefinePivotForm: SFC<Props> = React.memo(({ overrides = {}, onChang
|
|||
</EuiFormRow>
|
||||
{!disabledQuery && (
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.ml.dataframe.definePivotForm.queryLabel', {
|
||||
label={i18n.translate('xpack.ml.dataframe.stepDefineForm.queryLabel', {
|
||||
defaultMessage: 'Query',
|
||||
})}
|
||||
helpText={i18n.translate('xpack.ml.dataframe.definePivotForm.queryHelpText', {
|
||||
helpText={i18n.translate('xpack.ml.dataframe.stepDefineForm.queryHelpText', {
|
||||
defaultMessage: 'Use a query string to filter the source data (optional).',
|
||||
})}
|
||||
>
|
||||
|
@ -440,7 +445,7 @@ export const DefinePivotForm: SFC<Props> = React.memo(({ overrides = {}, onChang
|
|||
defaultQuery={search === defaultSearch ? emptySearch : search}
|
||||
box={{
|
||||
placeholder: i18n.translate(
|
||||
'xpack.ml.dataframe.definePivotForm.queryPlaceholder',
|
||||
'xpack.ml.dataframe.stepDefineForm.queryPlaceholder',
|
||||
{
|
||||
defaultMessage: 'e.g. {example}',
|
||||
values: { example: 'method:GET -is:active' },
|
||||
|
@ -457,7 +462,7 @@ export const DefinePivotForm: SFC<Props> = React.memo(({ overrides = {}, onChang
|
|||
|
||||
{kibanaContext.currentSavedSearch.id !== undefined && (
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.ml.dataframe.definePivotForm.savedSearchLabel', {
|
||||
label={i18n.translate('xpack.ml.dataframe.stepDefineForm.savedSearchLabel', {
|
||||
defaultMessage: 'Saved search',
|
||||
})}
|
||||
>
|
||||
|
@ -468,7 +473,7 @@ export const DefinePivotForm: SFC<Props> = React.memo(({ overrides = {}, onChang
|
|||
{!isAdvancedEditorEnabled && (
|
||||
<Fragment>
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.ml.dataframe.definePivotForm.groupByLabel', {
|
||||
label={i18n.translate('xpack.ml.dataframe.stepDefineForm.groupByLabel', {
|
||||
defaultMessage: 'Group by',
|
||||
})}
|
||||
>
|
||||
|
@ -483,7 +488,7 @@ export const DefinePivotForm: SFC<Props> = React.memo(({ overrides = {}, onChang
|
|||
changeHandler={addGroupBy}
|
||||
options={groupByOptions}
|
||||
placeholder={i18n.translate(
|
||||
'xpack.ml.dataframe.definePivotForm.groupByPlaceholder',
|
||||
'xpack.ml.dataframe.stepDefineForm.groupByPlaceholder',
|
||||
{
|
||||
defaultMessage: 'Add a group by field ...',
|
||||
}
|
||||
|
@ -493,7 +498,7 @@ export const DefinePivotForm: SFC<Props> = React.memo(({ overrides = {}, onChang
|
|||
</EuiFormRow>
|
||||
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.ml.dataframe.definePivotForm.aggregationsLabel', {
|
||||
label={i18n.translate('xpack.ml.dataframe.stepDefineForm.aggregationsLabel', {
|
||||
defaultMessage: 'Aggregations',
|
||||
})}
|
||||
>
|
||||
|
@ -508,7 +513,7 @@ export const DefinePivotForm: SFC<Props> = React.memo(({ overrides = {}, onChang
|
|||
changeHandler={addAggregation}
|
||||
options={aggOptions}
|
||||
placeholder={i18n.translate(
|
||||
'xpack.ml.dataframe.definePivotForm.aggregationsPlaceholder',
|
||||
'xpack.ml.dataframe.stepDefineForm.aggregationsPlaceholder',
|
||||
{
|
||||
defaultMessage: 'Add an aggregation ...',
|
||||
}
|
||||
|
@ -522,7 +527,7 @@ export const DefinePivotForm: SFC<Props> = React.memo(({ overrides = {}, onChang
|
|||
{isAdvancedEditorEnabled && (
|
||||
<Fragment>
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.ml.dataframe.definePivotForm.advancedEditorLabel', {
|
||||
label={i18n.translate('xpack.ml.dataframe.stepDefineForm.advancedEditorLabel', {
|
||||
defaultMessage: 'Pivot configuration object',
|
||||
})}
|
||||
helpText={advancedEditorHelpText}
|
||||
|
@ -554,7 +559,7 @@ export const DefinePivotForm: SFC<Props> = React.memo(({ overrides = {}, onChang
|
|||
fontSize: '12px',
|
||||
}}
|
||||
aria-label={i18n.translate(
|
||||
'xpack.ml.dataframe.definePivotForm.advancedEditorAriaLabel',
|
||||
'xpack.ml.dataframe.stepDefineForm.advancedEditorAriaLabel',
|
||||
{
|
||||
defaultMessage: 'Advanced editor',
|
||||
}
|
||||
|
@ -569,7 +574,7 @@ export const DefinePivotForm: SFC<Props> = React.memo(({ overrides = {}, onChang
|
|||
<EuiFlexItem>
|
||||
<EuiSwitch
|
||||
label={i18n.translate(
|
||||
'xpack.ml.dataframe.definePivotForm.advancedEditorSwitchLabel',
|
||||
'xpack.ml.dataframe.stepDefineForm.advancedEditorSwitchLabel',
|
||||
{
|
||||
defaultMessage: 'Advanced editor',
|
||||
}
|
||||
|
@ -592,7 +597,7 @@ export const DefinePivotForm: SFC<Props> = React.memo(({ overrides = {}, onChang
|
|||
<EuiOverlayMask>
|
||||
<EuiConfirmModal
|
||||
title={i18n.translate(
|
||||
'xpack.ml.dataframe.definePivotForm.advancedEditorSwitchModalTitle',
|
||||
'xpack.ml.dataframe.stepDefineForm.advancedEditorSwitchModalTitle',
|
||||
{
|
||||
defaultMessage: 'Unapplied changes',
|
||||
}
|
||||
|
@ -603,13 +608,13 @@ export const DefinePivotForm: SFC<Props> = React.memo(({ overrides = {}, onChang
|
|||
toggleAdvancedEditor();
|
||||
}}
|
||||
cancelButtonText={i18n.translate(
|
||||
'xpack.ml.dataframe.definePivotForm.advancedEditorSwitchModalCancelButtonText',
|
||||
'xpack.ml.dataframe.stepDefineForm.advancedEditorSwitchModalCancelButtonText',
|
||||
{
|
||||
defaultMessage: 'Cancel',
|
||||
}
|
||||
)}
|
||||
confirmButtonText={i18n.translate(
|
||||
'xpack.ml.dataframe.definePivotForm.advancedEditorSwitchModalConfirmButtonText',
|
||||
'xpack.ml.dataframe.stepDefineForm.advancedEditorSwitchModalConfirmButtonText',
|
||||
{
|
||||
defaultMessage: 'Disable advanced editor',
|
||||
}
|
||||
|
@ -619,7 +624,7 @@ export const DefinePivotForm: SFC<Props> = React.memo(({ overrides = {}, onChang
|
|||
>
|
||||
<p>
|
||||
{i18n.translate(
|
||||
'xpack.ml.dataframe.definePivotForm.advancedEditorSwitchModalBodyText',
|
||||
'xpack.ml.dataframe.stepDefineForm.advancedEditorSwitchModalBodyText',
|
||||
{
|
||||
defaultMessage: `The changes in the advanced editor haven't been applied yet. By disabling the advanced editor you will lose your edits.`,
|
||||
}
|
||||
|
@ -637,7 +642,7 @@ export const DefinePivotForm: SFC<Props> = React.memo(({ overrides = {}, onChang
|
|||
disabled={!isAdvancedEditorApplyButtonEnabled}
|
||||
>
|
||||
{i18n.translate(
|
||||
'xpack.ml.dataframe.definePivotForm.advancedEditorApplyButtonText',
|
||||
'xpack.ml.dataframe.stepDefineForm.advancedEditorApplyButtonText',
|
||||
{
|
||||
defaultMessage: 'Apply changes',
|
||||
}
|
||||
|
@ -649,7 +654,7 @@ export const DefinePivotForm: SFC<Props> = React.memo(({ overrides = {}, onChang
|
|||
{!valid && (
|
||||
<Fragment>
|
||||
<EuiFormHelpText style={{ maxWidth: '320px' }}>
|
||||
{i18n.translate('xpack.ml.dataframe.definePivotForm.formHelp', {
|
||||
{i18n.translate('xpack.ml.dataframe.stepDefineForm.formHelp', {
|
||||
defaultMessage:
|
||||
'Data frame transforms are scalable and automated processes for pivoting. Choose at least one group-by and aggregation to get started.',
|
||||
})}
|
|
@ -13,10 +13,10 @@ import {
|
|||
PivotGroupByConfig,
|
||||
PIVOT_SUPPORTED_AGGS,
|
||||
PIVOT_SUPPORTED_GROUP_BY_AGGS,
|
||||
} from '../../common';
|
||||
} from '../../../../common';
|
||||
|
||||
import { DefinePivotExposedState } from './define_pivot_form';
|
||||
import { DefinePivotSummary } from './define_pivot_summary';
|
||||
import { StepDefineExposedState } from './step_define_form';
|
||||
import { StepDefineSummary } from './step_define_summary';
|
||||
|
||||
// workaround to make React.memo() work with enzyme
|
||||
jest.mock('react', () => {
|
||||
|
@ -44,7 +44,7 @@ describe('Data Frame: <DefinePivotSummary />', () => {
|
|||
aggName: 'the-group-by-agg-name',
|
||||
dropDownName: 'the-group-by-drop-down-name',
|
||||
};
|
||||
const props: DefinePivotExposedState = {
|
||||
const props: StepDefineExposedState = {
|
||||
aggList: { 'the-agg-name': agg },
|
||||
groupByList: { 'the-group-by-name': groupBy },
|
||||
isAdvancedEditorEnabled: false,
|
||||
|
@ -66,7 +66,7 @@ describe('Data Frame: <DefinePivotSummary />', () => {
|
|||
kibanaConfig: {},
|
||||
}}
|
||||
>
|
||||
<DefinePivotSummary {...props} />
|
||||
<StepDefineSummary {...props} />
|
||||
</KibanaContext.Provider>
|
||||
</div>
|
||||
);
|
|
@ -10,17 +10,17 @@ import { i18n } from '@kbn/i18n';
|
|||
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiForm, EuiFormRow, EuiText } from '@elastic/eui';
|
||||
|
||||
import { AggListSummary } from '../../components/aggregation_list';
|
||||
import { GroupByListSummary } from '../../components/group_by_list';
|
||||
import { AggListSummary } from '../aggregation_list';
|
||||
import { GroupByListSummary } from '../group_by_list';
|
||||
import { PivotPreview } from './pivot_preview';
|
||||
|
||||
import { getPivotQuery, isKibanaContext, KibanaContext } from '../../common';
|
||||
import { DefinePivotExposedState } from './define_pivot_form';
|
||||
import { getPivotQuery, isKibanaContext, KibanaContext } from '../../../../common';
|
||||
import { StepDefineExposedState } from './step_define_form';
|
||||
|
||||
const defaultSearch = '*';
|
||||
const emptySearch = '';
|
||||
|
||||
export const DefinePivotSummary: SFC<DefinePivotExposedState> = ({
|
||||
export const StepDefineSummary: SFC<StepDefineExposedState> = ({
|
||||
search,
|
||||
groupByList,
|
||||
aggList,
|
||||
|
@ -42,7 +42,7 @@ export const DefinePivotSummary: SFC<DefinePivotExposedState> = ({
|
|||
{kibanaContext.currentSavedSearch.id === undefined && typeof search === 'string' && (
|
||||
<Fragment>
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.ml.dataframe.definePivotSummary.indexPatternLabel', {
|
||||
label={i18n.translate('xpack.ml.dataframe.stepDefineSummary.indexPatternLabel', {
|
||||
defaultMessage: 'Index pattern',
|
||||
})}
|
||||
>
|
||||
|
@ -50,7 +50,7 @@ export const DefinePivotSummary: SFC<DefinePivotExposedState> = ({
|
|||
</EuiFormRow>
|
||||
{displaySearch !== emptySearch && (
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.ml.dataframe.definePivotSummary.queryLabel', {
|
||||
label={i18n.translate('xpack.ml.dataframe.stepDefineSummary.queryLabel', {
|
||||
defaultMessage: 'Query',
|
||||
})}
|
||||
>
|
||||
|
@ -62,7 +62,7 @@ export const DefinePivotSummary: SFC<DefinePivotExposedState> = ({
|
|||
|
||||
{kibanaContext.currentSavedSearch.id !== undefined && (
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.ml.dataframe.definePivotForm.savedSearchLabel', {
|
||||
label={i18n.translate('xpack.ml.dataframe.stepDefineSummary.savedSearchLabel', {
|
||||
defaultMessage: 'Saved search',
|
||||
})}
|
||||
>
|
||||
|
@ -71,7 +71,7 @@ export const DefinePivotSummary: SFC<DefinePivotExposedState> = ({
|
|||
)}
|
||||
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.ml.dataframe.definePivotSummary.groupByLabel', {
|
||||
label={i18n.translate('xpack.ml.dataframe.stepDefineSummary.groupByLabel', {
|
||||
defaultMessage: 'Group by',
|
||||
})}
|
||||
>
|
||||
|
@ -79,7 +79,7 @@ export const DefinePivotSummary: SFC<DefinePivotExposedState> = ({
|
|||
</EuiFormRow>
|
||||
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.ml.dataframe.definePivotSummary.aggregationsLabel', {
|
||||
label={i18n.translate('xpack.ml.dataframe.stepDefineSummary.aggregationsLabel', {
|
||||
defaultMessage: 'Aggregations',
|
||||
})}
|
||||
>
|
|
@ -7,15 +7,15 @@
|
|||
import React, { SFC } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import { ml } from '../../../services/ml_api_service';
|
||||
import { SimpleQuery } from '../../common';
|
||||
import { ml } from '../../../../../services/ml_api_service';
|
||||
import { SimpleQuery } from '../../../../common';
|
||||
import {
|
||||
PIVOT_PREVIEW_STATUS,
|
||||
usePivotPreviewData,
|
||||
UsePivotPreviewDataReturnType,
|
||||
} from './use_pivot_preview_data';
|
||||
|
||||
jest.mock('../../../services/ml_api_service');
|
||||
jest.mock('../../../../../services/ml_api_service');
|
||||
|
||||
type Callback = () => void;
|
||||
interface TestHookProps {
|
|
@ -8,18 +8,18 @@ import { useEffect, useState } from 'react';
|
|||
|
||||
import { IndexPattern } from 'ui/index_patterns';
|
||||
|
||||
import { dictionaryToArray } from '../../../../common/types/common';
|
||||
import { ml } from '../../../services/ml_api_service';
|
||||
import { dictionaryToArray } from '../../../../../../common/types/common';
|
||||
import { ml } from '../../../../../services/ml_api_service';
|
||||
|
||||
import { Dictionary } from '../../../../common/types/common';
|
||||
import { ES_FIELD_TYPES } from '../../../../common/constants/field_types';
|
||||
import { Dictionary } from '../../../../../../common/types/common';
|
||||
import { ES_FIELD_TYPES } from '../../../../../../common/constants/field_types';
|
||||
import {
|
||||
DataFramePreviewRequest,
|
||||
getDataFramePreviewRequest,
|
||||
getPreviewRequestBody,
|
||||
PreviewRequestBody,
|
||||
PivotAggsConfigDict,
|
||||
PivotGroupByConfigDict,
|
||||
PivotQuery,
|
||||
} from '../../common';
|
||||
} from '../../../../common';
|
||||
|
||||
export enum PIVOT_PREVIEW_STATUS {
|
||||
UNUSED,
|
||||
|
@ -42,7 +42,7 @@ export interface UsePivotPreviewDataReturnType {
|
|||
status: PIVOT_PREVIEW_STATUS;
|
||||
dataFramePreviewData: DataFramePreviewData;
|
||||
dataFramePreviewMappings: DataFramePreviewMappings;
|
||||
previewRequest: DataFramePreviewRequest;
|
||||
previewRequest: PreviewRequestBody;
|
||||
}
|
||||
|
||||
export interface GetDataFrameTransformsResponse {
|
||||
|
@ -66,7 +66,7 @@ export const usePivotPreviewData = (
|
|||
const aggsArr = dictionaryToArray(aggs);
|
||||
const groupByArr = dictionaryToArray(groupBy);
|
||||
|
||||
const previewRequest = getDataFramePreviewRequest(indexPattern.title, query, groupByArr, aggsArr);
|
||||
const previewRequest = getPreviewRequestBody(indexPattern.title, query, groupByArr, aggsArr);
|
||||
|
||||
const getDataFramePreviewData = async () => {
|
||||
if (aggsArr.length === 0 || groupByArr.length === 0) {
|
|
@ -4,6 +4,5 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export type JobId = string;
|
||||
export type EsIndexName = string;
|
||||
export type IndexPatternTitle = string;
|
|
@ -4,6 +4,5 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { JobDetailsForm, getDefaultJobDetailsState } from './job_details_form';
|
||||
|
||||
export { JobDetailsSummary } from './job_details_summary';
|
||||
export { StepDetailsForm, getDefaultStepDetailsState } from './step_details_form';
|
||||
export { StepDetailsSummary } from './step_details_summary';
|
|
@ -12,35 +12,40 @@ import { toastNotifications } from 'ui/notify';
|
|||
|
||||
import { EuiLink, EuiSwitch, EuiFieldText, EuiForm, EuiFormRow, EuiSelect } from '@elastic/eui';
|
||||
|
||||
// @ts-ignore
|
||||
import { isJobIdValid } from '../../../../common/util/job_utils';
|
||||
import { isValidIndexName } from '../../../../common/util/es_utils';
|
||||
import { isValidIndexName } from '../../../../../../common/util/es_utils';
|
||||
|
||||
import { ml } from '../../../services/ml_api_service';
|
||||
import { ml } from '../../../../../services/ml_api_service';
|
||||
|
||||
import { DataFrameJobConfig, delayFormatRegex, KibanaContext, isKibanaContext } from '../../common';
|
||||
import { EsIndexName, IndexPatternTitle, JobId } from './common';
|
||||
import {
|
||||
delayFormatRegex,
|
||||
isKibanaContext,
|
||||
isTransformIdValid,
|
||||
DataFrameTransformId,
|
||||
DataFrameTransformPivotConfig,
|
||||
KibanaContext,
|
||||
} from '../../../../common';
|
||||
import { EsIndexName, IndexPatternTitle } from './common';
|
||||
|
||||
export interface JobDetailsExposedState {
|
||||
export interface StepDetailsExposedState {
|
||||
continuousModeDateField: string;
|
||||
continuousModeDelay: string;
|
||||
createIndexPattern: boolean;
|
||||
isContinuousModeEnabled: boolean;
|
||||
jobId: JobId;
|
||||
jobDescription: string;
|
||||
destinationIndex: EsIndexName;
|
||||
isContinuousModeEnabled: boolean;
|
||||
touched: boolean;
|
||||
transformId: DataFrameTransformId;
|
||||
transformDescription: string;
|
||||
valid: boolean;
|
||||
}
|
||||
|
||||
export function getDefaultJobDetailsState(): JobDetailsExposedState {
|
||||
export function getDefaultStepDetailsState(): StepDetailsExposedState {
|
||||
return {
|
||||
continuousModeDateField: '',
|
||||
continuousModeDelay: '60s',
|
||||
createIndexPattern: true,
|
||||
isContinuousModeEnabled: false,
|
||||
jobId: '',
|
||||
jobDescription: '',
|
||||
transformId: '',
|
||||
transformDescription: '',
|
||||
destinationIndex: '',
|
||||
touched: false,
|
||||
valid: false,
|
||||
|
@ -48,23 +53,25 @@ export function getDefaultJobDetailsState(): JobDetailsExposedState {
|
|||
}
|
||||
|
||||
interface Props {
|
||||
overrides?: JobDetailsExposedState;
|
||||
onChange(s: JobDetailsExposedState): void;
|
||||
overrides?: StepDetailsExposedState;
|
||||
onChange(s: StepDetailsExposedState): void;
|
||||
}
|
||||
|
||||
export const JobDetailsForm: SFC<Props> = React.memo(({ overrides = {}, onChange }) => {
|
||||
export const StepDetailsForm: SFC<Props> = React.memo(({ overrides = {}, onChange }) => {
|
||||
const kibanaContext = useContext(KibanaContext);
|
||||
|
||||
if (!isKibanaContext(kibanaContext)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const defaults = { ...getDefaultJobDetailsState(), ...overrides };
|
||||
const defaults = { ...getDefaultStepDetailsState(), ...overrides };
|
||||
|
||||
const [jobId, setJobId] = useState<JobId>(defaults.jobId);
|
||||
const [jobDescription, setJobDescription] = useState<string>(defaults.jobDescription);
|
||||
const [transformId, setTransformId] = useState<DataFrameTransformId>(defaults.transformId);
|
||||
const [transformDescription, setTransformDescription] = useState<string>(
|
||||
defaults.transformDescription
|
||||
);
|
||||
const [destinationIndex, setDestinationIndex] = useState<EsIndexName>(defaults.destinationIndex);
|
||||
const [jobIds, setJobIds] = useState<JobId[]>([]);
|
||||
const [transformIds, setTransformIds] = useState<DataFrameTransformId[]>([]);
|
||||
const [indexNames, setIndexNames] = useState<EsIndexName[]>([]);
|
||||
const [indexPatternTitles, setIndexPatternTitles] = useState<IndexPatternTitle[]>([]);
|
||||
const [createIndexPattern, setCreateIndexPattern] = useState(defaults.createIndexPattern);
|
||||
|
@ -84,19 +91,19 @@ export const JobDetailsForm: SFC<Props> = React.memo(({ overrides = {}, onChange
|
|||
const [continuousModeDelay, setContinuousModeDelay] = useState(defaults.continuousModeDelay);
|
||||
const isContinuousModeDelayValid = continuousModeDelay.match(delayFormatRegex) !== null;
|
||||
|
||||
// fetch existing job IDs and indices once for form validation
|
||||
// fetch existing transform IDs and indices once for form validation
|
||||
useEffect(() => {
|
||||
// use an IIFE to avoid returning a Promise to useEffect.
|
||||
(async function() {
|
||||
try {
|
||||
setJobIds(
|
||||
setTransformIds(
|
||||
(await ml.dataFrame.getDataFrameTransforms()).transforms.map(
|
||||
(job: DataFrameJobConfig) => job.id
|
||||
(transform: DataFrameTransformPivotConfig) => transform.id
|
||||
)
|
||||
);
|
||||
} catch (e) {
|
||||
toastNotifications.addDanger(
|
||||
i18n.translate('xpack.ml.dataframe.jobDetailsForm.errorGettingDataFrameJobsList', {
|
||||
i18n.translate('xpack.ml.dataframe.stepDetailsForm.errorGettingDataFrameTransformList', {
|
||||
defaultMessage:
|
||||
'An error occurred getting the existing data frame transform Ids: {error}',
|
||||
values: { error: JSON.stringify(e) },
|
||||
|
@ -108,7 +115,7 @@ export const JobDetailsForm: SFC<Props> = React.memo(({ overrides = {}, onChange
|
|||
setIndexNames((await ml.getIndices()).map(index => index.name));
|
||||
} catch (e) {
|
||||
toastNotifications.addDanger(
|
||||
i18n.translate('xpack.ml.dataframe.jobDetailsForm.errorGettingDataFrameIndexNames', {
|
||||
i18n.translate('xpack.ml.dataframe.stepDetailsForm.errorGettingDataFrameIndexNames', {
|
||||
defaultMessage: 'An error occurred getting the existing index names: {error}',
|
||||
values: { error: JSON.stringify(e) },
|
||||
})
|
||||
|
@ -119,7 +126,7 @@ export const JobDetailsForm: SFC<Props> = React.memo(({ overrides = {}, onChange
|
|||
setIndexPatternTitles(await kibanaContext.indexPatterns.getTitles());
|
||||
} catch (e) {
|
||||
toastNotifications.addDanger(
|
||||
i18n.translate('xpack.ml.dataframe.jobDetailsForm.errorGettingIndexPatternTitles', {
|
||||
i18n.translate('xpack.ml.dataframe.stepDetailsForm.errorGettingIndexPatternTitles', {
|
||||
defaultMessage: 'An error occurred getting the existing index pattern titles: {error}',
|
||||
values: { error: JSON.stringify(e) },
|
||||
})
|
||||
|
@ -128,9 +135,9 @@ export const JobDetailsForm: SFC<Props> = React.memo(({ overrides = {}, onChange
|
|||
})();
|
||||
}, []);
|
||||
|
||||
const jobIdExists = jobIds.some(id => jobId === id);
|
||||
const jobIdEmpty = jobId === '';
|
||||
const jobIdValid = isJobIdValid(jobId);
|
||||
const transformIdExists = transformIds.some(id => transformId === id);
|
||||
const transformIdEmpty = transformId === '';
|
||||
const transformIdValid = isTransformIdValid(transformId);
|
||||
|
||||
const indexNameExists = indexNames.some(name => destinationIndex === name);
|
||||
const indexNameEmpty = destinationIndex === '';
|
||||
|
@ -138,9 +145,9 @@ export const JobDetailsForm: SFC<Props> = React.memo(({ overrides = {}, onChange
|
|||
const indexPatternTitleExists = indexPatternTitles.some(name => destinationIndex === name);
|
||||
|
||||
const valid =
|
||||
!jobIdEmpty &&
|
||||
jobIdValid &&
|
||||
!jobIdExists &&
|
||||
!transformIdEmpty &&
|
||||
transformIdValid &&
|
||||
!transformIdExists &&
|
||||
!indexNameEmpty &&
|
||||
indexNameValid &&
|
||||
(!indexPatternTitleExists || !createIndexPattern) &&
|
||||
|
@ -153,8 +160,8 @@ export const JobDetailsForm: SFC<Props> = React.memo(({ overrides = {}, onChange
|
|||
continuousModeDelay,
|
||||
createIndexPattern,
|
||||
isContinuousModeEnabled,
|
||||
jobId,
|
||||
jobDescription,
|
||||
transformId,
|
||||
transformDescription,
|
||||
destinationIndex,
|
||||
touched: true,
|
||||
valid,
|
||||
|
@ -164,8 +171,8 @@ export const JobDetailsForm: SFC<Props> = React.memo(({ overrides = {}, onChange
|
|||
continuousModeDelay,
|
||||
createIndexPattern,
|
||||
isContinuousModeEnabled,
|
||||
jobId,
|
||||
jobDescription,
|
||||
transformId,
|
||||
transformDescription,
|
||||
destinationIndex,
|
||||
valid,
|
||||
]);
|
||||
|
@ -173,22 +180,22 @@ export const JobDetailsForm: SFC<Props> = React.memo(({ overrides = {}, onChange
|
|||
return (
|
||||
<EuiForm>
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.ml.dataframe.jobDetailsForm.jobIdLabel', {
|
||||
label={i18n.translate('xpack.ml.dataframe.stepDetailsForm.transformIdLabel', {
|
||||
defaultMessage: 'Transform id',
|
||||
})}
|
||||
isInvalid={(!jobIdEmpty && !jobIdValid) || jobIdExists}
|
||||
isInvalid={(!transformIdEmpty && !transformIdValid) || transformIdExists}
|
||||
error={[
|
||||
...(!jobIdEmpty && !jobIdValid
|
||||
...(!transformIdEmpty && !transformIdValid
|
||||
? [
|
||||
i18n.translate('xpack.ml.dataframe.jobDetailsForm.jobIdInvalidError', {
|
||||
i18n.translate('xpack.ml.dataframe.stepDetailsForm.transformIdInvalidError', {
|
||||
defaultMessage:
|
||||
'Must contain lowercase alphanumeric characters (a-z and 0-9), hyphens, and underscores only and must start and end with alphanumeric characters.',
|
||||
}),
|
||||
]
|
||||
: []),
|
||||
...(jobIdExists
|
||||
...(transformIdExists
|
||||
? [
|
||||
i18n.translate('xpack.ml.dataframe.jobDetailsForm.jobIdExistsError', {
|
||||
i18n.translate('xpack.ml.dataframe.stepDetailsForm.transformIdExistsError', {
|
||||
defaultMessage: 'A transform with this id already exists.',
|
||||
}),
|
||||
]
|
||||
|
@ -197,28 +204,34 @@ export const JobDetailsForm: SFC<Props> = React.memo(({ overrides = {}, onChange
|
|||
>
|
||||
<EuiFieldText
|
||||
placeholder="transform id"
|
||||
value={jobId}
|
||||
onChange={e => setJobId(e.target.value)}
|
||||
aria-label={i18n.translate('xpack.ml.dataframe.jobDetailsForm.jobIdInputAriaLabel', {
|
||||
defaultMessage: 'Choose a unique transform id.',
|
||||
})}
|
||||
isInvalid={(!jobIdEmpty && !jobIdValid) || jobIdExists}
|
||||
value={transformId}
|
||||
onChange={e => setTransformId(e.target.value)}
|
||||
aria-label={i18n.translate(
|
||||
'xpack.ml.dataframe.stepDetailsForm.transformIdInputAriaLabel',
|
||||
{
|
||||
defaultMessage: 'Choose a unique transform id.',
|
||||
}
|
||||
)}
|
||||
isInvalid={(!transformIdEmpty && !transformIdValid) || transformIdExists}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.ml.dataframe.jobDetailsForm.jobDescriptionLabel', {
|
||||
label={i18n.translate('xpack.ml.dataframe.stepDetailsForm.transformDescriptionLabel', {
|
||||
defaultMessage: 'Transform description',
|
||||
})}
|
||||
helpText={i18n.translate('xpack.ml.dataframe.jobDetailsForm.jobDescriptionHelpText', {
|
||||
defaultMessage: 'Optional descriptive text.',
|
||||
})}
|
||||
helpText={i18n.translate(
|
||||
'xpack.ml.dataframe.stepDetailsForm.transformDescriptionHelpText',
|
||||
{
|
||||
defaultMessage: 'Optional descriptive text.',
|
||||
}
|
||||
)}
|
||||
>
|
||||
<EuiFieldText
|
||||
placeholder="transform description"
|
||||
value={jobDescription}
|
||||
onChange={e => setJobDescription(e.target.value)}
|
||||
value={transformDescription}
|
||||
onChange={e => setTransformDescription(e.target.value)}
|
||||
aria-label={i18n.translate(
|
||||
'xpack.ml.dataframe.jobDetailsForm.jobDescriptionInputAriaLabel',
|
||||
'xpack.ml.dataframe.stepDetailsForm.transformDescriptionInputAriaLabel',
|
||||
{
|
||||
defaultMessage: 'Choose an optional transform description.',
|
||||
}
|
||||
|
@ -226,13 +239,13 @@ export const JobDetailsForm: SFC<Props> = React.memo(({ overrides = {}, onChange
|
|||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.ml.dataframe.jobDetailsForm.destinationIndexLabel', {
|
||||
label={i18n.translate('xpack.ml.dataframe.stepDetailsForm.destinationIndexLabel', {
|
||||
defaultMessage: 'Destination index',
|
||||
})}
|
||||
isInvalid={!indexNameEmpty && !indexNameValid}
|
||||
helpText={
|
||||
indexNameExists &&
|
||||
i18n.translate('xpack.ml.dataframe.jobDetailsForm.destinationIndexHelpText', {
|
||||
i18n.translate('xpack.ml.dataframe.stepDetailsForm.destinationIndexHelpText', {
|
||||
defaultMessage:
|
||||
'An index with this name already exists. Be aware that running this transform will modify this destination index.',
|
||||
})
|
||||
|
@ -241,7 +254,7 @@ export const JobDetailsForm: SFC<Props> = React.memo(({ overrides = {}, onChange
|
|||
!indexNameEmpty &&
|
||||
!indexNameValid && [
|
||||
<Fragment>
|
||||
{i18n.translate('xpack.ml.dataframe.jobDetailsForm.destinationIndexInvalidError', {
|
||||
{i18n.translate('xpack.ml.dataframe.stepDetailsForm.destinationIndexInvalidError', {
|
||||
defaultMessage: 'Invalid destination index name.',
|
||||
})}
|
||||
<br />
|
||||
|
@ -250,7 +263,7 @@ export const JobDetailsForm: SFC<Props> = React.memo(({ overrides = {}, onChange
|
|||
target="_blank"
|
||||
>
|
||||
{i18n.translate(
|
||||
'xpack.ml.dataframe.definePivotForm.destinationIndexInvalidErrorLink',
|
||||
'xpack.ml.dataframe.stepDetailsForm.destinationIndexInvalidErrorLink',
|
||||
{
|
||||
defaultMessage: 'Learn more about index name limitations.',
|
||||
}
|
||||
|
@ -265,7 +278,7 @@ export const JobDetailsForm: SFC<Props> = React.memo(({ overrides = {}, onChange
|
|||
value={destinationIndex}
|
||||
onChange={e => setDestinationIndex(e.target.value)}
|
||||
aria-label={i18n.translate(
|
||||
'xpack.ml.dataframe.jobDetailsForm.destinationIndexInputAriaLabel',
|
||||
'xpack.ml.dataframe.stepDetailsForm.destinationIndexInputAriaLabel',
|
||||
{
|
||||
defaultMessage: 'Choose a unique destination index name.',
|
||||
}
|
||||
|
@ -278,7 +291,7 @@ export const JobDetailsForm: SFC<Props> = React.memo(({ overrides = {}, onChange
|
|||
error={
|
||||
createIndexPattern &&
|
||||
indexPatternTitleExists && [
|
||||
i18n.translate('xpack.ml.dataframe.jobDetailsForm.indexPatternTitleError', {
|
||||
i18n.translate('xpack.ml.dataframe.stepDetailsForm.indexPatternTitleError', {
|
||||
defaultMessage: 'An index pattern with this title already exists.',
|
||||
}),
|
||||
]
|
||||
|
@ -286,7 +299,7 @@ export const JobDetailsForm: SFC<Props> = React.memo(({ overrides = {}, onChange
|
|||
>
|
||||
<EuiSwitch
|
||||
name="mlDataFrameCreateIndexPattern"
|
||||
label={i18n.translate('xpack.ml.dataframe.jobCreateForm.createIndexPatternLabel', {
|
||||
label={i18n.translate('xpack.ml.dataframe.stepCreateForm.createIndexPatternLabel', {
|
||||
defaultMessage: 'Create index pattern',
|
||||
})}
|
||||
checked={createIndexPattern === true}
|
||||
|
@ -296,7 +309,7 @@ export const JobDetailsForm: SFC<Props> = React.memo(({ overrides = {}, onChange
|
|||
<EuiFormRow
|
||||
helpText={
|
||||
isContinuousModeAvailable === false
|
||||
? i18n.translate('xpack.ml.dataframe.jobDetailsForm.continuousModeError', {
|
||||
? i18n.translate('xpack.ml.dataframe.stepDetailsForm.continuousModeError', {
|
||||
defaultMessage: 'Continuous mode is not available for indices without date fields.',
|
||||
})
|
||||
: ''
|
||||
|
@ -304,7 +317,7 @@ export const JobDetailsForm: SFC<Props> = React.memo(({ overrides = {}, onChange
|
|||
>
|
||||
<EuiSwitch
|
||||
name="mlDataFrameContinuousMode"
|
||||
label={i18n.translate('xpack.ml.dataframe.jobCreateForm.continuousModeLabel', {
|
||||
label={i18n.translate('xpack.ml.dataframe.stepCreateForm.continuousModeLabel', {
|
||||
defaultMessage: 'Continuous mode',
|
||||
})}
|
||||
checked={isContinuousModeEnabled === true}
|
||||
|
@ -316,13 +329,13 @@ export const JobDetailsForm: SFC<Props> = React.memo(({ overrides = {}, onChange
|
|||
<Fragment>
|
||||
<EuiFormRow
|
||||
label={i18n.translate(
|
||||
'xpack.ml.dataframe.jobDetailsForm.continuousModeDateFieldLabel',
|
||||
'xpack.ml.dataframe.stepDetailsForm.continuousModeDateFieldLabel',
|
||||
{
|
||||
defaultMessage: 'Date field',
|
||||
}
|
||||
)}
|
||||
helpText={i18n.translate(
|
||||
'xpack.ml.dataframe.jobDetailsForm.continuousModeDateFieldHelpText',
|
||||
'xpack.ml.dataframe.stepDetailsForm.continuousModeDateFieldHelpText',
|
||||
{
|
||||
defaultMessage: 'Select the date field that can be used to identify new documents.',
|
||||
}
|
||||
|
@ -335,19 +348,19 @@ export const JobDetailsForm: SFC<Props> = React.memo(({ overrides = {}, onChange
|
|||
/>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.ml.dataframe.jobDetailsForm.continuousModeDelayLabel', {
|
||||
label={i18n.translate('xpack.ml.dataframe.stepDetailsForm.continuousModeDelayLabel', {
|
||||
defaultMessage: 'Delay',
|
||||
})}
|
||||
isInvalid={!isContinuousModeDelayValid}
|
||||
error={
|
||||
!isContinuousModeDelayValid && [
|
||||
i18n.translate('xpack.ml.dataframe.jobDetailsForm.continuousModeDelayError', {
|
||||
i18n.translate('xpack.ml.dataframe.stepDetailsForm.continuousModeDelayError', {
|
||||
defaultMessage: 'Invalid delay format',
|
||||
}),
|
||||
]
|
||||
}
|
||||
helpText={i18n.translate(
|
||||
'xpack.ml.dataframe.jobDetailsForm.continuousModeDelayHelpText',
|
||||
'xpack.ml.dataframe.stepDetailsForm.continuousModeDelayHelpText',
|
||||
{
|
||||
defaultMessage: 'Time delay between current time and latest input data time.',
|
||||
}
|
||||
|
@ -358,7 +371,7 @@ export const JobDetailsForm: SFC<Props> = React.memo(({ overrides = {}, onChange
|
|||
value={continuousModeDelay}
|
||||
onChange={e => setContinuousModeDelay(e.target.value)}
|
||||
aria-label={i18n.translate(
|
||||
'xpack.ml.dataframe.jobDetailsForm.continuousModeAriaLabel',
|
||||
'xpack.ml.dataframe.stepDetailsForm.continuousModeAriaLabel',
|
||||
{
|
||||
defaultMessage: 'Choose a delay.',
|
||||
}
|
|
@ -10,15 +10,15 @@ import { i18n } from '@kbn/i18n';
|
|||
|
||||
import { EuiFieldText, EuiFormRow } from '@elastic/eui';
|
||||
|
||||
import { JobDetailsExposedState } from './job_details_form';
|
||||
import { StepDetailsExposedState } from './step_details_form';
|
||||
|
||||
export const JobDetailsSummary: SFC<JobDetailsExposedState> = React.memo(
|
||||
export const StepDetailsSummary: SFC<StepDetailsExposedState> = React.memo(
|
||||
({
|
||||
continuousModeDateField,
|
||||
createIndexPattern,
|
||||
isContinuousModeEnabled,
|
||||
jobId,
|
||||
jobDescription,
|
||||
transformId,
|
||||
transformDescription,
|
||||
destinationIndex,
|
||||
touched,
|
||||
}) => {
|
||||
|
@ -27,7 +27,7 @@ export const JobDetailsSummary: SFC<JobDetailsExposedState> = React.memo(
|
|||
}
|
||||
|
||||
const destinationIndexHelpText = createIndexPattern
|
||||
? i18n.translate('xpack.ml.dataframe.jobDetailsSummary.createIndexPatternMessage', {
|
||||
? i18n.translate('xpack.ml.dataframe.stepDetailsSummary.createIndexPatternMessage', {
|
||||
defaultMessage: 'A Kibana index pattern will be created for this transform.',
|
||||
})
|
||||
: '';
|
||||
|
@ -35,22 +35,22 @@ export const JobDetailsSummary: SFC<JobDetailsExposedState> = React.memo(
|
|||
return (
|
||||
<Fragment>
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.ml.dataframe.jobDetailsSummary.jobIdLabel', {
|
||||
label={i18n.translate('xpack.ml.dataframe.stepDetailsSummary.transformIdLabel', {
|
||||
defaultMessage: 'Transform id',
|
||||
})}
|
||||
>
|
||||
<EuiFieldText defaultValue={jobId} disabled={true} />
|
||||
<EuiFieldText defaultValue={transformId} disabled={true} />
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.ml.dataframe.jobDetailsSummary.jobDescriptionLabel', {
|
||||
label={i18n.translate('xpack.ml.dataframe.stepDetailsSummary.transformDescriptionLabel', {
|
||||
defaultMessage: 'Transform description',
|
||||
})}
|
||||
>
|
||||
<EuiFieldText defaultValue={jobDescription} disabled={true} />
|
||||
<EuiFieldText defaultValue={transformDescription} disabled={true} />
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
helpText={destinationIndexHelpText}
|
||||
label={i18n.translate('xpack.ml.dataframe.jobDetailsSummary.destinationIndexLabel', {
|
||||
label={i18n.translate('xpack.ml.dataframe.stepDetailsSummary.destinationIndexLabel', {
|
||||
defaultMessage: 'Destination index',
|
||||
})}
|
||||
>
|
||||
|
@ -59,7 +59,7 @@ export const JobDetailsSummary: SFC<JobDetailsExposedState> = React.memo(
|
|||
{isContinuousModeEnabled && (
|
||||
<EuiFormRow
|
||||
label={i18n.translate(
|
||||
'xpack.ml.dataframe.jobDetailsSummary.continuousModeDateFieldLabel',
|
||||
'xpack.ml.dataframe.stepDetailsSummary.continuousModeDateFieldLabel',
|
||||
{
|
||||
defaultMessage: 'Continuous mode date field',
|
||||
}
|
|
@ -4,4 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export * from './wizard_nav';
|
||||
export { Wizard } from './wizard';
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { Fragment, SFC, useContext, useRef, useState } from 'react';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { EuiSteps, EuiStepStatus } from '@elastic/eui';
|
||||
|
||||
import { isKibanaContext, getCreateRequestBody, KibanaContext } from '../../../../common';
|
||||
|
||||
import {
|
||||
StepDefineExposedState,
|
||||
StepDefineForm,
|
||||
StepDefineSummary,
|
||||
getDefaultStepDefineState,
|
||||
} from '../step_define';
|
||||
import { getDefaultStepCreateState, StepCreateForm, StepCreateSummary } from '../step_create';
|
||||
import { getDefaultStepDetailsState, StepDetailsForm, StepDetailsSummary } from '../step_details';
|
||||
import { WizardNav } from '../wizard_nav';
|
||||
|
||||
enum WIZARD_STEPS {
|
||||
DEFINE,
|
||||
DETAILS,
|
||||
CREATE,
|
||||
}
|
||||
|
||||
interface DefinePivotStepProps {
|
||||
isCurrentStep: boolean;
|
||||
stepDefineState: StepDefineExposedState;
|
||||
setCurrentStep: React.Dispatch<React.SetStateAction<WIZARD_STEPS>>;
|
||||
setStepDefineState: React.Dispatch<React.SetStateAction<StepDefineExposedState>>;
|
||||
}
|
||||
|
||||
const StepDefine: SFC<DefinePivotStepProps> = ({
|
||||
isCurrentStep,
|
||||
stepDefineState,
|
||||
setCurrentStep,
|
||||
setStepDefineState,
|
||||
}) => {
|
||||
const definePivotRef = useRef(null);
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<div ref={definePivotRef} />
|
||||
{isCurrentStep && (
|
||||
<Fragment>
|
||||
<StepDefineForm onChange={setStepDefineState} overrides={{ ...stepDefineState }} />
|
||||
<WizardNav
|
||||
next={() => setCurrentStep(WIZARD_STEPS.DETAILS)}
|
||||
nextActive={stepDefineState.valid}
|
||||
/>
|
||||
</Fragment>
|
||||
)}
|
||||
{!isCurrentStep && <StepDefineSummary {...stepDefineState} />}
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export const Wizard: SFC = React.memo(() => {
|
||||
const kibanaContext = useContext(KibanaContext);
|
||||
|
||||
if (!isKibanaContext(kibanaContext)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const indexPattern = kibanaContext.currentIndexPattern;
|
||||
|
||||
// The current WIZARD_STEP
|
||||
const [currentStep, setCurrentStep] = useState(WIZARD_STEPS.DEFINE);
|
||||
|
||||
// The DEFINE state
|
||||
const [stepDefineState, setStepDefineState] = useState(getDefaultStepDefineState(kibanaContext));
|
||||
|
||||
// The DETAILS state
|
||||
const [stepDetailsState, setStepDetailsState] = useState(getDefaultStepDetailsState());
|
||||
|
||||
const stepDetails =
|
||||
currentStep === WIZARD_STEPS.DETAILS ? (
|
||||
<StepDetailsForm onChange={setStepDetailsState} overrides={stepDetailsState} />
|
||||
) : (
|
||||
<StepDetailsSummary {...stepDetailsState} />
|
||||
);
|
||||
|
||||
const transformConfig = getCreateRequestBody(
|
||||
indexPattern.title,
|
||||
stepDefineState,
|
||||
stepDetailsState
|
||||
);
|
||||
|
||||
// The CREATE state
|
||||
const [stepCreateState, setStepCreateState] = useState(getDefaultStepCreateState);
|
||||
|
||||
const stepCreate =
|
||||
currentStep === WIZARD_STEPS.CREATE ? (
|
||||
<StepCreateForm
|
||||
createIndexPattern={stepDetailsState.createIndexPattern}
|
||||
transformId={stepDetailsState.transformId}
|
||||
transformConfig={transformConfig}
|
||||
onChange={setStepCreateState}
|
||||
overrides={stepCreateState}
|
||||
/>
|
||||
) : (
|
||||
<StepCreateSummary />
|
||||
);
|
||||
|
||||
// scroll to the currently selected wizard step
|
||||
/*
|
||||
function scrollToRef() {
|
||||
if (definePivotRef !== null && definePivotRef.current !== null) {
|
||||
// TODO Fix types
|
||||
const dummy = definePivotRef as any;
|
||||
const headerOffset = 70;
|
||||
window.scrollTo(0, dummy.current.offsetTop - headerOffset);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
const stepsConfig = [
|
||||
{
|
||||
title: i18n.translate('xpack.ml.dataframe.transformsWizard.stepDefineTitle', {
|
||||
defaultMessage: 'Define pivot',
|
||||
}),
|
||||
children: (
|
||||
<StepDefine
|
||||
isCurrentStep={currentStep === WIZARD_STEPS.DEFINE}
|
||||
stepDefineState={stepDefineState}
|
||||
setCurrentStep={setCurrentStep}
|
||||
setStepDefineState={setStepDefineState}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: i18n.translate('xpack.ml.dataframe.transformsWizard.stepDetailsTitle', {
|
||||
defaultMessage: 'Transform details',
|
||||
}),
|
||||
children: (
|
||||
<Fragment>
|
||||
{stepDetails}
|
||||
{currentStep === WIZARD_STEPS.DETAILS && (
|
||||
<WizardNav
|
||||
previous={() => {
|
||||
setCurrentStep(WIZARD_STEPS.DEFINE);
|
||||
// scrollToRef();
|
||||
}}
|
||||
next={() => setCurrentStep(WIZARD_STEPS.CREATE)}
|
||||
nextActive={stepDetailsState.valid}
|
||||
/>
|
||||
)}
|
||||
</Fragment>
|
||||
),
|
||||
status: currentStep >= WIZARD_STEPS.DETAILS ? undefined : ('incomplete' as EuiStepStatus),
|
||||
},
|
||||
{
|
||||
title: i18n.translate('xpack.ml.dataframe.transformsWizard.stepCreateTitle', {
|
||||
defaultMessage: 'Create',
|
||||
}),
|
||||
children: (
|
||||
<Fragment>
|
||||
{stepCreate}
|
||||
{currentStep === WIZARD_STEPS.CREATE && !stepCreateState.created && (
|
||||
<WizardNav previous={() => setCurrentStep(WIZARD_STEPS.DETAILS)} />
|
||||
)}
|
||||
</Fragment>
|
||||
),
|
||||
status: currentStep >= WIZARD_STEPS.CREATE ? undefined : ('incomplete' as EuiStepStatus),
|
||||
},
|
||||
];
|
||||
|
||||
return <EuiSteps steps={stepsConfig} />;
|
||||
});
|
|
@ -4,4 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { CreateJobButton } from './create_job_button';
|
||||
export { WizardNav } from './wizard_nav';
|
|
@ -20,7 +20,7 @@ import {
|
|||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { Wizard } from './wizard';
|
||||
import { Wizard } from './components/wizard';
|
||||
|
||||
export const Page: SFC = () => (
|
||||
<EuiPage>
|
||||
|
|
|
@ -8,22 +8,43 @@ import uiRoutes from 'ui/routes';
|
|||
|
||||
// @ts-ignore
|
||||
import { checkBasicLicense } from '../../../license/check_license';
|
||||
// @ts-ignore
|
||||
import { checkCreateDataFrameJobsPrivilege } from '../../../privilege/check_privilege';
|
||||
import { checkCreateDataFrameTransformPrivilege } from '../../../privilege/check_privilege';
|
||||
// @ts-ignore
|
||||
import { loadCurrentIndexPattern, loadCurrentSavedSearch } from '../../../util/index_utils';
|
||||
// @ts-ignore
|
||||
import { getDataFrameCreateBreadcrumbs } from '../../breadcrumbs';
|
||||
import { loadIndexPatterns } from '../../../util/index_utils';
|
||||
|
||||
const template = `<ml-nav-menu name="new_data_frame" /><ml-new-data-frame />`;
|
||||
import indexOrSearchTemplate from '../../../jobs/new_job/wizard/steps/index_or_search/index_or_search.html';
|
||||
|
||||
uiRoutes.when('/data_frames/new_job/step/pivot?', {
|
||||
template,
|
||||
import {
|
||||
getDataFrameCreateBreadcrumbs,
|
||||
getDataFrameIndexOrSearchBreadcrumbs,
|
||||
} from '../../breadcrumbs';
|
||||
|
||||
const wizardTemplate = `<ml-nav-menu name="new_data_frame" /><ml-new-data-frame />`;
|
||||
|
||||
uiRoutes.when('/data_frames/new_transform/step/pivot?', {
|
||||
template: wizardTemplate,
|
||||
k7Breadcrumbs: getDataFrameCreateBreadcrumbs,
|
||||
resolve: {
|
||||
CheckLicense: checkBasicLicense,
|
||||
privileges: checkCreateDataFrameJobsPrivilege,
|
||||
privileges: checkCreateDataFrameTransformPrivilege,
|
||||
indexPattern: loadCurrentIndexPattern,
|
||||
savedSearch: loadCurrentSavedSearch,
|
||||
},
|
||||
});
|
||||
|
||||
uiRoutes.when('/data_frames/new_transform', {
|
||||
redirectTo: '/data_frames/new_transform/step/index_or_search',
|
||||
});
|
||||
|
||||
uiRoutes.when('/data_frames/new_transform/step/index_or_search', {
|
||||
template: indexOrSearchTemplate,
|
||||
k7Breadcrumbs: getDataFrameIndexOrSearchBreadcrumbs,
|
||||
resolve: {
|
||||
CheckLicense: checkBasicLicense,
|
||||
privileges: checkCreateDataFrameTransformPrivilege,
|
||||
indexPatterns: loadIndexPatterns,
|
||||
nextStepPath: () => '#data_frames/new_transform/step/pivot',
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,182 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { Fragment, SFC, useContext, useRef, useState } from 'react';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { EuiSteps, EuiStepStatus } from '@elastic/eui';
|
||||
|
||||
import { WizardNav } from '../../components/wizard_nav';
|
||||
|
||||
import {
|
||||
DefinePivotExposedState,
|
||||
DefinePivotForm,
|
||||
DefinePivotSummary,
|
||||
getDefaultPivotState,
|
||||
} from '../../components/define_pivot';
|
||||
|
||||
import {
|
||||
getDefaultJobCreateState,
|
||||
JobCreateForm,
|
||||
JobCreateSummary,
|
||||
} from '../../components/job_create';
|
||||
|
||||
import { getDataFrameRequest } from '../../common';
|
||||
import {
|
||||
getDefaultJobDetailsState,
|
||||
JobDetailsForm,
|
||||
JobDetailsSummary,
|
||||
} from '../../components/job_details';
|
||||
|
||||
import { isKibanaContext, KibanaContext } from '../../common';
|
||||
|
||||
enum WIZARD_STEPS {
|
||||
DEFINE_PIVOT,
|
||||
JOB_DETAILS,
|
||||
JOB_CREATE,
|
||||
}
|
||||
|
||||
interface DefinePivotStepProps {
|
||||
isCurrentStep: boolean;
|
||||
pivotState: DefinePivotExposedState;
|
||||
setCurrentStep: React.Dispatch<React.SetStateAction<WIZARD_STEPS>>;
|
||||
setPivot: React.Dispatch<React.SetStateAction<DefinePivotExposedState>>;
|
||||
}
|
||||
|
||||
const DefinePivotStep: SFC<DefinePivotStepProps> = ({
|
||||
isCurrentStep,
|
||||
pivotState,
|
||||
setCurrentStep,
|
||||
setPivot,
|
||||
}) => {
|
||||
const definePivotRef = useRef(null);
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<div ref={definePivotRef} />
|
||||
{isCurrentStep && (
|
||||
<Fragment>
|
||||
<DefinePivotForm onChange={setPivot} overrides={{ ...pivotState }} />
|
||||
<WizardNav
|
||||
next={() => setCurrentStep(WIZARD_STEPS.JOB_DETAILS)}
|
||||
nextActive={pivotState.valid}
|
||||
/>
|
||||
</Fragment>
|
||||
)}
|
||||
{!isCurrentStep && <DefinePivotSummary {...pivotState} />}
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export const Wizard: SFC = React.memo(() => {
|
||||
const kibanaContext = useContext(KibanaContext);
|
||||
|
||||
if (!isKibanaContext(kibanaContext)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const indexPattern = kibanaContext.currentIndexPattern;
|
||||
|
||||
// The current WIZARD_STEP
|
||||
const [currentStep, setCurrentStep] = useState(WIZARD_STEPS.DEFINE_PIVOT);
|
||||
|
||||
// The DEFINE_PIVOT state
|
||||
const [pivotState, setPivot] = useState(getDefaultPivotState(kibanaContext));
|
||||
|
||||
// The JOB_DETAILS state
|
||||
const [jobDetailsState, setJobDetails] = useState(getDefaultJobDetailsState());
|
||||
|
||||
const jobDetails =
|
||||
currentStep === WIZARD_STEPS.JOB_DETAILS ? (
|
||||
<JobDetailsForm onChange={setJobDetails} overrides={jobDetailsState} />
|
||||
) : (
|
||||
<JobDetailsSummary {...jobDetailsState} />
|
||||
);
|
||||
|
||||
const jobConfig = getDataFrameRequest(indexPattern.title, pivotState, jobDetailsState);
|
||||
|
||||
// The JOB_CREATE state
|
||||
const [jobCreateState, setJobCreate] = useState(getDefaultJobCreateState);
|
||||
|
||||
const jobCreate =
|
||||
currentStep === WIZARD_STEPS.JOB_CREATE ? (
|
||||
<JobCreateForm
|
||||
createIndexPattern={jobDetailsState.createIndexPattern}
|
||||
jobId={jobDetailsState.jobId}
|
||||
jobConfig={jobConfig}
|
||||
onChange={setJobCreate}
|
||||
overrides={jobCreateState}
|
||||
/>
|
||||
) : (
|
||||
<JobCreateSummary />
|
||||
);
|
||||
|
||||
// scroll to the currently selected wizard step
|
||||
/*
|
||||
function scrollToRef() {
|
||||
if (definePivotRef !== null && definePivotRef.current !== null) {
|
||||
// TODO Fix types
|
||||
const dummy = definePivotRef as any;
|
||||
const headerOffset = 70;
|
||||
window.scrollTo(0, dummy.current.offsetTop - headerOffset);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
const stepsConfig = [
|
||||
{
|
||||
title: i18n.translate('xpack.ml.dataframe.transformsWizard.definePivotStepTitle', {
|
||||
defaultMessage: 'Define pivot',
|
||||
}),
|
||||
children: (
|
||||
<DefinePivotStep
|
||||
isCurrentStep={currentStep === WIZARD_STEPS.DEFINE_PIVOT}
|
||||
pivotState={pivotState}
|
||||
setCurrentStep={setCurrentStep}
|
||||
setPivot={setPivot}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: i18n.translate('xpack.ml.dataframe.transformsWizard.jobDetailsStepTitle', {
|
||||
defaultMessage: 'Transform details',
|
||||
}),
|
||||
children: (
|
||||
<Fragment>
|
||||
{jobDetails}
|
||||
{currentStep === WIZARD_STEPS.JOB_DETAILS && (
|
||||
<WizardNav
|
||||
previous={() => {
|
||||
setCurrentStep(WIZARD_STEPS.DEFINE_PIVOT);
|
||||
// scrollToRef();
|
||||
}}
|
||||
next={() => setCurrentStep(WIZARD_STEPS.JOB_CREATE)}
|
||||
nextActive={jobDetailsState.valid}
|
||||
/>
|
||||
)}
|
||||
</Fragment>
|
||||
),
|
||||
status: currentStep >= WIZARD_STEPS.JOB_DETAILS ? undefined : ('incomplete' as EuiStepStatus),
|
||||
},
|
||||
{
|
||||
title: i18n.translate('xpack.ml.dataframe.transformsWizard.createStepTitle', {
|
||||
defaultMessage: 'Create',
|
||||
}),
|
||||
children: (
|
||||
<Fragment>
|
||||
{jobCreate}
|
||||
{currentStep === WIZARD_STEPS.JOB_CREATE && !jobCreateState.created && (
|
||||
<WizardNav previous={() => setCurrentStep(WIZARD_STEPS.JOB_DETAILS)} />
|
||||
)}
|
||||
</Fragment>
|
||||
),
|
||||
status: currentStep >= WIZARD_STEPS.JOB_CREATE ? undefined : ('incomplete' as EuiStepStatus),
|
||||
},
|
||||
];
|
||||
|
||||
return <EuiSteps steps={stepsConfig} />;
|
||||
});
|
|
@ -1,7 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Data Frame: Job List <DataFrameJobList /> Minimal initialization 1`] = `
|
||||
<ProgressBar
|
||||
isLoading={false}
|
||||
/>
|
||||
`;
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import mockDataFrameJobListRow from './__mocks__/data_frame_job_list_row.json';
|
||||
|
||||
import { DATA_FRAME_TASK_STATE, isCompletedBatchJob } from './common';
|
||||
|
||||
describe('Data Frame: isCompletedBatchJob()', () => {
|
||||
test('isCompletedBatchJob()', () => {
|
||||
// check the job config/state against the conditions
|
||||
// that will be used by isCompletedBatchJob()
|
||||
// followed by a call to isCompletedBatchJob() itself
|
||||
expect(mockDataFrameJobListRow.state.checkpoint === 1).toBe(true);
|
||||
expect(mockDataFrameJobListRow.sync === undefined).toBe(true);
|
||||
expect(mockDataFrameJobListRow.state.task_state === DATA_FRAME_TASK_STATE.STOPPED).toBe(true);
|
||||
expect(isCompletedBatchJob(mockDataFrameJobListRow)).toBe(true);
|
||||
|
||||
// adapt the mock config to resemble a non-completed job.
|
||||
mockDataFrameJobListRow.state.checkpoint = 0;
|
||||
expect(isCompletedBatchJob(mockDataFrameJobListRow)).toBe(false);
|
||||
});
|
||||
});
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
import { ml } from '../../../../../../services/ml_api_service';
|
||||
|
||||
import { refreshTransformList$, REFRESH_TRANSFORM_LIST_STATE } from '../../../../../common';
|
||||
|
||||
import { DATA_FRAME_TASK_STATE, DataFrameJobListRow } from '../common';
|
||||
|
||||
export const deleteJob = async (d: DataFrameJobListRow) => {
|
||||
try {
|
||||
if (d.state.task_state === DATA_FRAME_TASK_STATE.FAILED) {
|
||||
await ml.dataFrame.stopDataFrameTransformsJob(
|
||||
d.config.id,
|
||||
d.state.task_state === DATA_FRAME_TASK_STATE.FAILED,
|
||||
true
|
||||
);
|
||||
}
|
||||
await ml.dataFrame.deleteDataFrameTransformsJob(d.config.id);
|
||||
toastNotifications.addSuccess(
|
||||
i18n.translate('xpack.ml.dataframe.jobsList.deleteJobSuccessMessage', {
|
||||
defaultMessage: 'Data frame transform {jobId} deleted successfully.',
|
||||
values: { jobId: d.config.id },
|
||||
})
|
||||
);
|
||||
} catch (e) {
|
||||
toastNotifications.addDanger(
|
||||
i18n.translate('xpack.ml.dataframe.jobsList.deleteJobErrorMessage', {
|
||||
defaultMessage: 'An error occurred deleting the data frame transform {jobId}: {error}',
|
||||
values: { jobId: d.config.id, error: JSON.stringify(e) },
|
||||
})
|
||||
);
|
||||
}
|
||||
refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH);
|
||||
};
|
|
@ -1,10 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { getJobsFactory } from './get_jobs';
|
||||
export { deleteJob } from './delete_job';
|
||||
export { startJob } from './start_job';
|
||||
export { stopJob } from './stop_job';
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
import { ml } from '../../../../../../services/ml_api_service';
|
||||
|
||||
import { refreshTransformList$, REFRESH_TRANSFORM_LIST_STATE } from '../../../../../common';
|
||||
|
||||
import { DATA_FRAME_TASK_STATE, DataFrameJobListRow } from '../common';
|
||||
|
||||
export const startJob = async (d: DataFrameJobListRow) => {
|
||||
try {
|
||||
await ml.dataFrame.startDataFrameTransformsJob(
|
||||
d.config.id,
|
||||
d.state.task_state === DATA_FRAME_TASK_STATE.FAILED
|
||||
);
|
||||
toastNotifications.addSuccess(
|
||||
i18n.translate('xpack.ml.dataframe.jobsList.startJobSuccessMessage', {
|
||||
defaultMessage: 'Data frame transform {jobId} started successfully.',
|
||||
values: { jobId: d.config.id },
|
||||
})
|
||||
);
|
||||
} catch (e) {
|
||||
toastNotifications.addDanger(
|
||||
i18n.translate('xpack.ml.dataframe.jobsList.startJobErrorMessage', {
|
||||
defaultMessage: 'An error occurred starting the data frame transform {jobId}: {error}',
|
||||
values: { jobId: d.config.id, error: JSON.stringify(e) },
|
||||
})
|
||||
);
|
||||
}
|
||||
refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH);
|
||||
};
|
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
import { ml } from '../../../../../../services/ml_api_service';
|
||||
|
||||
import { refreshTransformList$, REFRESH_TRANSFORM_LIST_STATE } from '../../../../../common';
|
||||
|
||||
import { DATA_FRAME_TASK_STATE, DataFrameJobListRow } from '../common';
|
||||
|
||||
export const stopJob = async (d: DataFrameJobListRow) => {
|
||||
try {
|
||||
await ml.dataFrame.stopDataFrameTransformsJob(
|
||||
d.config.id,
|
||||
d.state.task_state === DATA_FRAME_TASK_STATE.FAILED,
|
||||
true
|
||||
);
|
||||
toastNotifications.addSuccess(
|
||||
i18n.translate('xpack.ml.dataframe.jobsList.stopJobSuccessMessage', {
|
||||
defaultMessage: 'Data frame transform {jobId} stopped successfully.',
|
||||
values: { jobId: d.config.id },
|
||||
})
|
||||
);
|
||||
} catch (e) {
|
||||
toastNotifications.addDanger(
|
||||
i18n.translate('xpack.ml.dataframe.jobsList.stopJobErrorMessage', {
|
||||
defaultMessage: 'An error occurred stopping the data frame transform {jobId}: {error}',
|
||||
values: { jobId: d.config.id, error: JSON.stringify(e) },
|
||||
})
|
||||
);
|
||||
}
|
||||
refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH);
|
||||
};
|
|
@ -16,7 +16,7 @@ exports[`Data Frame: Job List <Page /> Minimal initialization 1`] = `
|
|||
<h1>
|
||||
<FormattedMessage
|
||||
defaultMessage="Data frame transforms"
|
||||
id="xpack.ml.dataframe.jobsList.dataFrameTitle"
|
||||
id="xpack.ml.dataframe.transformList.dataFrameTitle"
|
||||
values={Object {}}
|
||||
/>
|
||||
<span>
|
||||
|
@ -40,7 +40,7 @@ exports[`Data Frame: Job List <Page /> Minimal initialization 1`] = `
|
|||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<CreateJobButton />
|
||||
<CreateTransformButton />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPageContentHeaderSection>
|
||||
|
@ -54,7 +54,7 @@ exports[`Data Frame: Job List <Page /> Minimal initialization 1`] = `
|
|||
hasShadow={false}
|
||||
paddingSize="m"
|
||||
>
|
||||
<DataFrameJobList />
|
||||
<DataFrameTransformList />
|
||||
</EuiPanel>
|
||||
</EuiPageContentBody>
|
||||
</EuiPageBody>
|
|
@ -1,6 +1,6 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Data Frame: Job List <CreateJobButton /> Minimal initialization 1`] = `
|
||||
exports[`Data Frame: Transform List <CreateTransformButton /> Minimal initialization 1`] = `
|
||||
<EuiToolTip
|
||||
content="Your license has expired. Please contact your administrator."
|
||||
delay="regular"
|
||||
|
@ -19,7 +19,7 @@ exports[`Data Frame: Job List <CreateJobButton /> Minimal initialization 1`] = `
|
|||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Create transform"
|
||||
id="xpack.ml.dataframe.jobsList.createDataFrameButton"
|
||||
id="xpack.ml.dataframe.transformList.createDataFrameButton"
|
||||
values={Object {}}
|
||||
/>
|
||||
</EuiButton>
|
|
@ -7,12 +7,11 @@
|
|||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
|
||||
import './job_list.test.mocks';
|
||||
import { DataFrameJobList } from './job_list';
|
||||
import { CreateTransformButton } from './create_transform_button';
|
||||
|
||||
describe('Data Frame: Job List <DataFrameJobList />', () => {
|
||||
describe('Data Frame: Transform List <CreateTransformButton />', () => {
|
||||
test('Minimal initialization', () => {
|
||||
const wrapper = shallow(<DataFrameJobList />);
|
||||
const wrapper = shallow(<CreateTransformButton />);
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
|
@ -17,11 +17,11 @@ import {
|
|||
|
||||
import { moveToDataFrameWizard } from '../../../../common';
|
||||
|
||||
export const CreateJobButton: SFC = () => {
|
||||
export const CreateTransformButton: SFC = () => {
|
||||
const disabled =
|
||||
!checkPermission('canCreateDataFrameJob') ||
|
||||
!checkPermission('canPreviewDataFrameJob') ||
|
||||
!checkPermission('canStartStopDataFrameJob');
|
||||
!checkPermission('canCreateDataFrame') ||
|
||||
!checkPermission('canPreviewDataFrame') ||
|
||||
!checkPermission('canStartStopDataFrame');
|
||||
|
||||
const button = (
|
||||
<EuiButton
|
||||
|
@ -33,7 +33,7 @@ export const CreateJobButton: SFC = () => {
|
|||
data-test-subj="mlDataFramesButtonCreate"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.dataframe.jobsList.createDataFrameButton"
|
||||
id="xpack.ml.dataframe.transformList.createDataFrameButton"
|
||||
defaultMessage="Create transform"
|
||||
/>
|
||||
</EuiButton>
|
||||
|
@ -41,7 +41,7 @@ export const CreateJobButton: SFC = () => {
|
|||
|
||||
if (disabled) {
|
||||
return (
|
||||
<EuiToolTip position="top" content={createPermissionFailureMessage('canCreateDataFrameJob')}>
|
||||
<EuiToolTip position="top" content={createPermissionFailureMessage('canCreateDataFrame')}>
|
||||
{button}
|
||||
</EuiToolTip>
|
||||
);
|
|
@ -4,5 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export * from './list_form';
|
||||
export * from './list_summary';
|
||||
export { CreateTransformButton } from './create_transform_button';
|
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