Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,34 @@ export const FLYOUT_CONTINUE_BUTTON = i18n.translate(
'xpack.enterpriseSearch.appSearch.documentCreation.flyoutContinue',
{ defaultMessage: 'Continue' }
);
export const FLYOUT_CLOSE_BUTTON = i18n.translate(
'xpack.enterpriseSearch.appSearch.documentCreation.modalClose',
{ defaultMessage: 'Close' }
);

export const DOCUMENT_CREATION_ERRORS = {
TITLE: i18n.translate('xpack.enterpriseSearch.appSearch.documentCreation.errorsTitle', {
defaultMessage: 'Something went wrong. Please address the errors and try again.',
}),
NO_FILE: i18n.translate('xpack.enterpriseSearch.appSearch.documentCreation.noFileFound', {
defaultMessage: 'No file found.',
}),
NO_VALID_FILE: i18n.translate('xpack.enterpriseSearch.appSearch.documentCreation.noValidFile', {
defaultMessage: 'Problem parsing file.',
}),
NOT_VALID: i18n.translate('xpack.enterpriseSearch.appSearch.documentCreation.notValidJson', {
defaultMessage: 'Document contents must be a valid JSON array or object.',
}),
};
export const DOCUMENT_CREATION_WARNINGS = {
TITLE: i18n.translate('xpack.enterpriseSearch.appSearch.documentCreation.warningsTitle', {
defaultMessage: 'Warning!',
}),
LARGE_FILE: i18n.translate('xpack.enterpriseSearch.appSearch.documentCreation.largeFile', {
defaultMessage:
"You're uploading an extremely large file. This could potentially lock your browser, or take a very long time to process. If possible, try splitting your data up into multiple smaller files.",
}),
};

// This is indented the way it is to work with ApiCodeExample.
// Use dedent() when calling this alone
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@ import React from 'react';
import { shallow } from 'enzyme';
import { EuiTextArea, EuiButtonEmpty, EuiButton } from '@elastic/eui';

import { Errors } from '../creation_response_components';
import { PasteJsonText, FlyoutHeader, FlyoutBody, FlyoutFooter } from './paste_json_text';

describe('PasteJsonText', () => {
const values = {
textInput: 'hello world',
isUploading: false,
errors: [],
configuredLimits: {
engine: {
maxDocumentByteSize: 102400,
Expand All @@ -24,6 +27,7 @@ describe('PasteJsonText', () => {
};
const actions = {
setTextInput: jest.fn(),
onSubmitJson: jest.fn(),
closeDocumentCreation: jest.fn(),
};

Expand Down Expand Up @@ -58,6 +62,16 @@ describe('PasteJsonText', () => {
textarea.simulate('change', { target: { value: 'dolor sit amet' } });
expect(actions.setTextInput).toHaveBeenCalledWith('dolor sit amet');
});

it('shows an error banner and sets invalid form props if errors exist', () => {
const wrapper = shallow(<FlyoutBody />);
expect(wrapper.find(EuiTextArea).prop('isInvalid')).toBe(false);

setMockValues({ ...values, errors: ['some error'] });
rerender(wrapper);
expect(wrapper.find(EuiTextArea).prop('isInvalid')).toBe(true);
expect(wrapper.prop('banner').type).toEqual(Errors);
});
});

describe('FlyoutFooter', () => {
Expand All @@ -68,6 +82,13 @@ describe('PasteJsonText', () => {
expect(actions.closeDocumentCreation).toHaveBeenCalled();
});

it('submits json', () => {
const wrapper = shallow(<FlyoutFooter />);

wrapper.find(EuiButton).simulate('click');
expect(actions.onSubmitJson).toHaveBeenCalled();
});

it('disables/enables the Continue button based on whether text has been entered', () => {
const wrapper = shallow(<FlyoutFooter />);
expect(wrapper.find(EuiButton).prop('isDisabled')).toBe(false);
Expand All @@ -76,5 +97,14 @@ describe('PasteJsonText', () => {
rerender(wrapper);
expect(wrapper.find(EuiButton).prop('isDisabled')).toBe(true);
});

it('sets isLoading based on isUploading', () => {
const wrapper = shallow(<FlyoutFooter />);
expect(wrapper.find(EuiButton).prop('isLoading')).toBe(false);

setMockValues({ ...values, isUploading: true });
rerender(wrapper);
expect(wrapper.find(EuiButton).prop('isLoading')).toBe(true);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
import { AppLogic } from '../../../app_logic';

import { FLYOUT_ARIA_LABEL_ID, FLYOUT_CANCEL_BUTTON, FLYOUT_CONTINUE_BUTTON } from '../constants';
import { Errors } from '../creation_response_components';
import { DocumentCreationLogic } from '../';

import './paste_json_text.scss';
Expand Down Expand Up @@ -55,11 +56,11 @@ export const FlyoutBody: React.FC = () => {
const { configuredLimits } = useValues(AppLogic);
const maxDocumentByteSize = configuredLimits?.engine?.maxDocumentByteSize;

const { textInput } = useValues(DocumentCreationLogic);
const { textInput, errors } = useValues(DocumentCreationLogic);
const { setTextInput } = useActions(DocumentCreationLogic);

return (
<EuiFlyoutBody>
<EuiFlyoutBody banner={<Errors />}>
<EuiText color="subdued">
<p>
{i18n.translate(
Expand All @@ -76,6 +77,7 @@ export const FlyoutBody: React.FC = () => {
<EuiTextArea
value={textInput}
onChange={(e) => setTextInput(e.target.value)}
isInvalid={errors.length > 0}
aria-label={i18n.translate(
'xpack.enterpriseSearch.appSearch.documentCreation.pasteJsonText.label',
{ defaultMessage: 'Paste JSON here' }
Expand All @@ -89,8 +91,8 @@ export const FlyoutBody: React.FC = () => {
};

export const FlyoutFooter: React.FC = () => {
const { textInput } = useValues(DocumentCreationLogic);
const { closeDocumentCreation } = useActions(DocumentCreationLogic);
const { textInput, isUploading } = useValues(DocumentCreationLogic);
const { onSubmitJson, closeDocumentCreation } = useActions(DocumentCreationLogic);

return (
<EuiFlyoutFooter>
Expand All @@ -99,7 +101,7 @@ export const FlyoutFooter: React.FC = () => {
<EuiButtonEmpty onClick={closeDocumentCreation}>{FLYOUT_CANCEL_BUTTON}</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton fill isDisabled={!textInput.length}>
<EuiButton fill onClick={onSubmitJson} isLoading={isUploading} isDisabled={!textInput}>
{FLYOUT_CONTINUE_BUTTON}
</EuiButton>
</EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
/*
* 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 { setMockValues, setMockActions } from '../../../../__mocks__/kea.mock';
import { rerender } from '../../../../__mocks__';
Expand All @@ -16,12 +11,15 @@ import React from 'react';
import { shallow } from 'enzyme';
import { EuiFilePicker, EuiButtonEmpty, EuiButton } from '@elastic/eui';

import { Errors } from '../creation_response_components';
import { UploadJsonFile, FlyoutHeader, FlyoutBody, FlyoutFooter } from './upload_json_file';

describe('UploadJsonFile', () => {
const mockFile = new File(['mock'], 'mock.json', { type: 'application/json' });
const values = {
fileInput: null,
isUploading: false,
errors: [],
configuredLimits: {
engine: {
maxDocumentByteSize: 102400,
Expand All @@ -30,6 +28,7 @@ describe('UploadJsonFile', () => {
};
const actions = {
setFileInput: jest.fn(),
onSubmitFile: jest.fn(),
closeDocumentCreation: jest.fn(),
};

Expand Down Expand Up @@ -63,6 +62,25 @@ describe('UploadJsonFile', () => {
wrapper.find(EuiFilePicker).simulate('change', []);
expect(actions.setFileInput).toHaveBeenCalledWith(null);
});

it('sets isLoading based on isUploading', () => {
const wrapper = shallow(<FlyoutBody />);
expect(wrapper.find(EuiFilePicker).prop('isLoading')).toBe(false);

setMockValues({ ...values, isUploading: true });
rerender(wrapper);
expect(wrapper.find(EuiFilePicker).prop('isLoading')).toBe(true);
});

it('shows an error banner and sets invalid form props if errors exist', () => {
const wrapper = shallow(<FlyoutBody />);
expect(wrapper.find(EuiFilePicker).prop('isInvalid')).toBe(false);

setMockValues({ ...values, errors: ['some error'] });
rerender(wrapper);
expect(wrapper.find(EuiFilePicker).prop('isInvalid')).toBe(true);
expect(wrapper.prop('banner').type).toEqual(Errors);
});
});

describe('FlyoutFooter', () => {
Expand All @@ -73,6 +91,13 @@ describe('UploadJsonFile', () => {
expect(actions.closeDocumentCreation).toHaveBeenCalled();
});

it('submits the json file', () => {
const wrapper = shallow(<FlyoutFooter />);

wrapper.find(EuiButton).simulate('click');
expect(actions.onSubmitFile).toHaveBeenCalled();
});

it('disables/enables the Continue button based on whether files have been uploaded', () => {
const wrapper = shallow(<FlyoutFooter />);
expect(wrapper.find(EuiButton).prop('isDisabled')).toBe(true);
Expand All @@ -81,5 +106,14 @@ describe('UploadJsonFile', () => {
rerender(wrapper);
expect(wrapper.find(EuiButton).prop('isDisabled')).toBe(true);
});

it('sets isLoading based on isUploading', () => {
const wrapper = shallow(<FlyoutFooter />);
expect(wrapper.find(EuiButton).prop('isLoading')).toBe(false);

setMockValues({ ...values, isUploading: true });
rerender(wrapper);
expect(wrapper.find(EuiButton).prop('isLoading')).toBe(true);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
/*
* 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 from 'react';
import { useValues, useActions } from 'kea';
Expand All @@ -30,6 +25,7 @@ import {
import { AppLogic } from '../../../app_logic';

import { FLYOUT_ARIA_LABEL_ID, FLYOUT_CANCEL_BUTTON, FLYOUT_CONTINUE_BUTTON } from '../constants';
import { Errors } from '../creation_response_components';
import { DocumentCreationLogic } from '../';

export const UploadJsonFile: React.FC = () => (
Expand Down Expand Up @@ -59,10 +55,11 @@ export const FlyoutBody: React.FC = () => {
const { configuredLimits } = useValues(AppLogic);
const maxDocumentByteSize = configuredLimits?.engine?.maxDocumentByteSize;

const { isUploading, errors } = useValues(DocumentCreationLogic);
const { setFileInput } = useActions(DocumentCreationLogic);

return (
<EuiFlyoutBody>
<EuiFlyoutBody banner={<Errors />}>
<EuiText color="subdued">
<p>
{i18n.translate(
Expand All @@ -80,14 +77,16 @@ export const FlyoutBody: React.FC = () => {
onChange={(files) => setFileInput(files?.length ? files[0] : null)}
accept="application/json"
fullWidth
isLoading={isUploading}
isInvalid={errors.length > 0}
/>
</EuiFlyoutBody>
);
};

export const FlyoutFooter: React.FC = () => {
const { fileInput } = useValues(DocumentCreationLogic);
const { closeDocumentCreation } = useActions(DocumentCreationLogic);
const { fileInput, isUploading } = useValues(DocumentCreationLogic);
const { onSubmitFile, closeDocumentCreation } = useActions(DocumentCreationLogic);

return (
<EuiFlyoutFooter>
Expand All @@ -96,7 +95,7 @@ export const FlyoutFooter: React.FC = () => {
<EuiButtonEmpty onClick={closeDocumentCreation}>{FLYOUT_CANCEL_BUTTON}</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton fill isDisabled={!fileInput}>
<EuiButton fill onClick={onSubmitFile} isLoading={isUploading} isDisabled={!fileInput}>
{FLYOUT_CONTINUE_BUTTON}
</EuiButton>
</EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* 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 { setMockValues } from '../../../../__mocks__/kea.mock';

import React from 'react';
import { shallow } from 'enzyme';
import { EuiCallOut } from '@elastic/eui';

import { Errors } from './';

describe('Errors', () => {
it('does not render if no errors or warnings to render', () => {
setMockValues({ errors: [], warnings: [] });
const wrapper = shallow(<Errors />);

expect(wrapper.find(EuiCallOut)).toHaveLength(0);
});

it('renders errors', () => {
setMockValues({ errors: ['error 1', 'error 2'], warnings: [] });
const wrapper = shallow(<Errors />);

expect(wrapper.find(EuiCallOut)).toHaveLength(1);
expect(wrapper.find(EuiCallOut).prop('title')).toEqual(
'Something went wrong. Please address the errors and try again.'
);
expect(wrapper.find('p').first().text()).toEqual('error 1');
expect(wrapper.find('p').last().text()).toEqual('error 2');
});

it('renders warnings', () => {
setMockValues({ errors: [], warnings: ['document size warning'] });
const wrapper = shallow(<Errors />);

expect(wrapper.find(EuiCallOut)).toHaveLength(1);
expect(wrapper.find(EuiCallOut).prop('title')).toEqual('Warning!');
expect(wrapper.find('p').text()).toEqual('document size warning');
});

it('renders both errors and warnings', () => {
setMockValues({ errors: ['some error'], warnings: ['some warning'] });
const wrapper = shallow(<Errors />);

expect(wrapper.find(EuiCallOut)).toHaveLength(2);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* 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 from 'react';
import { useValues } from 'kea';

import { EuiCallOut } from '@elastic/eui';

import { DOCUMENT_CREATION_ERRORS, DOCUMENT_CREATION_WARNINGS } from '../constants';
import { DocumentCreationLogic } from '../';

export const Errors: React.FC = () => {
const { errors, warnings } = useValues(DocumentCreationLogic);

return (
<>
{errors.length > 0 && (
<EuiCallOut color="danger" iconType="alert" title={DOCUMENT_CREATION_ERRORS.TITLE}>
{errors.map((message, index) => (
<p key={index}>{message}</p>
))}
</EuiCallOut>
)}
{warnings.length > 0 && (
<EuiCallOut color="warning" iconType="alert" title={DOCUMENT_CREATION_WARNINGS.TITLE}>
{warnings.map((message, index) => (
<p key={index}>{message}</p>
))}
</EuiCallOut>
)}
</>
);
};
Loading