-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Enterprise Search] Basic DocumentCreation creation mode modal views (#…
…86056) * Add ApiCodeExample modal component - Previously lived in EngineOverview / Onboarding * Add basic PasteJsonText component * Add basic UploadJsonFile component * [Refactor] Have all modal components manage their own ModalHeader & ModalFooters - Per feedback from Casey + Update DocumentCreationModal to use switch * Set basic empty/disabled validation on ModalFooter continue buttons * Update x-pack/plugins/enterprise_search/public/applications/app_search/components/document_creation/creation_mode_components/api_code_example.tsx Co-authored-by: Jason Stoltzfus <jastoltz24@gmail.com> * [PR feedback] Typescript improvements * [PR feedback] Remove need for hasFile reducer - by storing either 1 file or null - which gets around the stored FileList reference not triggering a rerender/change Co-authored-by: Jason Stoltzfus <jastoltz24@gmail.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
- Loading branch information
1 parent
fc7ae0e
commit d73af32
Showing
15 changed files
with
830 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
...pp_search/components/document_creation/creation_mode_components/api_code_example.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
/* | ||
* 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 '../../../../__mocks__/enterprise_search_url.mock'; | ||
import { setMockValues, setMockActions } from '../../../../__mocks__/kea.mock'; | ||
|
||
import React from 'react'; | ||
import { shallow, ShallowWrapper } from 'enzyme'; | ||
import { EuiCode, EuiCodeBlock, EuiButtonEmpty } from '@elastic/eui'; | ||
|
||
import { ApiCodeExample, ModalHeader, ModalBody, ModalFooter } from './api_code_example'; | ||
|
||
describe('ApiCodeExample', () => { | ||
const values = { | ||
engineName: 'test-engine', | ||
engine: { apiKey: 'test-key' }, | ||
}; | ||
const actions = { | ||
closeDocumentCreation: jest.fn(), | ||
}; | ||
|
||
beforeAll(() => { | ||
setMockValues(values); | ||
setMockActions(actions); | ||
}); | ||
|
||
it('renders', () => { | ||
const wrapper = shallow(<ApiCodeExample />); | ||
expect(wrapper.find(ModalHeader)).toHaveLength(1); | ||
expect(wrapper.find(ModalBody)).toHaveLength(1); | ||
expect(wrapper.find(ModalFooter)).toHaveLength(1); | ||
}); | ||
|
||
describe('ModalHeader', () => { | ||
it('renders', () => { | ||
const wrapper = shallow(<ModalHeader />); | ||
expect(wrapper.find('h2').text()).toEqual('Indexing by API'); | ||
}); | ||
}); | ||
|
||
describe('ModalBody', () => { | ||
let wrapper: ShallowWrapper; | ||
|
||
beforeAll(() => { | ||
wrapper = shallow(<ModalBody />); | ||
}); | ||
|
||
it('renders with the full remote Enterprise Search API URL', () => { | ||
expect(wrapper.find(EuiCode).dive().dive().text()).toEqual( | ||
'http://localhost:3002/api/as/v1/engines/test-engine/documents' | ||
); | ||
expect(wrapper.find(EuiCodeBlock).dive().dive().text()).toEqual( | ||
expect.stringContaining('http://localhost:3002/api/as/v1/engines/test-engine/documents') | ||
); | ||
}); | ||
|
||
it('renders with the API key', () => { | ||
expect(wrapper.find(EuiCodeBlock).dive().dive().text()).toEqual( | ||
expect.stringContaining('test-key') | ||
); | ||
}); | ||
}); | ||
|
||
describe('ModalFooter', () => { | ||
it('closes the modal', () => { | ||
const wrapper = shallow(<ModalFooter />); | ||
|
||
wrapper.find(EuiButtonEmpty).simulate('click'); | ||
expect(actions.closeDocumentCreation).toHaveBeenCalled(); | ||
}); | ||
}); | ||
}); |
128 changes: 128 additions & 0 deletions
128
...ons/app_search/components/document_creation/creation_mode_components/api_code_example.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
/* | ||
* 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 dedent from 'dedent'; | ||
import React from 'react'; | ||
import { useValues, useActions } from 'kea'; | ||
|
||
import { i18n } from '@kbn/i18n'; | ||
import { FormattedMessage } from '@kbn/i18n/react'; | ||
import { | ||
EuiModalHeader, | ||
EuiModalHeaderTitle, | ||
EuiModalBody, | ||
EuiModalFooter, | ||
EuiButtonEmpty, | ||
EuiText, | ||
EuiLink, | ||
EuiSpacer, | ||
EuiPanel, | ||
EuiBadge, | ||
EuiCode, | ||
EuiCodeBlock, | ||
} from '@elastic/eui'; | ||
|
||
import { getEnterpriseSearchUrl } from '../../../../shared/enterprise_search_url'; | ||
import { EngineLogic } from '../../engine'; | ||
import { EngineDetails } from '../../engine/types'; | ||
|
||
import { DOCS_PREFIX } from '../../../routes'; | ||
import { DOCUMENTS_API_JSON_EXAMPLE, MODAL_CANCEL_BUTTON } from '../constants'; | ||
import { DocumentCreationLogic } from '../'; | ||
|
||
export const ApiCodeExample: React.FC = () => ( | ||
<> | ||
<ModalHeader /> | ||
<ModalBody /> | ||
<ModalFooter /> | ||
</> | ||
); | ||
|
||
export const ModalHeader: React.FC = () => { | ||
return ( | ||
<EuiModalHeader> | ||
<EuiModalHeaderTitle> | ||
<h2> | ||
{i18n.translate('xpack.enterpriseSearch.appSearch.documentCreation.api.title', { | ||
defaultMessage: 'Indexing by API', | ||
})} | ||
</h2> | ||
</EuiModalHeaderTitle> | ||
</EuiModalHeader> | ||
); | ||
}; | ||
|
||
export const ModalBody: React.FC = () => { | ||
const { engineName, engine } = useValues(EngineLogic); | ||
const { apiKey } = engine as EngineDetails; | ||
|
||
const documentsApiUrl = getEnterpriseSearchUrl(`/api/as/v1/engines/${engineName}/documents`); | ||
|
||
return ( | ||
<EuiModalBody> | ||
<EuiText color="subdued"> | ||
<p> | ||
<FormattedMessage | ||
id="xpack.enterpriseSearch.appSearch.documentCreation.api.description" | ||
defaultMessage="The {documentsApiLink} can be used to add new documents to your engine, update documents, retrieve documents by id, and delete documents. There are a variety of {clientLibrariesLink} to help you get started." | ||
values={{ | ||
documentsApiLink: ( | ||
<EuiLink target="_blank" href={`${DOCS_PREFIX}/indexing-documents-guide.html`}> | ||
documents API | ||
</EuiLink> | ||
), | ||
clientLibrariesLink: ( | ||
<EuiLink target="_blank" href={`${DOCS_PREFIX}/api-clients.html`}> | ||
client libraries | ||
</EuiLink> | ||
), | ||
}} | ||
/> | ||
</p> | ||
<p> | ||
{i18n.translate('xpack.enterpriseSearch.appSearch.documentCreation.api.example', { | ||
defaultMessage: | ||
'To see the API in action, you can experiment with the example request below using a command line or a client library.', | ||
})} | ||
</p> | ||
</EuiText> | ||
<EuiSpacer /> | ||
<EuiPanel hasShadow={false} paddingSize="s" className="eui-textBreakAll"> | ||
<EuiBadge color="primary">POST</EuiBadge> | ||
<EuiCode transparentBackground>{documentsApiUrl}</EuiCode> | ||
</EuiPanel> | ||
<EuiCodeBlock language="bash" fontSize="m" isCopyable> | ||
{dedent(` | ||
curl -X POST '${documentsApiUrl}' | ||
-H 'Content-Type: application/json' | ||
-H 'Authorization: Bearer ${apiKey}' | ||
-d '${DOCUMENTS_API_JSON_EXAMPLE}' | ||
# Returns | ||
# [ | ||
# { | ||
# "id": "park_rocky-mountain", | ||
# "errors": [] | ||
# }, | ||
# { | ||
# "id": "park_saguaro", | ||
# "errors": [] | ||
# } | ||
# ] | ||
`)} | ||
</EuiCodeBlock> | ||
</EuiModalBody> | ||
); | ||
}; | ||
|
||
export const ModalFooter: React.FC = () => { | ||
const { closeDocumentCreation } = useActions(DocumentCreationLogic); | ||
|
||
return ( | ||
<EuiModalFooter> | ||
<EuiButtonEmpty onClick={closeDocumentCreation}>{MODAL_CANCEL_BUTTON}</EuiButtonEmpty> | ||
</EuiModalFooter> | ||
); | ||
}; |
10 changes: 10 additions & 0 deletions
10
...ic/applications/app_search/components/document_creation/creation_mode_components/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
/* | ||
* 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. | ||
*/ | ||
|
||
export { ShowCreationModes } from './show_creation_modes'; | ||
export { ApiCodeExample } from './api_code_example'; | ||
export { PasteJsonText } from './paste_json_text'; | ||
export { UploadJsonFile } from './upload_json_file'; |
9 changes: 9 additions & 0 deletions
9
...ons/app_search/components/document_creation/creation_mode_components/paste_json_text.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/* | ||
* 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. | ||
*/ | ||
|
||
.pasteJsonTextArea { | ||
font-family: $euiCodeFontFamily; | ||
} |
80 changes: 80 additions & 0 deletions
80
...app_search/components/document_creation/creation_mode_components/paste_json_text.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
/* | ||
* 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__'; | ||
|
||
import React from 'react'; | ||
import { shallow } from 'enzyme'; | ||
import { EuiTextArea, EuiButtonEmpty, EuiButton } from '@elastic/eui'; | ||
|
||
import { PasteJsonText, ModalHeader, ModalBody, ModalFooter } from './paste_json_text'; | ||
|
||
describe('PasteJsonText', () => { | ||
const values = { | ||
textInput: 'hello world', | ||
configuredLimits: { | ||
engine: { | ||
maxDocumentByteSize: 102400, | ||
}, | ||
}, | ||
}; | ||
const actions = { | ||
setTextInput: jest.fn(), | ||
closeDocumentCreation: jest.fn(), | ||
}; | ||
|
||
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
setMockValues(values); | ||
setMockActions(actions); | ||
}); | ||
|
||
it('renders', () => { | ||
const wrapper = shallow(<PasteJsonText />); | ||
expect(wrapper.find(ModalHeader)).toHaveLength(1); | ||
expect(wrapper.find(ModalBody)).toHaveLength(1); | ||
expect(wrapper.find(ModalFooter)).toHaveLength(1); | ||
}); | ||
|
||
describe('ModalHeader', () => { | ||
it('renders', () => { | ||
const wrapper = shallow(<ModalHeader />); | ||
expect(wrapper.find('h2').text()).toEqual('Create documents'); | ||
}); | ||
}); | ||
|
||
describe('ModalBody', () => { | ||
it('renders and updates the textarea value', () => { | ||
setMockValues({ ...values, textInput: 'lorem ipsum' }); | ||
const wrapper = shallow(<ModalBody />); | ||
const textarea = wrapper.find(EuiTextArea); | ||
|
||
expect(textarea.prop('value')).toEqual('lorem ipsum'); | ||
|
||
textarea.simulate('change', { target: { value: 'dolor sit amet' } }); | ||
expect(actions.setTextInput).toHaveBeenCalledWith('dolor sit amet'); | ||
}); | ||
}); | ||
|
||
describe('ModalFooter', () => { | ||
it('closes the modal', () => { | ||
const wrapper = shallow(<ModalFooter />); | ||
|
||
wrapper.find(EuiButtonEmpty).simulate('click'); | ||
expect(actions.closeDocumentCreation).toHaveBeenCalled(); | ||
}); | ||
|
||
it('disables/enables the Continue button based on whether text has been entered', () => { | ||
const wrapper = shallow(<ModalFooter />); | ||
expect(wrapper.find(EuiButton).prop('isDisabled')).toBe(false); | ||
|
||
setMockValues({ ...values, textInput: '' }); | ||
rerender(wrapper); | ||
expect(wrapper.find(EuiButton).prop('isDisabled')).toBe(true); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.