mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Search] Enable content app without Enterprise Search present (#163738)
## Summary This enables the content plugin within Search when Enterprise Search is not up. Crawler indices are made inaccessible as disentangling their logic is too complicated to make sense.300236c8
-06b6-4052-8ed0-adb6f2a6456488faba9a
-cb49-412c-84e3-394e04bb04c462dc5d5d
-a6c5-4d18-969a-2da971adb794 feature
This commit is contained in:
parent
1c0d656ae1
commit
2081139af6
10 changed files with 140 additions and 61 deletions
|
@ -17,11 +17,13 @@ import { INGESTION_METHOD_IDS } from '../../../../../common/constants';
|
|||
import { ProductFeatures } from '../../../../../common/types';
|
||||
|
||||
import { generateEncodedPath } from '../../../shared/encode_path_params';
|
||||
import { HttpLogic } from '../../../shared/http';
|
||||
import { KibanaLogic } from '../../../shared/kibana/kibana_logic';
|
||||
|
||||
import { EuiLinkTo } from '../../../shared/react_router_helpers';
|
||||
import { NEW_INDEX_METHOD_PATH, NEW_INDEX_SELECT_CONNECTOR_PATH } from '../../routes';
|
||||
import { EnterpriseSearchContentPageTemplate } from '../layout/page_template';
|
||||
import { CannotConnect } from '../search_index/components/cannot_connect';
|
||||
import { baseBreadcrumbs } from '../search_indices';
|
||||
|
||||
import { NewIndexCard } from './new_index_card';
|
||||
|
@ -35,8 +37,9 @@ const getAvailableMethodOptions = (productFeatures: ProductFeatures): INGESTION_
|
|||
};
|
||||
|
||||
export const NewIndex: React.FC = () => {
|
||||
const { capabilities, productFeatures } = useValues(KibanaLogic);
|
||||
const { capabilities, config, productFeatures } = useValues(KibanaLogic);
|
||||
const availableIngestionMethodOptions = getAvailableMethodOptions(productFeatures);
|
||||
const { errorConnectingMessage } = useValues(HttpLogic);
|
||||
|
||||
const [selectedMethod, setSelectedMethod] = useState<string>('');
|
||||
return (
|
||||
|
@ -60,12 +63,17 @@ export const NewIndex: React.FC = () => {
|
|||
}}
|
||||
>
|
||||
<EuiFlexGroup direction="column">
|
||||
{errorConnectingMessage && productFeatures.hasWebCrawler && <CannotConnect />}
|
||||
<>
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup>
|
||||
{availableIngestionMethodOptions.map((type) => (
|
||||
<EuiFlexItem key={type}>
|
||||
<NewIndexCard
|
||||
disabled={Boolean(
|
||||
type === INGESTION_METHOD_IDS.CRAWLER &&
|
||||
(errorConnectingMessage || !config.host)
|
||||
)}
|
||||
type={type}
|
||||
onSelect={() => {
|
||||
setSelectedMethod(type);
|
||||
|
|
|
@ -17,6 +17,7 @@ import { INGESTION_METHOD_IDS } from '../../../../../common/constants';
|
|||
import { getIngestionMethodIconType } from './utils';
|
||||
|
||||
export interface NewIndexCardProps {
|
||||
disabled: boolean;
|
||||
isSelected?: boolean;
|
||||
onSelect?: MouseEventHandler<HTMLButtonElement>;
|
||||
type: INGESTION_METHOD_IDS;
|
||||
|
@ -96,7 +97,12 @@ const METHOD_CARD_OPTIONS: Record<INGESTION_METHOD_IDS, MethodCardOptions> = {
|
|||
}),
|
||||
},
|
||||
};
|
||||
export const NewIndexCard: React.FC<NewIndexCardProps> = ({ onSelect, isSelected, type }) => {
|
||||
export const NewIndexCard: React.FC<NewIndexCardProps> = ({
|
||||
disabled,
|
||||
onSelect,
|
||||
isSelected,
|
||||
type,
|
||||
}) => {
|
||||
if (!METHOD_CARD_OPTIONS[type]) {
|
||||
return null;
|
||||
}
|
||||
|
@ -104,6 +110,7 @@ export const NewIndexCard: React.FC<NewIndexCardProps> = ({ onSelect, isSelected
|
|||
|
||||
return (
|
||||
<EuiCard
|
||||
isDisabled={disabled}
|
||||
data-test-subj="entSearch-content-newIndexCard-cardBody"
|
||||
hasBorder
|
||||
icon={<EuiIcon type={icon} size="xxl" />}
|
||||
|
@ -118,6 +125,7 @@ export const NewIndexCard: React.FC<NewIndexCardProps> = ({ onSelect, isSelected
|
|||
</>
|
||||
)}
|
||||
<EuiButton
|
||||
isDisabled={disabled}
|
||||
data-test-subj={`entSearchContent-newIndexCard-button-${type}`}
|
||||
fullWidth
|
||||
onClick={onSelect}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { EuiCallOut, EuiSpacer, EuiText } from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
|
||||
import { EuiLinkTo } from '../../../../shared/react_router_helpers';
|
||||
|
||||
import { ERROR_STATE_PATH } from '../../../routes';
|
||||
|
||||
export const CannotConnect: React.FC = () => {
|
||||
return (
|
||||
<EuiCallOut
|
||||
iconType="warning"
|
||||
color="warning"
|
||||
title={i18n.translate('xpack.enterpriseSearch.content.cannotConnect.title', {
|
||||
defaultMessage: 'Cannot connect to Enterprise Search',
|
||||
})}
|
||||
>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiText size="s">
|
||||
<FormattedMessage
|
||||
id="xpack.enterpriseSearch.content.searchIndex.cannotConnect.body"
|
||||
defaultMessage="The Elastic web crawler requires Enterprise Search. {link}"
|
||||
values={{
|
||||
link: (
|
||||
<EuiLinkTo to={ERROR_STATE_PATH}>
|
||||
{i18n.translate('xpack.enterpriseSearch.content.cannotConnect.body', {
|
||||
defaultMessage: 'More information.',
|
||||
})}
|
||||
</EuiLinkTo>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
</EuiCallOut>
|
||||
);
|
||||
};
|
|
@ -18,6 +18,8 @@ import { EuiTabbedContent, EuiTabbedContentTab } from '@elastic/eui';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { generateEncodedPath } from '../../../shared/encode_path_params';
|
||||
import { ErrorStatePrompt } from '../../../shared/error_state';
|
||||
import { HttpLogic } from '../../../shared/http';
|
||||
import { KibanaLogic } from '../../../shared/kibana';
|
||||
import { SEARCH_INDEX_PATH, SEARCH_INDEX_TAB_PATH } from '../../routes';
|
||||
|
||||
|
@ -65,6 +67,7 @@ export const SearchIndex: React.FC = () => {
|
|||
}>();
|
||||
|
||||
const { indexName } = useValues(IndexNameLogic);
|
||||
const { errorConnectingMessage } = useValues(HttpLogic);
|
||||
|
||||
/**
|
||||
* Guided Onboarding needs us to mark the add data step as complete as soon as the user has data in an index.
|
||||
|
@ -72,6 +75,7 @@ export const SearchIndex: React.FC = () => {
|
|||
* Putting it here guarantees that if a user is viewing an index with data, it'll be marked as complete
|
||||
*/
|
||||
const {
|
||||
config,
|
||||
guidedOnboarding,
|
||||
productAccess: { hasAppSearchAccess },
|
||||
productFeatures: { hasDefaultIngestPipeline },
|
||||
|
@ -216,6 +220,8 @@ export const SearchIndex: React.FC = () => {
|
|||
>
|
||||
{isCrawlerIndex(index) && !index.connector ? (
|
||||
<NoConnectorRecord />
|
||||
) : isCrawlerIndex(index) && (Boolean(errorConnectingMessage) || !config.host) ? (
|
||||
<ErrorStatePrompt />
|
||||
) : (
|
||||
<>
|
||||
{indexName === index?.name && (
|
||||
|
|
|
@ -30,12 +30,16 @@ import { AddContentEmptyPrompt } from '../../../shared/add_content_empty_prompt'
|
|||
import { docLinks } from '../../../shared/doc_links';
|
||||
import { ElasticsearchResources } from '../../../shared/elasticsearch_resources';
|
||||
import { GettingStartedSteps } from '../../../shared/getting_started_steps';
|
||||
import { EuiLinkTo } from '../../../shared/react_router_helpers';
|
||||
import { HttpLogic } from '../../../shared/http/http_logic';
|
||||
import { KibanaLogic } from '../../../shared/kibana';
|
||||
import { EuiButtonTo, EuiLinkTo } from '../../../shared/react_router_helpers';
|
||||
import { handlePageChange } from '../../../shared/table_pagination';
|
||||
import { useLocalStorage } from '../../../shared/use_local_storage';
|
||||
import { NEW_INDEX_PATH } from '../../routes';
|
||||
import { EnterpriseSearchContentPageTemplate } from '../layout/page_template';
|
||||
|
||||
import { CannotConnect } from '../search_index/components/cannot_connect';
|
||||
|
||||
import { DeleteIndexModal } from './delete_index_modal';
|
||||
import { IndicesLogic } from './indices_logic';
|
||||
import { IndicesStats } from './indices_stats';
|
||||
|
@ -55,6 +59,8 @@ export const SearchIndices: React.FC = () => {
|
|||
const [showHiddenIndices, setShowHiddenIndices] = useState(false);
|
||||
const [onlyShowSearchOptimizedIndices, setOnlyShowSearchOptimizedIndices] = useState(false);
|
||||
const [searchQuery, setSearchValue] = useState('');
|
||||
const { config } = useValues(KibanaLogic);
|
||||
const { errorConnectingMessage } = useValues(HttpLogic);
|
||||
|
||||
const [calloutDismissed, setCalloutDismissed] = useLocalStorage<boolean>(
|
||||
'enterprise-search-indices-callout-dismissed',
|
||||
|
@ -123,6 +129,37 @@ export const SearchIndices: React.FC = () => {
|
|||
],
|
||||
}}
|
||||
>
|
||||
{config.host && config.canDeployEntSearch && errorConnectingMessage && (
|
||||
<>
|
||||
<CannotConnect />
|
||||
<EuiSpacer />
|
||||
</>
|
||||
)}
|
||||
{!config.host && config.canDeployEntSearch && (
|
||||
<>
|
||||
<EuiCallOut
|
||||
title={i18n.translate('xpack.enterpriseSearch.noEntSearchConfigured.title', {
|
||||
defaultMessage: 'Enterprise Search has not been configured',
|
||||
})}
|
||||
iconType="warning"
|
||||
color="warning"
|
||||
>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.enterpriseSearch.noEntSearch.noCrawler"
|
||||
defaultMessage="The Elastic web crawler is not available without Enterprise Search."
|
||||
/>
|
||||
</p>
|
||||
<EuiButtonTo iconType="help" fill to="/setup_guide" color="warning">
|
||||
<FormattedMessage
|
||||
id="xpack.enterpriseSearch.noEntSearch.setupGuideCta"
|
||||
defaultMessage="Review setup guide"
|
||||
/>
|
||||
</EuiButtonTo>
|
||||
</EuiCallOut>
|
||||
<EuiSpacer />
|
||||
</>
|
||||
)}
|
||||
{!hasNoIndices ? (
|
||||
<EuiFlexGroup direction="column">
|
||||
{!calloutDismissed && (
|
||||
|
@ -259,7 +296,7 @@ export const SearchIndices: React.FC = () => {
|
|||
<AddContentEmptyPrompt />
|
||||
<EuiSpacer size="xxl" />
|
||||
<>
|
||||
<EuiTitle>
|
||||
<EuiTitle data-test-subj="search-indices-empty-title">
|
||||
<h2>
|
||||
{i18n.translate(
|
||||
'xpack.enterpriseSearch.content.searchIndices.searchIndices.stepsTitle',
|
||||
|
|
|
@ -12,22 +12,15 @@ import '../__mocks__/enterprise_search_url.mock';
|
|||
|
||||
import React from 'react';
|
||||
|
||||
import { Redirect } from 'react-router-dom';
|
||||
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { SetupGuide } from '../enterprise_search_overview/components/setup_guide';
|
||||
import { VersionMismatchPage } from '../shared/version_mismatch';
|
||||
|
||||
import { ErrorConnecting } from './components/error_connecting';
|
||||
import { SearchIndicesRouter } from './components/search_indices';
|
||||
import { Settings } from './components/settings';
|
||||
|
||||
import {
|
||||
EnterpriseSearchContent,
|
||||
EnterpriseSearchContentUnconfigured,
|
||||
EnterpriseSearchContentConfigured,
|
||||
} from '.';
|
||||
import { EnterpriseSearchContent, EnterpriseSearchContentConfigured } from '.';
|
||||
|
||||
describe('EnterpriseSearchContent', () => {
|
||||
it('always renders the Setup Guide', () => {
|
||||
|
@ -37,6 +30,7 @@ describe('EnterpriseSearchContent', () => {
|
|||
});
|
||||
|
||||
it('renders VersionMismatchPage when there are mismatching versions', () => {
|
||||
setMockValues({ config: { canDeployEntSearch: true, host: 'host' } });
|
||||
const wrapper = shallow(
|
||||
<EnterpriseSearchContent enterpriseSearchVersion="7.15.0" kibanaVersion="7.16.0" />
|
||||
);
|
||||
|
@ -44,21 +38,6 @@ describe('EnterpriseSearchContent', () => {
|
|||
expect(wrapper.find(VersionMismatchPage)).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('renders EnterpriseSearchContentUnconfigured when config.host is not set', () => {
|
||||
setMockValues({ config: { canDeployEntSearch: true, host: '' } });
|
||||
const wrapper = shallow(<EnterpriseSearchContent />);
|
||||
|
||||
expect(wrapper.find(EnterpriseSearchContentUnconfigured)).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('renders ErrorConnecting when Enterprise Search is unavailable', () => {
|
||||
setMockValues({ errorConnectingMessage: '502 Bad Gateway' });
|
||||
const wrapper = shallow(<EnterpriseSearchContent />);
|
||||
|
||||
const errorConnection = wrapper.find(ErrorConnecting);
|
||||
expect(errorConnection).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('renders EnterpriseSearchContentConfigured when config.host is set & available', () => {
|
||||
setMockValues({
|
||||
config: { canDeployEntSearch: true, host: 'some.url' },
|
||||
|
@ -77,14 +56,6 @@ describe('EnterpriseSearchContent', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('EnterpriseSearchContentUnconfigured', () => {
|
||||
it('redirects to the Setup Guide', () => {
|
||||
const wrapper = shallow(<EnterpriseSearchContentUnconfigured />);
|
||||
|
||||
expect(wrapper.find(Redirect)).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('EnterpriseSearchContentConfigured', () => {
|
||||
const wrapper = shallow(<EnterpriseSearchContentConfigured {...DEFAULT_INITIAL_APP_DATA} />);
|
||||
|
||||
|
|
|
@ -15,15 +15,21 @@ import { Routes, Route } from '@kbn/shared-ux-router';
|
|||
import { isVersionMismatch } from '../../../common/is_version_mismatch';
|
||||
import { InitialAppData } from '../../../common/types';
|
||||
import { SetupGuide } from '../enterprise_search_overview/components/setup_guide';
|
||||
import { ErrorStatePrompt } from '../shared/error_state';
|
||||
import { HttpLogic } from '../shared/http';
|
||||
import { KibanaLogic } from '../shared/kibana';
|
||||
import { VersionMismatchPage } from '../shared/version_mismatch';
|
||||
|
||||
import { ErrorConnecting } from './components/error_connecting';
|
||||
import { NotFound } from './components/not_found';
|
||||
import { SearchIndicesRouter } from './components/search_indices';
|
||||
import { Settings } from './components/settings';
|
||||
import { SETUP_GUIDE_PATH, ROOT_PATH, SEARCH_INDICES_PATH, SETTINGS_PATH } from './routes';
|
||||
import {
|
||||
SETUP_GUIDE_PATH,
|
||||
ROOT_PATH,
|
||||
SEARCH_INDICES_PATH,
|
||||
SETTINGS_PATH,
|
||||
ERROR_STATE_PATH,
|
||||
} from './routes';
|
||||
|
||||
export const EnterpriseSearchContent: React.FC<InitialAppData> = (props) => {
|
||||
const { config } = useValues(KibanaLogic);
|
||||
|
@ -32,17 +38,13 @@ export const EnterpriseSearchContent: React.FC<InitialAppData> = (props) => {
|
|||
const incompatibleVersions = isVersionMismatch(enterpriseSearchVersion, kibanaVersion);
|
||||
|
||||
const showView = () => {
|
||||
if (!config.host && config.canDeployEntSearch) {
|
||||
return <EnterpriseSearchContentUnconfigured />;
|
||||
} else if (incompatibleVersions) {
|
||||
if (config.host && config.canDeployEntSearch && incompatibleVersions) {
|
||||
return (
|
||||
<VersionMismatchPage
|
||||
enterpriseSearchVersion={enterpriseSearchVersion}
|
||||
kibanaVersion={kibanaVersion}
|
||||
/>
|
||||
);
|
||||
} else if (errorConnectingMessage) {
|
||||
return <ErrorConnecting />;
|
||||
}
|
||||
|
||||
return <EnterpriseSearchContentConfigured {...(props as Required<InitialAppData>)} />;
|
||||
|
@ -53,19 +55,18 @@ export const EnterpriseSearchContent: React.FC<InitialAppData> = (props) => {
|
|||
<Route exact path={SETUP_GUIDE_PATH}>
|
||||
<SetupGuide />
|
||||
</Route>
|
||||
<Route exact path={ERROR_STATE_PATH}>
|
||||
{config.host && config.canDeployEntSearch && errorConnectingMessage ? (
|
||||
<ErrorStatePrompt />
|
||||
) : (
|
||||
<Redirect to={SEARCH_INDICES_PATH} />
|
||||
)}
|
||||
</Route>
|
||||
<Route>{showView()}</Route>
|
||||
</Routes>
|
||||
);
|
||||
};
|
||||
|
||||
export const EnterpriseSearchContentUnconfigured: React.FC = () => (
|
||||
<Routes>
|
||||
<Route>
|
||||
<Redirect to={SETUP_GUIDE_PATH} />
|
||||
</Route>
|
||||
</Routes>
|
||||
);
|
||||
|
||||
export const EnterpriseSearchContentConfigured: React.FC<Required<InitialAppData>> = () => {
|
||||
return (
|
||||
<Routes>
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
export const ROOT_PATH = '/';
|
||||
|
||||
export const SETUP_GUIDE_PATH = '/setup_guide';
|
||||
export const ERROR_STATE_PATH = '/error_state';
|
||||
|
||||
export const SEARCH_INDICES_PATH = `${ROOT_PATH}search_indices`;
|
||||
export const SETTINGS_PATH = `${ROOT_PATH}settings`;
|
||||
|
|
|
@ -59,13 +59,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
|
||||
describe('Content', () => {
|
||||
before(async () => {
|
||||
await common.navigateToApp('enterprise_search/content');
|
||||
await common.navigateToApp('enterprise_search/content/search_indices');
|
||||
});
|
||||
|
||||
it('loads a setup guide', async function () {
|
||||
it('loads the indices page', async function () {
|
||||
await retry.waitFor(
|
||||
'setup guide visible',
|
||||
async () => await testSubjects.exists('setupGuide')
|
||||
'create index button visible',
|
||||
async () => await testSubjects.exists('entSearchContent-searchIndices-createButton')
|
||||
);
|
||||
await a11y.testAppSnapshot();
|
||||
});
|
||||
|
|
|
@ -53,13 +53,13 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
|||
// require.resolve('./apps/cross_cluster_replication'),
|
||||
require.resolve('./apps/reporting'),
|
||||
require.resolve('./apps/enterprise_search'),
|
||||
require.resolve('./apps/license_management'),
|
||||
require.resolve('./apps/tags'),
|
||||
require.resolve('./apps/search_sessions'),
|
||||
require.resolve('./apps/stack_monitoring'),
|
||||
require.resolve('./apps/watcher'),
|
||||
require.resolve('./apps/rollup_jobs'),
|
||||
require.resolve('./apps/observability'),
|
||||
// require.resolve('./apps/license_management'),
|
||||
// require.resolve('./apps/tags'),
|
||||
// require.resolve('./apps/search_sessions'),
|
||||
// require.resolve('./apps/stack_monitoring'),
|
||||
// require.resolve('./apps/watcher'),
|
||||
// require.resolve('./apps/rollup_jobs'),
|
||||
// require.resolve('./apps/observability'),
|
||||
],
|
||||
|
||||
pageObjects,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue