Skip to content
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

[App Search] Convert Documents views to new page template + minor UI polish #102807

Merged
merged 5 commits into from
Jun 21, 2021
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 @@ -7,43 +7,41 @@

import React from 'react';

import { EuiButton, EuiEmptyPrompt, EuiPanel } from '@elastic/eui';
import { EuiButton, EuiEmptyPrompt } from '@elastic/eui';
import { i18n } from '@kbn/i18n';

import { DOCS_PREFIX } from '../../../routes';

export const EmptyState = () => (
<EuiPanel color="subdued" grow={false}>
<EuiEmptyPrompt
data-test-subj="EmptyDocumentPrompt"
iconType="documents"
title={
<h2>
{i18n.translate('xpack.enterpriseSearch.appSearch.documents.empty.title', {
defaultMessage: 'Add your first documents',
})}
</h2>
}
body={
<p>
{i18n.translate('xpack.enterpriseSearch.appSearch.documents.empty.description', {
defaultMessage:
'You can index documents using the App Search Web Crawler, by uploading JSON, or by using the API.',
})}
</p>
}
actions={
<EuiButton
size="s"
target="_blank"
iconType="popout"
href={`${DOCS_PREFIX}/indexing-documents-guide.html`}
>
{i18n.translate('xpack.enterpriseSearch.appSearch.engine.documents.empty.buttonLabel', {
defaultMessage: 'Read the documents guide',
})}
</EuiButton>
}
/>
</EuiPanel>
<EuiEmptyPrompt
data-test-subj="EmptyDocumentPrompt"
iconType="documents"
title={
<h2>
{i18n.translate('xpack.enterpriseSearch.appSearch.documents.empty.title', {
defaultMessage: 'Add your first documents',
})}
</h2>
}
body={
<p>
{i18n.translate('xpack.enterpriseSearch.appSearch.documents.empty.description', {
defaultMessage:
'You can index documents using the App Search Web Crawler, by uploading JSON, or by using the API.',
})}
</p>
}
actions={
<EuiButton
size="s"
target="_blank"
iconType="popout"
href={`${DOCS_PREFIX}/indexing-documents-guide.html`}
>
{i18n.translate('xpack.enterpriseSearch.appSearch.engine.documents.empty.buttonLabel', {
defaultMessage: 'Read the documents guide',
})}
</EuiButton>
}
/>
);
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ import React from 'react';

import { shallow } from 'enzyme';

import { EuiPageHeader, EuiPageContent, EuiBasicTable } from '@elastic/eui';
import { EuiPanel, EuiBasicTable } from '@elastic/eui';

import { getPageHeaderActions } from '../../../test_helpers';

import { Loading } from '../../../shared/loading';
import { ResultFieldValue } from '../result';

import { DocumentDetail } from '.';
Expand Down Expand Up @@ -45,7 +46,7 @@ describe('DocumentDetail', () => {

it('renders', () => {
const wrapper = shallow(<DocumentDetail />);
expect(wrapper.find(EuiPageContent).length).toBe(1);
expect(wrapper.find(EuiPanel).length).toBe(1);
});

it('initializes data on mount', () => {
Expand All @@ -59,17 +60,6 @@ describe('DocumentDetail', () => {
expect(actions.setFields).toHaveBeenCalledWith([]);
});

it('will show a loader while data is loading', () => {
setMockValues({
...values,
dataLoading: true,
});

const wrapper = shallow(<DocumentDetail />);

expect(wrapper.find(Loading).length).toBe(1);
});

describe('field values list', () => {
let columns: any;

Expand Down Expand Up @@ -102,8 +92,7 @@ describe('DocumentDetail', () => {

it('will delete the document when the delete button is pressed', () => {
const wrapper = shallow(<DocumentDetail />);
const header = wrapper.find(EuiPageHeader).dive().children().dive();
const button = header.find('[data-test-subj="DeleteDocumentButton"]');
const button = getPageHeaderActions(wrapper).find('[data-test-subj="DeleteDocumentButton"]');

button.simulate('click');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,13 @@ import { useParams } from 'react-router-dom';

import { useActions, useValues } from 'kea';

import {
EuiButton,
EuiPageHeader,
EuiPageContentBody,
EuiPageContent,
EuiBasicTable,
EuiBasicTableColumn,
} from '@elastic/eui';
import { EuiPanel, EuiButton, EuiBasicTable, EuiBasicTableColumn } from '@elastic/eui';
import { i18n } from '@kbn/i18n';

import { DELETE_BUTTON_LABEL } from '../../../shared/constants';
import { FlashMessages } from '../../../shared/flash_messages';
import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome';
import { Loading } from '../../../shared/loading';
import { useDecodedParams } from '../../utils/encode_path_params';
import { getEngineBreadcrumbs } from '../engine';
import { AppSearchPageTemplate } from '../layout';
import { ResultFieldValue } from '../result';

import { DOCUMENTS_TITLE } from './constants';
Expand All @@ -52,10 +43,6 @@ export const DocumentDetail: React.FC = () => {
};
}, []);

if (dataLoading) {
return <Loading />;
}

const columns: Array<EuiBasicTableColumn<FieldDetails>> = [
{
name: i18n.translate('xpack.enterpriseSearch.appSearch.documentDetail.fieldHeader', {
Expand All @@ -74,11 +61,11 @@ export const DocumentDetail: React.FC = () => {
];

return (
<>
<SetPageChrome trail={getEngineBreadcrumbs([DOCUMENTS_TITLE, documentTitle])} />
<EuiPageHeader
pageTitle={DOCUMENT_DETAIL_TITLE(documentTitle)}
rightSideItems={[
<AppSearchPageTemplate
pageChrome={getEngineBreadcrumbs([DOCUMENTS_TITLE, documentTitle])}
pageHeader={{
pageTitle: DOCUMENT_DETAIL_TITLE(documentTitle),
rightSideItems: [
<EuiButton
color="danger"
iconType="trash"
Expand All @@ -87,14 +74,13 @@ export const DocumentDetail: React.FC = () => {
>
{DELETE_BUTTON_LABEL}
</EuiButton>,
]}
/>
<EuiPageContent hasBorder>
<EuiPageContentBody>
<FlashMessages />
<EuiBasicTable columns={columns} items={fields} />
</EuiPageContentBody>
</EuiPageContent>
</>
],
}}
isLoading={dataLoading}
>
<EuiPanel hasBorder>
<EuiBasicTable columns={columns} items={fields} />
</EuiPanel>
</AppSearchPageTemplate>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import '../../__mocks__/engine_logic.mock';

import React from 'react';

import { shallow, ShallowWrapper } from 'enzyme';
import { shallow } from 'enzyme';

import { EuiPageHeader } from '@elastic/eui';
import { getPageHeaderActions } from '../../../test_helpers';

import { DocumentCreationButton } from './components';
import { SearchExperience } from './search_experience';
Expand All @@ -22,6 +22,7 @@ import { Documents } from '.';
describe('Documents', () => {
const values = {
isMetaEngine: false,
engine: { document_count: 1 },
myRole: { canManageEngineDocuments: true },
};

Expand All @@ -36,17 +37,14 @@ describe('Documents', () => {
});

describe('DocumentCreationButton', () => {
const getHeader = (wrapper: ShallowWrapper) =>
wrapper.find(EuiPageHeader).dive().children().dive();

it('renders a DocumentCreationButton if the user can manage engine documents', () => {
setMockValues({
...values,
myRole: { canManageEngineDocuments: true },
});

const wrapper = shallow(<Documents />);
expect(getHeader(wrapper).find(DocumentCreationButton).exists()).toBe(true);
expect(getPageHeaderActions(wrapper).find(DocumentCreationButton).exists()).toBe(true);
});

it('does not render a DocumentCreationButton if the user cannot manage engine documents', () => {
Expand All @@ -56,7 +54,7 @@ describe('Documents', () => {
});

const wrapper = shallow(<Documents />);
expect(getHeader(wrapper).find(DocumentCreationButton).exists()).toBe(false);
expect(getPageHeaderActions(wrapper).find(DocumentCreationButton).exists()).toBe(false);
});

it('does not render a DocumentCreationButton for meta engines even if the user can manage engine documents', () => {
Expand All @@ -67,7 +65,7 @@ describe('Documents', () => {
});

const wrapper = shallow(<Documents />);
expect(getHeader(wrapper).find(DocumentCreationButton).exists()).toBe(false);
expect(getPageHeaderActions(wrapper).find(DocumentCreationButton).exists()).toBe(false);
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,32 @@ import React from 'react';

import { useValues } from 'kea';

import { EuiPageHeader, EuiCallOut, EuiSpacer } from '@elastic/eui';
import { EuiCallOut, EuiSpacer } from '@elastic/eui';
import { i18n } from '@kbn/i18n';

import { FlashMessages } from '../../../shared/flash_messages';
import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome';

import { AppLogic } from '../../app_logic';
import { EngineLogic, getEngineBreadcrumbs } from '../engine';
import { AppSearchPageTemplate } from '../layout';

import { DocumentCreationButton } from './components';
import { DocumentCreationButton, EmptyState } from './components';
import { DOCUMENTS_TITLE } from './constants';
import { SearchExperience } from './search_experience';

export const Documents: React.FC = () => {
const { isMetaEngine } = useValues(EngineLogic);
const { isMetaEngine, engine } = useValues(EngineLogic);
const { myRole } = useValues(AppLogic);

return (
<>
<SetPageChrome trail={getEngineBreadcrumbs([DOCUMENTS_TITLE])} />
<EuiPageHeader
pageTitle={DOCUMENTS_TITLE}
rightSideItems={
myRole.canManageEngineDocuments && !isMetaEngine
? [<DocumentCreationButton />]
: undefined
}
/>
<FlashMessages />
<AppSearchPageTemplate
pageChrome={getEngineBreadcrumbs([DOCUMENTS_TITLE])}
pageHeader={{
pageTitle: DOCUMENTS_TITLE,
rightSideItems:
myRole.canManageEngineDocuments && !isMetaEngine ? [<DocumentCreationButton />] : [],
}}
isEmptyState={!engine.document_count}
Copy link
Member Author

@cee-chen cee-chen Jun 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, totally forgot to mention - I have plans to pull this out to a flat isEngineEmpty selector, but I'm going to do that in a later tech debt/polish PR, since I'll also be using that check for the engine overview

emptyState={<EmptyState />}
>
{isMetaEngine && (
<>
<EuiCallOut
Expand All @@ -61,6 +58,6 @@ export const Documents: React.FC = () => {
</>
)}
<SearchExperience />
</>
</AppSearchPageTemplate>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

.documentsSearchExperience__content {
flex-grow: 4;
position: relative;
}

.documentsSearchExperience__pagingInfo {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ jest.mock('../../../../shared/use_local_storage', () => ({
}));
import { useLocalStorage } from '../../../../shared/use_local_storage';

import { EmptyState } from '../components';

import { CustomizationCallout } from './customization_callout';
import { CustomizationModal } from './customization_modal';
import { SearchExperienceContent } from './search_experience_content';
Expand Down Expand Up @@ -58,14 +56,6 @@ describe('SearchExperience', () => {
expect(wrapper.find(SearchExperienceContent)).toHaveLength(1);
});

it('renders an empty state when the engine does not have documents', () => {
setMockValues({ ...values, engine: { ...values.engine, document_count: 0 } });
const wrapper = shallow(<SearchExperience />);

expect(wrapper.find(EmptyState)).toHaveLength(1);
expect(wrapper.find(SearchExperienceContent)).toHaveLength(0);
});

describe('when there are no selected filter fields', () => {
let wrapper: ShallowWrapper;
beforeEach(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import './search_experience.scss';
import { externalUrl } from '../../../../shared/enterprise_search_url';
import { useLocalStorage } from '../../../../shared/use_local_storage';
import { EngineLogic } from '../../engine';
import { EmptyState } from '../components';

import { buildSearchUIConfig } from './build_search_ui_config';
import { buildSortOptions } from './build_sort_options';
Expand Down Expand Up @@ -141,11 +140,7 @@ export const SearchExperience: React.FC = () => {
)}
</EuiFlexItem>
<EuiFlexItem className="documentsSearchExperience__content">
{engine.document_count && engine.document_count > 0 ? (
<SearchExperienceContent />
) : (
<EmptyState />
)}
<SearchExperienceContent />
</EuiFlexItem>
</EuiFlexGroup>
</SearchProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { shallow } from 'enzyme';
// @ts-expect-error types are not available for this package yet
import { Results } from '@elastic/react-search-ui';

import { Loading } from '../../../../shared/loading';
import { SchemaType } from '../../../../shared/schema/types';

import { Pagination } from './pagination';
Expand Down Expand Up @@ -82,13 +83,13 @@ describe('SearchExperienceContent', () => {
expect(wrapper.find(Pagination).exists()).toBe(true);
});

it('renders empty if a search was not performed yet', () => {
it('renders a loading state if a search was not performed yet', () => {
setMockSearchContextState({
...searchState,
wasSearched: false,
});
const wrapper = shallow(<SearchExperienceContent />);
expect(wrapper.isEmptyRender()).toBe(true);
expect(wrapper.find(Loading)).toHaveLength(1);
});

it('renders results if a search was performed and there are more than 0 totalResults', () => {
Expand Down
Loading