diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/sample_logs_input.test.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/sample_logs_input.test.tsx index af21526b7f14d..a137933afed3f 100644 --- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/sample_logs_input.test.tsx +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/sample_logs_input.test.tsx @@ -40,7 +40,7 @@ describe('SampleLogsInput', () => { describe('when uploading a json logs sample', () => { const type = 'application/json'; - describe('when the file is valid', () => { + describe('when the file is valid json', () => { const logsSampleRaw = `{"message":"test message 1"},{"message":"test message 2"}`; beforeEach(async () => { await changeFile(input, new File([`[${logsSampleRaw}]`], 'test.json', { type })); @@ -73,9 +73,11 @@ describe('SampleLogsInput', () => { describe('when the file is invalid', () => { describe.each([ - ['[{"message":"test message 1"}', `The logs sample file has not a valid ${type} format`], + [ + '[{"message":"test message 1"}', + 'Cannot parse the logs sample file as either a JSON or NDJSON file', + ], ['["test message 1"]', 'The logs sample file contains non-object entries'], - ['{"message":"test message 1"}', 'The logs sample file is not an array'], ['[]', 'The logs sample file is empty'], ])('with logs content %s', (logsSample, errorMessage) => { beforeEach(async () => { @@ -98,7 +100,7 @@ describe('SampleLogsInput', () => { describe('when setting a ndjson logs sample', () => { const type = 'application/x-ndjson'; - describe('when the file is valid', () => { + describe('when the file is valid ndjson', () => { const logsSampleRaw = `{"message":"test message 1"}\n{"message":"test message 2"}`; beforeEach(async () => { await changeFile(input, new File([logsSampleRaw], 'test.json', { type })); @@ -131,7 +133,10 @@ describe('SampleLogsInput', () => { describe('when the file is invalid', () => { describe.each([ - ['{"message":"test message 1"]', `The logs sample file has not a valid ${type} format`], + [ + '{"message":"test message 1"}\n{"message": }', + 'Cannot parse the logs sample file as either a JSON or NDJSON file', + ], ['"test message 1"', 'The logs sample file contains non-object entries'], ['', 'The logs sample file is empty'], ])('with logs content %s', (logsSample, errorMessage) => { diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/sample_logs_input.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/sample_logs_input.tsx index 072669a6bdd1d..cb4f735cc707c 100644 --- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/sample_logs_input.tsx +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/sample_logs_input.tsx @@ -19,24 +19,34 @@ const MaxLogsSampleRows = 10; * Parse the logs sample file content (json or ndjson) and return the parsed logs sample */ const parseLogsContent = ( - fileContent: string | undefined, - fileType: string + fileContent: string | undefined ): { error?: string; isTruncated?: boolean; logsSampleParsed?: string[] } => { if (fileContent == null) { return { error: i18n.LOGS_SAMPLE_ERROR.CAN_NOT_READ }; } let parsedContent; try { - if (fileType === 'application/json') { + parsedContent = fileContent + .split('\n') + .filter((line) => line.trim() !== '') + .map((line) => JSON.parse(line)); + + // Special case for files that can be parsed as both JSON and NDJSON: + // for a one-line array [] -> extract its contents + // for a one-line object {} -> do nothing + if ( + Array.isArray(parsedContent) && + parsedContent.length === 1 && + Array.isArray(parsedContent[0]) + ) { + parsedContent = parsedContent[0]; + } + } catch (parseNDJSONError) { + try { parsedContent = JSON.parse(fileContent); - } else if (fileType === 'application/x-ndjson') { - parsedContent = fileContent - .split('\n') - .filter((line) => line.trim() !== '') - .map((line) => JSON.parse(line)); + } catch (parseJSONError) { + return { error: i18n.LOGS_SAMPLE_ERROR.CAN_NOT_PARSE }; } - } catch (_) { - return { error: i18n.LOGS_SAMPLE_ERROR.FORMAT(fileType) }; } if (!Array.isArray(parsedContent)) { @@ -81,10 +91,7 @@ export const SampleLogsInput = React.memo(({ integrationSe const reader = new FileReader(); reader.onload = function (e) { const fileContent = e.target?.result as string | undefined; // We can safely cast to string since we call `readAsText` to load the file. - const { error, isTruncated, logsSampleParsed } = parseLogsContent( - fileContent, - logsSampleFile.type - ); + const { error, isTruncated, logsSampleParsed } = parseLogsContent(fileContent); setIsParsing(false); setSampleFileError(error); if (error) { @@ -137,7 +144,6 @@ export const SampleLogsInput = React.memo(({ integrationSe onChange={onChangeLogsSample} display="large" aria-label="Upload logs sample file" - accept="application/json,application/x-ndjson" isLoading={isParsing} data-test-subj="logsSampleFilePicker" data-loading={isParsing} diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/translations.ts b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/translations.ts index e4cc004e2673b..0af9f803f71fc 100644 --- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/translations.ts +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/translations.ts @@ -126,11 +126,12 @@ export const LOGS_SAMPLE_ERROR = { defaultMessage: 'Failed to read the logs sample file', } ), - FORMAT: (fileType: string) => - i18n.translate('xpack.integrationAssistant.step.dataStream.logsSample.errorFormat', { - values: { fileType }, - defaultMessage: 'The logs sample file has not a valid {fileType} format', - }), + CAN_NOT_PARSE: i18n.translate( + 'xpack.integrationAssistant.step.dataStream.logsSample.errorCanNotParse', + { + defaultMessage: 'Cannot parse the logs sample file as either a JSON or NDJSON file', + } + ), NOT_ARRAY: i18n.translate('xpack.integrationAssistant.step.dataStream.logsSample.errorNotArray', { defaultMessage: 'The logs sample file is not an array', }),