Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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