-
Notifications
You must be signed in to change notification settings - Fork 8.5k
[Enterprise Search] Added a Credentials page to App Search #79749
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
JasonStoltz
merged 30 commits into
elastic:master
from
JasonStoltz:JasonStoltz/credentials-view
Oct 8, 2020
Merged
Changes from 4 commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
3a0c9b2
Revert "Temporarily remove Layout from App Search plugin for 7.10 rel…
constancecchen 53ace58
Added a Credentials route and link
JasonStoltz 6c352b8
Added Credentials Page
JasonStoltz 9434cc8
Added Credentials List
JasonStoltz 09e7d93
Merge branch 'master' into JasonStoltz/credentials-view
JasonStoltz c010b8a
Implement feedback items:
JasonStoltz e659382
Remove unused imports
JasonStoltz 2c9a99a
PR Feedback
JasonStoltz 91c4ff8
Add reusable shallow unmount helper
cee-chen 714da22
Simplify Kea test mocks
cee-chen 4917cbb
Switch to ApiTokenTypes
JasonStoltz 280b2f7
Apply suggestions from code review
JasonStoltz 30c52a7
Use ApiTokenTypes for IApiToken
JasonStoltz 343290e
PR Feedback
JasonStoltz 9e6b0c4
We can lose these CSS classes...
JasonStoltz 564737a
I think we can rewrite this return flow
JasonStoltz 7caf342
Missed a ApiTokenTypes issue
JasonStoltz c52c139
Do we want to write a test file for this?
JasonStoltz 593a3a2
PR Feedback
JasonStoltz 53865ce
Super exciting proposal here
JasonStoltz 5d0ab10
Feedback
JasonStoltz b82eb10
Update x-pack/plugins/enterprise_search/public/applications/__mocks__…
JasonStoltz f653187
Apply suggestions from code review
JasonStoltz a30f8d5
nit - may as well keep EUI imports together
JasonStoltz 49570d4
Just an idea / me going all #microperf here
JasonStoltz f41a356
Remove shallow_usememo
JasonStoltz d2e21d7
Apply suggestions from code review
JasonStoltz a0ff646
More feedback
JasonStoltz bfd75d8
mockKea simplifying
cee-chen 473c1d2
Merge branch 'master' into JasonStoltz/credentials-view
JasonStoltz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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
86 changes: 86 additions & 0 deletions
86
...erprise_search/public/applications/app_search/components/credentials/credentials.test.tsx
This file contains hidden or 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,86 @@ | ||
| /* | ||
| * 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__/kea.mock'; | ||
| import '../../../__mocks__/shallow_useeffect.mock'; | ||
|
|
||
| import React, { useEffect } from 'react'; | ||
| import { shallow } from 'enzyme'; | ||
| import { useValues, useActions } from 'kea'; | ||
|
|
||
| import { Credentials } from './credentials'; | ||
| import { EuiCopy, EuiPageContentBody } from '@elastic/eui'; | ||
|
|
||
| import { externalUrl } from '../../../shared/enterprise_search_url'; | ||
|
|
||
| const getUseEffectUnmountHandler = () => (useEffect as jest.Mock).mock.calls[0][0](); | ||
|
|
||
| describe('Credentials', () => { | ||
| const mockKea = ({ values = {}, actions = {} }) => { | ||
| const mergedValues = { | ||
| dataLoading: false, | ||
| ...values, | ||
| }; | ||
|
|
||
| const mergedActions = { | ||
| initializeCredentialsData: jest.fn, | ||
| ...actions, | ||
| }; | ||
|
|
||
| (useValues as jest.Mock).mockImplementationOnce(() => mergedValues); | ||
| (useActions as jest.Mock).mockImplementationOnce(() => mergedActions); | ||
| }; | ||
|
|
||
| beforeEach(() => { | ||
| jest.clearAllMocks(); | ||
| }); | ||
cee-chen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| it('renders', () => { | ||
| mockKea({}); | ||
| const wrapper = shallow(<Credentials />); | ||
| expect(wrapper.find(EuiPageContentBody)).toHaveLength(1); | ||
| }); | ||
|
|
||
| it('initializes data on mount', () => { | ||
| const initializeCredentialsData = jest.fn(); | ||
| mockKea({ actions: { initializeCredentialsData } }); | ||
| shallow(<Credentials />); | ||
| expect(initializeCredentialsData).toHaveBeenCalledTimes(1); | ||
| }); | ||
|
|
||
| it('calls resetCredentials on unmount', () => { | ||
| const resetCredentials = jest.fn(); | ||
| mockKea({ actions: { resetCredentials } }); | ||
| shallow(<Credentials />); | ||
| const unmountHandler = getUseEffectUnmountHandler(); | ||
| unmountHandler(); | ||
| expect(resetCredentials).toHaveBeenCalledTimes(1); | ||
| }); | ||
|
|
||
| it('renders nothing if data is still loading', () => { | ||
| mockKea({ values: { dataLoading: true } }); | ||
| const wrapper = shallow(<Credentials />); | ||
| expect(wrapper.find(EuiPageContentBody)).toHaveLength(0); | ||
| }); | ||
|
|
||
| it('renders the API endpoint and a button to copy it', () => { | ||
| externalUrl.enterpriseSearchUrl = 'http://localhost:3002'; | ||
| mockKea({}); | ||
| const copyMock = jest.fn(); | ||
| const wrapper = shallow(<Credentials />); | ||
| const copyEl = shallow(wrapper.find(EuiCopy).props().children(copyMock)); | ||
| expect(copyEl.find('EuiButtonIcon').props().onClick).toEqual(copyMock); | ||
| expect(copyEl.find('span').text()).toEqual('http://localhost:3002'); | ||
JasonStoltz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| }); | ||
|
|
||
| it('will show the Crendentials Flyout when the Create API Key button is pressed', () => { | ||
| const showCredentialsForm = jest.fn(); | ||
| mockKea({ actions: { showCredentialsForm } }); | ||
| const wrapper = shallow(<Credentials />); | ||
| const button: any = wrapper.find('[data-test-subj="CreateAPIKeyButton"]'); | ||
| button.props().onClick(); | ||
| expect(showCredentialsForm).toHaveBeenCalledTimes(1); | ||
| }); | ||
| }); | ||
146 changes: 146 additions & 0 deletions
146
...s/enterprise_search/public/applications/app_search/components/credentials/credentials.tsx
This file contains hidden or 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,146 @@ | ||
| /* | ||
| * 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, { useEffect } from 'react'; | ||
| import { useActions, useValues } from 'kea'; | ||
|
|
||
| import { | ||
| EuiPageHeader, | ||
| EuiPageHeaderSection, | ||
| EuiTitle, | ||
| EuiPageContentBody, | ||
| EuiFlexGroup, | ||
| EuiFlexItem, | ||
| EuiPanel, | ||
| EuiCopy, | ||
| EuiButtonIcon, | ||
| EuiSpacer, | ||
| EuiButton, | ||
| } from '@elastic/eui'; | ||
| import { i18n } from '@kbn/i18n'; | ||
|
|
||
| import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; | ||
| import { | ||
| CredentialsLogic, | ||
| ICredentialsLogicActions, | ||
| ICredentialsLogicValues, | ||
| } from './credentials_logic'; | ||
cee-chen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| import { externalUrl } from '../../../shared/enterprise_search_url/external_url'; | ||
| import { CredentialsList } from './credentials_list'; | ||
|
|
||
| export const Credentials: React.FC = () => { | ||
| const { initializeCredentialsData, resetCredentials, showCredentialsForm } = useActions( | ||
| CredentialsLogic | ||
| ) as ICredentialsLogicActions; | ||
|
|
||
| const { dataLoading } = useValues(CredentialsLogic) as ICredentialsLogicValues; | ||
cee-chen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| useEffect(() => { | ||
| initializeCredentialsData(); | ||
| return () => { | ||
| resetCredentials(); | ||
| }; | ||
| }, []); | ||
|
|
||
| // TODO | ||
| // if (dataLoading) { return <Loading /> } | ||
| if (dataLoading) { | ||
| return null; | ||
| } | ||
| return ( | ||
| <> | ||
| <SetPageChrome | ||
| trail={[ | ||
| i18n.translate('xpack.enterpriseSearch.appSearch.credentials.title', { | ||
| defaultMessage: 'Credentials', | ||
| }), | ||
| ]} | ||
| /> | ||
| <EuiPageHeader> | ||
| <EuiPageHeaderSection> | ||
| <EuiTitle size="l"> | ||
| <h1> | ||
| {i18n.translate('xpack.enterpriseSearch.appSearch.credentials.title', { | ||
| defaultMessage: 'Credentials', | ||
| })} | ||
| </h1> | ||
| </EuiTitle> | ||
| </EuiPageHeaderSection> | ||
| </EuiPageHeader> | ||
| <EuiPageContentBody> | ||
| <EuiFlexGroup> | ||
| <EuiFlexItem> | ||
cee-chen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| <EuiPanel style={{ textAlign: 'center' }}> | ||
cee-chen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| <EuiTitle size="s"> | ||
| <h2> | ||
| {i18n.translate('xpack.enterpriseSearch.appSearch.credentials.apiEndpoint', { | ||
| defaultMessage: 'Endpoint', | ||
| })} | ||
| </h2> | ||
| </EuiTitle> | ||
| <EuiCopy | ||
| textToCopy={externalUrl.enterpriseSearchUrl} | ||
| afterMessage={i18n.translate( | ||
| 'xpack.enterpriseSearch.appSearch.credentials.copied', | ||
| { | ||
| defaultMessage: 'Copied', | ||
| } | ||
| )} | ||
| > | ||
| {(copy) => ( | ||
| <div> | ||
cee-chen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| <EuiButtonIcon | ||
| onClick={copy} | ||
| iconType="copyClipboard" | ||
| aria-label={i18n.translate( | ||
| 'xpack.enterpriseSearch.appSearch.credentials.copyApiEndpoint', | ||
| { | ||
| defaultMessage: 'Copy API Endpoint to clipboard.', | ||
| } | ||
| )} | ||
| /> | ||
| <span>{externalUrl.enterpriseSearchUrl}</span> | ||
| </div> | ||
cee-chen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| )} | ||
| </EuiCopy> | ||
| </EuiPanel> | ||
| </EuiFlexItem> | ||
| </EuiFlexGroup> | ||
| <EuiSpacer size="xxl" /> | ||
| <EuiFlexGroup> | ||
| <EuiFlexItem> | ||
cee-chen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| <EuiTitle size="m"> | ||
| <h2> | ||
| {i18n.translate('xpack.enterpriseSearch.appSearch.credentials.apiKeys', { | ||
| defaultMessage: 'API Keys', | ||
| })} | ||
| </h2> | ||
| </EuiTitle> | ||
| </EuiFlexItem> | ||
| <EuiFlexItem grow={false}> | ||
cee-chen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| <EuiButton | ||
| color="primary" | ||
| data-test-subj="CreateAPIKeyButton" | ||
| fill={true} | ||
| onClick={() => showCredentialsForm()} | ||
| > | ||
| {i18n.translate('xpack.enterpriseSearch.appSearch.credentials.createKey', { | ||
| defaultMessage: 'Create a key', | ||
| })} | ||
| </EuiButton> | ||
| </EuiFlexItem> | ||
| </EuiFlexGroup> | ||
cee-chen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| <EuiFlexGroup> | ||
| <EuiFlexItem> | ||
| <EuiPanel> | ||
| <CredentialsList /> | ||
| </EuiPanel> | ||
| </EuiFlexItem> | ||
| </EuiFlexGroup> | ||
cee-chen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| </EuiPageContentBody> | ||
| </> | ||
| ); | ||
| }; | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.