From 27fcb77e4a70b73ef88c42d600352131018072e8 Mon Sep 17 00:00:00 2001 From: Melissa Alvarez Date: Thu, 19 Oct 2023 08:36:23 -0600 Subject: [PATCH] [ML] Data Frame Analytics creation: ensure form state persists after switch to editor (#169186) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary This PR: - ensures the form state is correctly persisted when switching back to form state from the editor - fixes the issue where the 'Create index pattern' checkbox would no longer be checked by default when switching back from the editor - adds functional tests for the data frame analytics wizard covering the case of switching to json editor and back to form Flaky test runner [build](https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/3558) ✅ 100/100 runs passed ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../advanced_step/advanced_step_form.tsx | 1 + .../create_analytics_advanced_editor.tsx | 64 ++++++++++--------- .../use_create_analytics_form/reducer.ts | 5 +- .../classification_creation.ts | 13 ++++ .../outlier_detection_creation.ts | 13 ++++ .../regression_creation.ts | 13 ++++ .../ml/data_frame_analytics_creation.ts | 34 +++++++++- 7 files changed, 109 insertions(+), 34 deletions(-) diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/advanced_step/advanced_step_form.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/advanced_step/advanced_step_form.tsx index 2521138a542d5..46351707a43c5 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/advanced_step/advanced_step_form.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/advanced_step/advanced_step_form.tsx @@ -248,6 +248,7 @@ export const AdvancedStepForm: FC = ({ randomizeSeed, softTreeDepthLimit, softTreeDepthTolerance, + useEstimatedMml, ]); const outlierDetectionAdvancedConfig = ( diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/create_analytics_advanced_editor/create_analytics_advanced_editor.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/create_analytics_advanced_editor/create_analytics_advanced_editor.tsx index c809597ed1208..dab0359457786 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/create_analytics_advanced_editor/create_analytics_advanced_editor.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/create_analytics_advanced_editor/create_analytics_advanced_editor.tsx @@ -139,38 +139,40 @@ export const CreateAnalyticsAdvancedEditor: FC = (prop )} style={{ maxWidth: '100%' }} > - + + wordWrap: 'on', + wrappingIndent: 'indent', + }} + /> + {advancedEditorMessages.map((advancedEditorMessage, i) => ( diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.ts index 5a3f26a63975e..69eececeba129 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/hooks/use_create_analytics_form/reducer.ts @@ -577,7 +577,9 @@ export function reducer(state: State, action: Action): State { const { jobConfig: config } = state; const { jobId } = state.form; // @ts-ignore - const formState = getFormStateFromJobConfig(config, false); + const formStateFromJobConfig = getFormStateFromJobConfig(config, false); + // Ensure previous form settings are persisted. Form state does not include any nested attributes. + const formState = { ...formStateFromJobConfig, ...state.form }; if (typeof jobId === 'string' && jobId.trim() !== '') { formState.jobId = jobId; @@ -605,7 +607,6 @@ export function reducer(state: State, action: Action): State { return validateForm({ ...state, - // @ts-ignore form: formState, isAdvancedEditorEnabled: false, advancedEditorRawString: JSON.stringify(config, null, 2), diff --git a/x-pack/test/functional/apps/ml/data_frame_analytics/classification_creation.ts b/x-pack/test/functional/apps/ml/data_frame_analytics/classification_creation.ts index 52da33a14c5ac..6dd953a84e4d0 100644 --- a/x-pack/test/functional/apps/ml/data_frame_analytics/classification_creation.ts +++ b/x-pack/test/functional/apps/ml/data_frame_analytics/classification_creation.ts @@ -89,6 +89,11 @@ export default function ({ getService }: FtrProviderContext) { isDependentVariableInput: true, }, ], + advancedEditorContent: [ + '{', + ` "description": "Classification job based on 'ft_bank_marketing' dataset with dependentVariable 'y' and trainingPercent '20'",`, + ' "source": {', + ], expected: { rocCurveColorState: [ // tick/grid/axis @@ -321,6 +326,14 @@ export default function ({ getService }: FtrProviderContext) { // - ⚠ Analysis fields await ml.dataFrameAnalyticsCreation.assertAllValidationCalloutsPresent(4); + // switch to json editor and back + await ml.testExecution.logTestStep('switches to advanced editor then back to form'); + await ml.dataFrameAnalyticsCreation.openAdvancedEditor(); + await ml.dataFrameAnalyticsCreation.assertAdvancedEditorCodeEditorContent( + testData.advancedEditorContent + ); + await ml.dataFrameAnalyticsCreation.closeAdvancedEditor(); + await ml.testExecution.logTestStep('continues to the create step'); await ml.dataFrameAnalyticsCreation.continueToCreateStep(); diff --git a/x-pack/test/functional/apps/ml/data_frame_analytics/outlier_detection_creation.ts b/x-pack/test/functional/apps/ml/data_frame_analytics/outlier_detection_creation.ts index e7a14abbebb65..8b4514add92cb 100644 --- a/x-pack/test/functional/apps/ml/data_frame_analytics/outlier_detection_creation.ts +++ b/x-pack/test/functional/apps/ml/data_frame_analytics/outlier_detection_creation.ts @@ -84,6 +84,11 @@ export default function ({ getService }: FtrProviderContext) { }, modelMemory: '5mb', createIndexPattern: true, + advancedEditorContent: [ + '{', + ' "description": "Outlier detection job based on ft_ihp_outlier dataset with runtime fields",', + ' "source": {', + ], expected: { histogramCharts: [ { chartAvailable: true, id: '1stFlrSF', legend: '334 - 4692' }, @@ -307,6 +312,14 @@ export default function ({ getService }: FtrProviderContext) { await ml.dataFrameAnalyticsCreation.assertValidationCalloutsExists(); await ml.dataFrameAnalyticsCreation.assertAllValidationCalloutsPresent(1); + // switch to json editor and back + await ml.testExecution.logTestStep('switches to advanced editor then back to form'); + await ml.dataFrameAnalyticsCreation.openAdvancedEditor(); + await ml.dataFrameAnalyticsCreation.assertAdvancedEditorCodeEditorContent( + testData.advancedEditorContent + ); + await ml.dataFrameAnalyticsCreation.closeAdvancedEditor(); + await ml.testExecution.logTestStep('continues to the create step'); await ml.dataFrameAnalyticsCreation.continueToCreateStep(); diff --git a/x-pack/test/functional/apps/ml/data_frame_analytics/regression_creation.ts b/x-pack/test/functional/apps/ml/data_frame_analytics/regression_creation.ts index fe4010264c621..b4ed75c35043a 100644 --- a/x-pack/test/functional/apps/ml/data_frame_analytics/regression_creation.ts +++ b/x-pack/test/functional/apps/ml/data_frame_analytics/regression_creation.ts @@ -91,6 +91,11 @@ export default function ({ getService }: FtrProviderContext) { trainingPercent: 20, modelMemory: '20mb', createIndexPattern: true, + advancedEditorContent: [ + '{', + ' "description": "Regression job based on ft_egs_regression dataset with runtime fields",', + ' "source": {', + ], expected: { scatterplotMatrixColorStats: [ // some marker colors of the continuous color scale @@ -322,6 +327,14 @@ export default function ({ getService }: FtrProviderContext) { await ml.dataFrameAnalyticsCreation.assertValidationCalloutsExists(); await ml.dataFrameAnalyticsCreation.assertAllValidationCalloutsPresent(3); + // switch to json editor and back + await ml.testExecution.logTestStep('switches to advanced editor then back to form'); + await ml.dataFrameAnalyticsCreation.openAdvancedEditor(); + await ml.dataFrameAnalyticsCreation.assertAdvancedEditorCodeEditorContent( + testData.advancedEditorContent + ); + await ml.dataFrameAnalyticsCreation.closeAdvancedEditor(); + await ml.testExecution.logTestStep('continues to the create step'); await ml.dataFrameAnalyticsCreation.continueToCreateStep(); diff --git a/x-pack/test/functional/services/ml/data_frame_analytics_creation.ts b/x-pack/test/functional/services/ml/data_frame_analytics_creation.ts index 43bb799a5a759..beedbb145dce4 100644 --- a/x-pack/test/functional/services/ml/data_frame_analytics_creation.ts +++ b/x-pack/test/functional/services/ml/data_frame_analytics_creation.ts @@ -54,8 +54,40 @@ export function MachineLearningDataFrameAnalyticsCreationProvider( await headerPage.waitUntilLoadingHasFinished(); }, + async assertAdvancedEditorCodeEditorExists() { + await testSubjects.existOrFail('mlAnalyticsCreateJobWizardAdvancedEditorCodeEditor', { + allowHidden: true, + }); + }, + + async assertAdvancedEditorCodeEditorContent(expectedContent: string[]) { + await this.assertAdvancedEditorCodeEditorExists(); + const wrapper = await testSubjects.find('mlAnalyticsCreateJobWizardAdvancedEditorCodeEditor'); + const editor = await wrapper.findByCssSelector('.monaco-editor .view-lines'); + const editorContentString = await editor.getVisibleText(); + const splicedAdvancedEditorValue = editorContentString.split('\n').splice(0, 3); + expect(splicedAdvancedEditorValue).to.eql( + expectedContent, + `Expected the first editor lines to be '${expectedContent}' (got '${splicedAdvancedEditorValue}')` + ); + }, + + async openAdvancedEditor() { + this.assertAdvancedEditorSwitchExists(); + await testSubjects.click('mlAnalyticsCreateJobWizardAdvancedEditorSwitch'); + this.assertAdvancedEditorSwitchCheckState(true); + this.assertAdvancedEditorCodeEditorExists(); + }, + + async closeAdvancedEditor() { + this.assertAdvancedEditorSwitchExists(); + await testSubjects.click('mlAnalyticsCreateJobWizardAdvancedEditorSwitch'); + this.assertAdvancedEditorSwitchCheckState(false); + await testSubjects.missingOrFail('mlAnalyticsCreateJobWizardAdvancedEditorCodeEditor'); + }, + async assertAdvancedEditorSwitchExists() { - await testSubjects.existOrFail(`mlAnalyticsCreateJobWizardAdvancedEditorSwitch`, { + await testSubjects.existOrFail('mlAnalyticsCreateJobWizardAdvancedEditorSwitch', { allowHidden: true, }); },