diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/job_create.helpers.js b/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/job_create.helpers.js
index 57b551cad595b..e97f060306e52 100644
--- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/job_create.helpers.js
+++ b/x-pack/legacy/plugins/rollup/__jest__/client_integration/helpers/job_create.helpers.js
@@ -14,7 +14,7 @@ const initTestBed = registerTestBed(JobCreate, { store: rollupJobsStore });
export const setup = (props) => {
const testBed = initTestBed(props);
- const { component, form } = testBed;
+ const { component, form, table } = testBed;
// User actions
const clickNextStep = () => {
@@ -68,6 +68,30 @@ export const setup = (props) => {
}
};
+ // Helpers for the metrics step in job creation.
+ // Mostly placed here for now to make test file a bit smaller and specific
+ // to tests.
+ const getFieldListTableRows = () => {
+ const { rows } = table.getMetaData('rollupJobMetricsFieldList');
+ return rows;
+ };
+
+ const getFieldListTableRow = (row) => {
+ const rows = getFieldListTableRows();
+ return rows[row];
+ };
+
+ const getFieldChooserColumnForRow = (row) => {
+ const selectedRow = getFieldListTableRow(row);
+ const [,, fieldChooserColumn] = selectedRow.columns;
+ return fieldChooserColumn;
+ };
+
+ const getSelectAllInputForRow = (row) => {
+ const fieldChooser = getFieldChooserColumnForRow(row);
+ return fieldChooser.reactWrapper.find('input').first();
+ };
+
// Misc
const getEuiStepsHorizontalActive = () => component.find('.euiStepHorizontal-isSelected').text();
@@ -84,5 +108,11 @@ export const setup = (props) => {
...testBed.form,
fillFormFields,
},
+ metrics: {
+ getFieldListTableRows,
+ getFieldListTableRow,
+ getFieldChooserColumnForRow,
+ getSelectAllInputForRow,
+ }
};
};
diff --git a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_metrics.test.js b/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_metrics.test.js
index f54ba7f85ae99..cfd4901e3a8be 100644
--- a/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_metrics.test.js
+++ b/x-pack/legacy/plugins/rollup/__jest__/client_integration/job_create_metrics.test.js
@@ -36,6 +36,7 @@ describe('Create Rollup Job, step 5: Metrics', () => {
let getEuiStepsHorizontalActive;
let goToStep;
let table;
+ let metrics;
beforeAll(() => {
({ server, httpRequestsMockHelpers } = setupEnvironment());
@@ -56,6 +57,7 @@ describe('Create Rollup Job, step 5: Metrics', () => {
getEuiStepsHorizontalActive,
goToStep,
table,
+ metrics,
} = setup());
});
@@ -175,6 +177,9 @@ describe('Create Rollup Job, step 5: Metrics', () => {
}
};
+ const numericTypeMetrics = ['avg', 'max', 'min', 'sum', 'value_count'];
+ const dateTypeMetrics = ['max', 'min', 'value_count'];
+
it('should have an empty field list', async () => {
await goToStep(5);
@@ -189,7 +194,6 @@ describe('Create Rollup Job, step 5: Metrics', () => {
});
it('should have "avg", "max", "min", "sum" & "value count" metrics for *numeric* fields', () => {
- const numericTypeMetrics = ['avg', 'max', 'min', 'sum', 'value_count'];
addFieldToList('numeric');
numericTypeMetrics.forEach(type => {
try {
@@ -203,11 +207,10 @@ describe('Create Rollup Job, step 5: Metrics', () => {
const { rows: [firstRow] } = table.getMetaData('rollupJobMetricsFieldList');
const columnWithMetricsCheckboxes = 2;
const metricsCheckboxes = firstRow.columns[columnWithMetricsCheckboxes].reactWrapper.find('input');
- expect(metricsCheckboxes.length).toBe(numericTypeMetrics.length);
+ expect(metricsCheckboxes.length).toBe(numericTypeMetrics.length + 1 /* add one for select all */);
});
it('should have "max", "min", & "value count" metrics for *date* fields', () => {
- const dateTypeMetrics = ['max', 'min', 'value_count'];
addFieldToList('date');
dateTypeMetrics.forEach(type => {
@@ -222,7 +225,7 @@ describe('Create Rollup Job, step 5: Metrics', () => {
const { rows: [firstRow] } = table.getMetaData('rollupJobMetricsFieldList');
const columnWithMetricsCheckboxes = 2;
const metricsCheckboxes = firstRow.columns[columnWithMetricsCheckboxes].reactWrapper.find('input');
- expect(metricsCheckboxes.length).toBe(dateTypeMetrics.length);
+ expect(metricsCheckboxes.length).toBe(dateTypeMetrics.length + 1 /* add one for select all */);
});
it('should not allow to go to the next step if at least one metric type is not selected', () => {
@@ -247,12 +250,162 @@ describe('Create Rollup Job, step 5: Metrics', () => {
const columnsFirstRow = fieldListRows[0].columns;
// The last column is the eui "actions" column
- const deleteButton = columnsFirstRow[columnsFirstRow.length - 1].reactWrapper.find('button');
+ const deleteButton = columnsFirstRow[columnsFirstRow.length - 1].reactWrapper.find('button').last();
deleteButton.simulate('click');
({ rows: fieldListRows } = table.getMetaData('rollupJobMetricsFieldList'));
expect(fieldListRows[0].columns[0].value).toEqual('No metrics fields added');
});
});
+
+ describe('when using multi-selectors', () => {
+ let getSelectAllInputForRow;
+ let getFieldChooserColumnForRow;
+ let getFieldListTableRows;
+
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setIndexPatternValidityResponse({ numericFields, dateFields });
+ await goToStep(5);
+ await addFieldToList('numeric');
+ await addFieldToList('date');
+ find('rollupJobSelectAllMetricsPopoverButton').simulate('click');
+ ({ getSelectAllInputForRow, getFieldChooserColumnForRow, getFieldListTableRows } = metrics);
+ });
+
+ const expectAllFieldChooserInputs = (fieldChooserColumn, expected) => {
+ const inputs = fieldChooserColumn.reactWrapper.find('input');
+ inputs.forEach((input) => {
+ expect(input.props().checked).toBe(expected);
+ });
+ };
+
+ it('should select all of the fields in a row', async () => {
+ // The last column is the eui "actions" column
+ const selectAllCheckbox = getSelectAllInputForRow(0);
+ selectAllCheckbox.simulate('change', { checked: true });
+ const fieldChooserColumn = getFieldChooserColumnForRow(0);
+ expectAllFieldChooserInputs(fieldChooserColumn, true);
+ });
+
+ it('should deselect all of the fields in a row ', async () => {
+ const selectAllCheckbox = getSelectAllInputForRow(0);
+ selectAllCheckbox.simulate('change', { checked: true });
+
+ let fieldChooserColumn = getFieldChooserColumnForRow(0);
+ expectAllFieldChooserInputs(fieldChooserColumn, true);
+
+ selectAllCheckbox.simulate('change', { checked: false });
+ fieldChooserColumn = getFieldChooserColumnForRow(0);
+ expectAllFieldChooserInputs(fieldChooserColumn, false);
+ });
+
+ it('should select all of the metric types across rows (column-wise)', () => {
+ const selectAllAvgCheckbox = find('rollupJobMetricsSelectAllCheckbox-avg');
+ selectAllAvgCheckbox.first().simulate('change', { checked: true });
+
+ const rows = getFieldListTableRows();
+
+ rows
+ .filter((row) => {
+ const [, metricTypeCol ] = row.columns;
+ return metricTypeCol.value === 'numeric';
+ })
+ .forEach((row, idx) => {
+ const fieldChooser = getFieldChooserColumnForRow(idx);
+ fieldChooser.reactWrapper.find('input').forEach(input => {
+ const props = input.props();
+ if (props['data-test-subj'].endsWith('avg')) {
+ expect(props.checked).toBe(true);
+ } else {
+ expect(props.checked).toBe(false);
+ }
+ });
+ });
+ });
+
+ it('should deselect all of the metric types across rows (column-wise)', () => {
+ const selectAllAvgCheckbox = find('rollupJobMetricsSelectAllCheckbox-avg');
+
+ // Select first, which adds metrics column-wise, and then de-select column-wise to ensure
+ // that we correctly remove/undo our adding action.
+ selectAllAvgCheckbox.last().simulate('change', { checked: true });
+ selectAllAvgCheckbox.last().simulate('change', { checked: false });
+
+ const rows = getFieldListTableRows();
+
+ rows.forEach((row, idx) => {
+ const [, metricTypeCol ] = row.columns;
+ if (metricTypeCol.value !== 'numeric') {
+ return;
+ }
+ const fieldChooser = getFieldChooserColumnForRow(idx);
+ fieldChooser.reactWrapper.find('input').forEach(input => {
+ expect(input.props().checked).toBe(false);
+ });
+ });
+ });
+
+ it('should correctly select across rows and columns', async () => {
+ /**
+ * Tricky test case where we want to determine that the column-wise and row-wise
+ * selections are interacting correctly with each other.
+ *
+ * We will select avg (numeric) and max (numeric + date) to ensure that we are
+ * testing across metrics types too. The plan is:
+ *
+ * 1. Select all avg column-wise
+ * 2. Select all max column-wise
+ * 3. Select and deselect row-wise the first numeric metric row. Because some items will
+ * have been selected by the previous column-wise selection we want to test that row-wise
+ * select all followed by de-select can effectively undo the column-wise selections.
+ * 4. Expect the avg and max select all checkboxes to be unchecked
+ * 5. Select all on the last date metric row-wise
+ * 6. Select then deselect all max column-wise
+ * 7. Expect everything but all and max to be selected on the last date metric row
+ *
+ * Let's a go!
+ */
+
+ // 1.
+ find('rollupJobMetricsSelectAllCheckbox-avg').first().simulate('change', { checked: true });
+ // 2.
+ find('rollupJobMetricsSelectAllCheckbox-max').first().simulate('change', { checked: true });
+
+ const selectAllCheckbox = getSelectAllInputForRow(0);
+
+ // 3.
+ // Select all (which should check all checkboxes)
+ selectAllCheckbox.simulate('change', { checked: true });
+ // Deselect all (which should deselect all checkboxes)
+ selectAllCheckbox.simulate('change', { checked: false });
+
+ // 4.
+ expect(find('rollupJobMetricsSelectAllCheckbox-avg').first().props().checked).toBe(false);
+ expect(find('rollupJobMetricsSelectAllCheckbox-max').first().props().checked).toBe(false);
+
+ let rows = getFieldListTableRows();
+ // 5.
+ getSelectAllInputForRow(rows.length - 1).simulate('change', { checked: true });
+
+ // 6.
+ find('rollupJobMetricsSelectAllCheckbox-max').first().simulate('change', { checked: true });
+ find('rollupJobMetricsSelectAllCheckbox-max').first().simulate('change', { checked: false });
+
+ rows = getFieldListTableRows();
+ const lastRowFieldChooserColumn = getFieldChooserColumnForRow(rows.length - 1);
+ // 7.
+ lastRowFieldChooserColumn.reactWrapper.find('input').forEach((input) => {
+ const props = input.props();
+ if (
+ props['data-test-subj'].endsWith('max') ||
+ props['data-test-subj'].endsWith('All')
+ ) {
+ expect(props.checked).toBe(false);
+ } else {
+ expect(props.checked).toBe(true);
+ }
+ });
+ });
+ });
});
});
diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/constants/index.js b/x-pack/legacy/plugins/rollup/public/crud_app/constants/index.js
index f71725d23b4e0..9b2b10d3ae742 100644
--- a/x-pack/legacy/plugins/rollup/public/crud_app/constants/index.js
+++ b/x-pack/legacy/plugins/rollup/public/crud_app/constants/index.js
@@ -7,3 +7,7 @@
export {
CRUD_APP_BASE_PATH,
} from './paths';
+
+export {
+ METRICS_CONFIG
+} from './metrics_config';
diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/constants/metrics_config.js b/x-pack/legacy/plugins/rollup/public/crud_app/constants/metrics_config.js
new file mode 100644
index 0000000000000..f0931252a2d1e
--- /dev/null
+++ b/x-pack/legacy/plugins/rollup/public/crud_app/constants/metrics_config.js
@@ -0,0 +1,45 @@
+/*
+ * 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';
+
+export const METRICS_CONFIG = [
+ {
+ type: 'avg',
+ label: i18n.translate(
+ 'xpack.rollupJobs.create.stepMetrics.checkboxAverageLabel',
+ { defaultMessage: 'Average' },
+ ),
+ },
+ {
+ type: 'max',
+ label: i18n.translate(
+ 'xpack.rollupJobs.create.stepMetrics.checkboxMaxLabel',
+ { defaultMessage: 'Maximum' },
+ ),
+ },
+ {
+ type: 'min',
+ label: i18n.translate(
+ 'xpack.rollupJobs.create.stepMetrics.checkboxMinLabel',
+ { defaultMessage: 'Minimum' },
+ ),
+ },
+ {
+ type: 'sum',
+ label: i18n.translate(
+ 'xpack.rollupJobs.create.stepMetrics.checkboxSumLabel',
+ { defaultMessage: 'Sum' },
+ ),
+ },
+ {
+ type: 'value_count',
+ label: i18n.translate(
+ 'xpack.rollupJobs.create.stepMetrics.checkboxValueCountLabel',
+ { defaultMessage: 'Value count' },
+ ),
+ },
+];
diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/field_list/field_list.js b/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/field_list/field_list.js
index 5734cdb1ec0a6..6f3834971917f 100644
--- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/field_list/field_list.js
+++ b/x-pack/legacy/plugins/rollup/public/crud_app/sections/components/field_list/field_list.js
@@ -45,7 +45,7 @@ export const FieldList = ({
type: 'icon',
color: 'danger',
onClick: (field) => onRemoveField(field),
- }]
+ }],
});
} else {
extendedColumns = columns;
diff --git a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/components/field_chooser.js b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/components/field_chooser.js
index 6f56b9a204588..6d6b77ab2e047 100644
--- a/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/components/field_chooser.js
+++ b/x-pack/legacy/plugins/rollup/public/crud_app/sections/job_create/steps/components/field_chooser.js
@@ -25,7 +25,6 @@ export class FieldChooser extends Component {
fields: PropTypes.array.isRequired,
selectedFields: PropTypes.array.isRequired,
onSelectField: PropTypes.func.isRequired,
- columns: PropTypes.array.isRequired,
prompt: PropTypes.string,
dataTestSubj: PropTypes.string,
}
@@ -136,7 +135,6 @@ export class FieldChooser extends Component {
);
};
-
return (
@@ -250,28 +396,51 @@ export class StepMetricsUi extends Component {
-