mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
# Backport This will backport the following commits from `main` to `8.x`: - [[ES3][Search] Create Index Page (#199402)](https://github.com/elastic/kibana/pull/199402) <!--- Backport version: 8.9.8 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Rodney Norris","email":"rodney.norris@elastic.co"},"sourceCommit":{"committedDate":"2024-11-11T19:24:32Z","message":"[ES3][Search] Create Index Page (#199402)\n\n## Summary\r\n\r\nThis PR introduces a Create Index page for the serverless search\r\nsolution. This page is almost identical to the new Global Empty State,\r\nbut is navigated to via the Create Index button in Index Management. The\r\nindex details redirect logic is also slightly different on the Create\r\nIndex page, it will only redirect when the \"code\" view is open and a new\r\nindex is created. instead of redirecting from both UI and Code view like\r\nthe Global Empty State page does.\r\n\r\nWith the addition of this page we are also removing the \"Home\" link from\r\nthe serverless search side nav to reduce confusion when the global empty\r\nstart redirects to index management when indices exist.\r\n\r\nThere is also some minor clean-up to ensure both the global empty state\r\nand the new create index pages have proper document titles and\r\nbreadcrumbs.\r\n\r\n### Screenshots\r\nUpdates to Global Empty State:\r\n\r\n\r\nCreate Index Page:\r\n<img width=\"1320\" alt=\"image\"\r\nsrc=\"https://github.com/user-attachments/assets/0d095eb6-fda3-4783-83ab-20449b5b31f1\">\r\n\r\n### Checklist\r\n\r\n- [x] Any text added follows [EUI's writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing), uses\r\nsentence case text and includes [i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n- [ ]\r\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\r\nwas added for features that require explanation or tutorials\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n- [x] [Flaky Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\r\nused on any tests changed\r\n- [x] Any UI touched in this PR is usable by keyboard only (learn more\r\nabout [keyboard accessibility](https://webaim.org/techniques/keyboard/))\r\n- [x] Any UI touched in this PR does not create any new axe failures\r\n(run axe in browser:\r\n[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),\r\n[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>\r\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"e03e59b6d482a05435d86a612d92028f264df893","branchLabelMapping":{"^v9.0.0$":"main","^v8.17.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:Search","backport:prev-minor","v8.17.0"],"number":199402,"url":"https://github.com/elastic/kibana/pull/199402","mergeCommit":{"message":"[ES3][Search] Create Index Page (#199402)\n\n## Summary\r\n\r\nThis PR introduces a Create Index page for the serverless search\r\nsolution. This page is almost identical to the new Global Empty State,\r\nbut is navigated to via the Create Index button in Index Management. The\r\nindex details redirect logic is also slightly different on the Create\r\nIndex page, it will only redirect when the \"code\" view is open and a new\r\nindex is created. instead of redirecting from both UI and Code view like\r\nthe Global Empty State page does.\r\n\r\nWith the addition of this page we are also removing the \"Home\" link from\r\nthe serverless search side nav to reduce confusion when the global empty\r\nstart redirects to index management when indices exist.\r\n\r\nThere is also some minor clean-up to ensure both the global empty state\r\nand the new create index pages have proper document titles and\r\nbreadcrumbs.\r\n\r\n### Screenshots\r\nUpdates to Global Empty State:\r\n\r\n\r\nCreate Index Page:\r\n<img width=\"1320\" alt=\"image\"\r\nsrc=\"https://github.com/user-attachments/assets/0d095eb6-fda3-4783-83ab-20449b5b31f1\">\r\n\r\n### Checklist\r\n\r\n- [x] Any text added follows [EUI's writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing), uses\r\nsentence case text and includes [i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n- [ ]\r\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\r\nwas added for features that require explanation or tutorials\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n- [x] [Flaky Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\r\nused on any tests changed\r\n- [x] Any UI touched in this PR is usable by keyboard only (learn more\r\nabout [keyboard accessibility](https://webaim.org/techniques/keyboard/))\r\n- [x] Any UI touched in this PR does not create any new axe failures\r\n(run axe in browser:\r\n[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),\r\n[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>\r\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"e03e59b6d482a05435d86a612d92028f264df893"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","labelRegex":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/199402","number":199402,"mergeCommit":{"message":"[ES3][Search] Create Index Page (#199402)\n\n## Summary\r\n\r\nThis PR introduces a Create Index page for the serverless search\r\nsolution. This page is almost identical to the new Global Empty State,\r\nbut is navigated to via the Create Index button in Index Management. The\r\nindex details redirect logic is also slightly different on the Create\r\nIndex page, it will only redirect when the \"code\" view is open and a new\r\nindex is created. instead of redirecting from both UI and Code view like\r\nthe Global Empty State page does.\r\n\r\nWith the addition of this page we are also removing the \"Home\" link from\r\nthe serverless search side nav to reduce confusion when the global empty\r\nstart redirects to index management when indices exist.\r\n\r\nThere is also some minor clean-up to ensure both the global empty state\r\nand the new create index pages have proper document titles and\r\nbreadcrumbs.\r\n\r\n### Screenshots\r\nUpdates to Global Empty State:\r\n\r\n\r\nCreate Index Page:\r\n<img width=\"1320\" alt=\"image\"\r\nsrc=\"https://github.com/user-attachments/assets/0d095eb6-fda3-4783-83ab-20449b5b31f1\">\r\n\r\n### Checklist\r\n\r\n- [x] Any text added follows [EUI's writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing), uses\r\nsentence case text and includes [i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n- [ ]\r\n[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)\r\nwas added for features that require explanation or tutorials\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n- [x] [Flaky Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was\r\nused on any tests changed\r\n- [x] Any UI touched in this PR is usable by keyboard only (learn more\r\nabout [keyboard accessibility](https://webaim.org/techniques/keyboard/))\r\n- [x] Any UI touched in this PR does not create any new axe failures\r\n(run axe in browser:\r\n[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),\r\n[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>\r\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"e03e59b6d482a05435d86a612d92028f264df893"}},{"branch":"8.x","label":"v8.17.0","labelRegex":"^v8.17.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> --------- Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
f157662827
commit
8c95788e7c
51 changed files with 1461 additions and 625 deletions
|
@ -25,3 +25,4 @@ export const SEARCH_ELASTICSEARCH = 'enterpriseSearchElasticsearch';
|
|||
export const SEARCH_VECTOR_SEARCH = 'enterpriseSearchVectorSearch';
|
||||
export const SEARCH_SEMANTIC_SEARCH = 'enterpriseSearchSemanticSearch';
|
||||
export const SEARCH_AI_SEARCH = 'enterpriseSearchAISearch';
|
||||
export const SEARCH_INDICES_CREATE_INDEX = 'createIndex';
|
||||
|
|
|
@ -22,6 +22,7 @@ import {
|
|||
SEARCH_HOMEPAGE,
|
||||
SEARCH_INDICES_START,
|
||||
SEARCH_INDICES,
|
||||
SEARCH_INDICES_CREATE_INDEX,
|
||||
SEARCH_ELASTICSEARCH,
|
||||
SEARCH_VECTOR_SEARCH,
|
||||
SEARCH_SEMANTIC_SEARCH,
|
||||
|
@ -55,6 +56,8 @@ export type AppsearchLinkId = 'engines';
|
|||
|
||||
export type RelevanceLinkId = 'inferenceEndpoints';
|
||||
|
||||
export type SearchIndicesLinkId = typeof SEARCH_INDICES_CREATE_INDEX;
|
||||
|
||||
export type DeepLinkId =
|
||||
| EnterpriseSearchApp
|
||||
| EnterpriseSearchContentApp
|
||||
|
@ -77,4 +80,5 @@ export type DeepLinkId =
|
|||
| SearchElasticsearch
|
||||
| SearchVectorSearch
|
||||
| SearchSemanticSearch
|
||||
| SearchAISearch;
|
||||
| SearchAISearch
|
||||
| `${SearchIndices}:${SearchIndicesLinkId}`;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import React from 'react';
|
||||
import { EuiButton, EuiEmptyPrompt } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import type { SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import { CreateIndexButton } from '../../sections/home/index_list/create_index/create_index_button';
|
||||
import { ExtensionsService } from '../../../services/extensions_service';
|
||||
|
||||
|
@ -16,11 +17,13 @@ export const NoMatch = ({
|
|||
filter,
|
||||
resetFilter,
|
||||
extensionsService,
|
||||
share,
|
||||
}: {
|
||||
loadIndices: () => void;
|
||||
filter: string;
|
||||
resetFilter: () => void;
|
||||
extensionsService: ExtensionsService;
|
||||
share?: SharePluginStart;
|
||||
}) => {
|
||||
if (filter) {
|
||||
return (
|
||||
|
@ -62,7 +65,7 @@ export const NoMatch = ({
|
|||
|
||||
if (extensionsService.emptyListContent) {
|
||||
return extensionsService.emptyListContent.renderContent({
|
||||
createIndexButton: <CreateIndexButton loadIndices={loadIndices} />,
|
||||
createIndexButton: <CreateIndexButton loadIndices={loadIndices} share={share} />,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -85,7 +88,7 @@ export const NoMatch = ({
|
|||
/>
|
||||
</p>
|
||||
}
|
||||
actions={<CreateIndexButton loadIndices={loadIndices} />}
|
||||
actions={<CreateIndexButton loadIndices={loadIndices} share={share} />}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -7,22 +7,32 @@
|
|||
|
||||
import React, { useState } from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import type { SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import { EuiButton } from '@elastic/eui';
|
||||
|
||||
import { CreateIndexModal } from './create_index_modal';
|
||||
|
||||
export const CreateIndexButton = ({ loadIndices }: { loadIndices: () => void }) => {
|
||||
export interface CreateIndexButtonProps {
|
||||
loadIndices: () => void;
|
||||
share?: SharePluginStart;
|
||||
}
|
||||
|
||||
export const CreateIndexButton = ({ loadIndices, share }: CreateIndexButtonProps) => {
|
||||
const [createIndexModalOpen, setCreateIndexModalOpen] = useState<boolean>(false);
|
||||
const createIndexUrl = share?.url.locators.get('SEARCH_CREATE_INDEX')?.useUrl({});
|
||||
const actionProp = createIndexUrl
|
||||
? { href: createIndexUrl }
|
||||
: { onClick: () => setCreateIndexModalOpen(true) };
|
||||
|
||||
return (
|
||||
<>
|
||||
<EuiButton
|
||||
fill
|
||||
iconType="plusInCircleFilled"
|
||||
onClick={() => setCreateIndexModalOpen(true)}
|
||||
key="createIndexButton"
|
||||
data-test-subj="createIndexButton"
|
||||
data-telemetry-id="idxMgmt-indexList-createIndexButton"
|
||||
{...actionProp}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.idxMgmt.indexTable.createIndexButton"
|
||||
|
|
|
@ -545,9 +545,10 @@ export class IndexTable extends Component {
|
|||
|
||||
return (
|
||||
<AppContextConsumer>
|
||||
{({ services, config, core }) => {
|
||||
{({ services, config, core, plugins }) => {
|
||||
const { extensionsService } = services;
|
||||
const { application, http } = core;
|
||||
const { share } = plugins;
|
||||
const columnConfigs = getColumnConfigs({
|
||||
showIndexStats: config.enableIndexStats,
|
||||
showSizeAndDocCount: config.enableSizeAndDocCount,
|
||||
|
@ -669,7 +670,7 @@ export class IndexTable extends Component {
|
|||
</>
|
||||
)}
|
||||
<EuiFlexItem grow={false}>
|
||||
<CreateIndexButton loadIndices={loadIndices} />
|
||||
<CreateIndexButton loadIndices={loadIndices} share={share} />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
||||
|
@ -714,6 +715,7 @@ export class IndexTable extends Component {
|
|||
<EuiTableRowCell align="center" colSpan={columnsCount}>
|
||||
<NoMatch
|
||||
loadIndices={loadIndices}
|
||||
share={share}
|
||||
filter={filter}
|
||||
resetFilter={() => filterChanged('')}
|
||||
extensionsService={extensionsService}
|
||||
|
|
|
@ -12,9 +12,9 @@ export enum AnalyticsEvents {
|
|||
startCreateIndexPageModifyIndexName = 'start_modify_index_name',
|
||||
startCreateIndexClick = 'start_create_index',
|
||||
startCreateIndexLanguageSelect = 'start_code_lang_select',
|
||||
startCreateIndexRunInConsole = 'start_cta_run_in_console',
|
||||
startCreateIndexCodeCopyInstall = 'start_code_copy_install',
|
||||
startCreateIndexCodeCopy = 'start_code_copy',
|
||||
startCreateIndexRunInConsole = 'start_cta_run_in_console',
|
||||
startCreateIndexCreatedRedirect = 'start_index_created_api',
|
||||
startFileUploadClick = 'start_file_upload',
|
||||
indexDetailsInstallCodeCopy = 'index_details_code_copy_install',
|
||||
|
@ -23,4 +23,15 @@ export enum AnalyticsEvents {
|
|||
indexDetailsNavDataTab = 'index_details_nav_data_tab',
|
||||
indexDetailsNavSettingsTab = 'index_details_nav_settings_tab',
|
||||
indexDetailsNavMappingsTab = 'index_details_nav_mappings_tab',
|
||||
createIndexPageOpened = 'create_index_page_opened',
|
||||
createIndexShowCodeClick = 'create_index_show_code',
|
||||
createIndexShowUIClick = 'create_index_show_create_index_ui',
|
||||
createIndexPageModifyIndexName = 'create_index_modify_index_name',
|
||||
createIndexCreateIndexClick = 'create_index_click_create',
|
||||
createIndexLanguageSelect = 'create_index_code_lang_select',
|
||||
createIndexRunInConsole = 'create_index_run_in_console',
|
||||
createIndexCodeCopyInstall = 'create_index_copy_install',
|
||||
createIndexCodeCopy = 'create_index_code_copy',
|
||||
createIndexFileUploadClick = 'create_index_file_upload',
|
||||
createIndexIndexCreatedRedirect = 'create_index_created_api',
|
||||
}
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* 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, { useCallback, useState } from 'react';
|
||||
|
||||
import type { IndicesStatusResponse, UserStartPrivilegesResponse } from '../../../common';
|
||||
|
||||
import { AnalyticsEvents } from '../../analytics/constants';
|
||||
import { AvailableLanguages } from '../../code_examples';
|
||||
import { useKibana } from '../../hooks/use_kibana';
|
||||
import { useUsageTracker } from '../../hooks/use_usage_tracker';
|
||||
import { CreateIndexFormState } from '../../types';
|
||||
import { generateRandomIndexName } from '../../utils/indices';
|
||||
import { getDefaultCodingLanguage } from '../../utils/language';
|
||||
|
||||
import { CreateIndexPanel } from '../shared/create_index_panel';
|
||||
|
||||
import { CreateIndexCodeView } from './create_index_code_view';
|
||||
import { CreateIndexUIView } from './create_index_ui_view';
|
||||
|
||||
function initCreateIndexState() {
|
||||
const defaultIndexName = generateRandomIndexName();
|
||||
return {
|
||||
indexName: defaultIndexName,
|
||||
defaultIndexName,
|
||||
codingLanguage: getDefaultCodingLanguage(),
|
||||
};
|
||||
}
|
||||
|
||||
export interface CreateIndexProps {
|
||||
indicesData?: IndicesStatusResponse;
|
||||
userPrivileges?: UserStartPrivilegesResponse;
|
||||
}
|
||||
|
||||
enum CreateIndexViewMode {
|
||||
UI = 'ui',
|
||||
Code = 'code',
|
||||
}
|
||||
|
||||
export const CreateIndex = ({ indicesData, userPrivileges }: CreateIndexProps) => {
|
||||
const { application } = useKibana().services;
|
||||
const [createIndexView, setCreateIndexView] = useState<CreateIndexViewMode>(
|
||||
userPrivileges?.privileges.canCreateIndex === false
|
||||
? CreateIndexViewMode.Code
|
||||
: CreateIndexViewMode.UI
|
||||
);
|
||||
const [formState, setFormState] = useState<CreateIndexFormState>(initCreateIndexState);
|
||||
const usageTracker = useUsageTracker();
|
||||
const onChangeView = useCallback(
|
||||
(id: string) => {
|
||||
switch (id) {
|
||||
case CreateIndexViewMode.UI:
|
||||
usageTracker.click(AnalyticsEvents.createIndexShowUIClick);
|
||||
setCreateIndexView(CreateIndexViewMode.UI);
|
||||
return;
|
||||
case CreateIndexViewMode.Code:
|
||||
usageTracker.click(AnalyticsEvents.createIndexShowCodeClick);
|
||||
setCreateIndexView(CreateIndexViewMode.Code);
|
||||
return;
|
||||
}
|
||||
},
|
||||
[usageTracker]
|
||||
);
|
||||
const onChangeCodingLanguage = useCallback(
|
||||
(language: AvailableLanguages) => {
|
||||
setFormState({
|
||||
...formState,
|
||||
codingLanguage: language,
|
||||
});
|
||||
usageTracker.count([
|
||||
AnalyticsEvents.createIndexLanguageSelect,
|
||||
`${AnalyticsEvents.createIndexLanguageSelect}_${language}`,
|
||||
]);
|
||||
},
|
||||
[usageTracker, formState, setFormState]
|
||||
);
|
||||
const onClose = useCallback(() => {
|
||||
application.navigateToApp('management', { deepLinkId: 'index_management' });
|
||||
}, [application]);
|
||||
|
||||
return (
|
||||
<CreateIndexPanel
|
||||
createIndexView={createIndexView}
|
||||
onChangeView={onChangeView}
|
||||
onClose={onClose}
|
||||
>
|
||||
{createIndexView === CreateIndexViewMode.UI && (
|
||||
<CreateIndexUIView
|
||||
formState={formState}
|
||||
setFormState={setFormState}
|
||||
userPrivileges={userPrivileges}
|
||||
/>
|
||||
)}
|
||||
{createIndexView === CreateIndexViewMode.Code && (
|
||||
<CreateIndexCodeView
|
||||
indicesData={indicesData}
|
||||
selectedLanguage={formState.codingLanguage}
|
||||
indexName={formState.indexName}
|
||||
changeCodingLanguage={onChangeCodingLanguage}
|
||||
canCreateApiKey={userPrivileges?.privileges.canCreateApiKeys}
|
||||
analyticsEvents={{
|
||||
runInConsole: AnalyticsEvents.createIndexRunInConsole,
|
||||
installCommands: AnalyticsEvents.createIndexCodeCopyInstall,
|
||||
createIndex: AnalyticsEvents.createIndexCodeCopy,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</CreateIndexPanel>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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 type { IndicesStatusResponse } from '../../../common';
|
||||
import {
|
||||
CreateIndexCodeView as SharedCreateIndexCodeView,
|
||||
CreateIndexCodeViewProps as SharedCreateIndexCodeViewProps,
|
||||
} from '../shared/create_index_code_view';
|
||||
|
||||
import { useIndicesRedirect } from './hooks/use_indices_redirect';
|
||||
|
||||
export interface CreateIndexCodeViewProps extends SharedCreateIndexCodeViewProps {
|
||||
indicesData?: IndicesStatusResponse;
|
||||
}
|
||||
|
||||
export const CreateIndexCodeView = ({ indicesData, ...props }: CreateIndexCodeViewProps) => {
|
||||
useIndicesRedirect(indicesData);
|
||||
|
||||
return <SharedCreateIndexCodeView {...props} />;
|
||||
};
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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, { useMemo } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { EuiLoadingLogo, EuiPageTemplate } from '@elastic/eui';
|
||||
import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';
|
||||
|
||||
import { useKibana } from '../../hooks/use_kibana';
|
||||
import { useIndicesStatusQuery } from '../../hooks/api/use_indices_status';
|
||||
import { useUserPrivilegesQuery } from '../../hooks/api/use_user_permissions';
|
||||
import { LoadIndicesStatusError } from '../shared/load_indices_status_error';
|
||||
|
||||
import { CreateIndex } from './create_index';
|
||||
import { usePageChrome } from '../../hooks/use_page_chrome';
|
||||
import { IndexManagementBreadcrumbs } from '../shared/breadcrumbs';
|
||||
|
||||
const CreateIndexLabel = i18n.translate('xpack.searchIndices.createIndex.docTitle', {
|
||||
defaultMessage: 'Create Index',
|
||||
});
|
||||
|
||||
export const CreateIndexPage = () => {
|
||||
const { console: consolePlugin } = useKibana().services;
|
||||
const {
|
||||
data: indicesData,
|
||||
isInitialLoading,
|
||||
isError: hasIndicesStatusFetchError,
|
||||
error: indicesFetchError,
|
||||
} = useIndicesStatusQuery();
|
||||
const { data: userPrivileges } = useUserPrivilegesQuery();
|
||||
|
||||
const embeddableConsole = useMemo(
|
||||
() => (consolePlugin?.EmbeddableConsole ? <consolePlugin.EmbeddableConsole /> : null),
|
||||
[consolePlugin]
|
||||
);
|
||||
usePageChrome(CreateIndexLabel, [...IndexManagementBreadcrumbs, { text: CreateIndexLabel }]);
|
||||
|
||||
return (
|
||||
<EuiPageTemplate
|
||||
offset={0}
|
||||
restrictWidth={false}
|
||||
data-test-subj="elasticsearchCreateIndexPage"
|
||||
grow={false}
|
||||
>
|
||||
<KibanaPageTemplate.Section alignment="center" restrictWidth={false} grow>
|
||||
{isInitialLoading && <EuiLoadingLogo />}
|
||||
{hasIndicesStatusFetchError && <LoadIndicesStatusError error={indicesFetchError} />}
|
||||
{!isInitialLoading && !hasIndicesStatusFetchError && (
|
||||
<CreateIndex indicesData={indicesData} userPrivileges={userPrivileges} />
|
||||
)}
|
||||
</KibanaPageTemplate.Section>
|
||||
{embeddableConsole}
|
||||
</EuiPageTemplate>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* 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, { useCallback, useState } from 'react';
|
||||
|
||||
import type { UserStartPrivilegesResponse } from '../../../common';
|
||||
import { AnalyticsEvents } from '../../analytics/constants';
|
||||
import { CreateIndexFormState } from '../../types';
|
||||
import { CreateIndexForm } from '../shared/create_index_form';
|
||||
import { useUsageTracker } from '../../hooks/use_usage_tracker';
|
||||
import { isValidIndexName } from '../../utils/indices';
|
||||
import { useCreateIndex } from '../shared/hooks/use_create_index';
|
||||
|
||||
import { useKibana } from '../../hooks/use_kibana';
|
||||
|
||||
export interface CreateIndexUIViewProps {
|
||||
formState: CreateIndexFormState;
|
||||
setFormState: (value: CreateIndexFormState) => void;
|
||||
userPrivileges?: UserStartPrivilegesResponse;
|
||||
}
|
||||
|
||||
export const CreateIndexUIView = ({
|
||||
formState,
|
||||
setFormState,
|
||||
userPrivileges,
|
||||
}: CreateIndexUIViewProps) => {
|
||||
const [indexNameHasError, setIndexNameHasError] = useState<boolean>(false);
|
||||
const { application } = useKibana().services;
|
||||
const usageTracker = useUsageTracker();
|
||||
const { createIndex, isLoading } = useCreateIndex();
|
||||
const onIndexNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const newIndexName = e.target.value;
|
||||
setFormState({ ...formState, indexName: e.target.value });
|
||||
const invalidIndexName = !isValidIndexName(newIndexName);
|
||||
if (indexNameHasError !== invalidIndexName) {
|
||||
setIndexNameHasError(invalidIndexName);
|
||||
}
|
||||
};
|
||||
const onCreateIndex = useCallback(
|
||||
(e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
if (!isValidIndexName(formState.indexName)) {
|
||||
return;
|
||||
}
|
||||
usageTracker.click(AnalyticsEvents.createIndexCreateIndexClick);
|
||||
|
||||
if (formState.defaultIndexName !== formState.indexName) {
|
||||
usageTracker.click(AnalyticsEvents.createIndexPageModifyIndexName);
|
||||
}
|
||||
|
||||
createIndex({ indexName: formState.indexName });
|
||||
},
|
||||
[usageTracker, createIndex, formState.indexName, formState.defaultIndexName]
|
||||
);
|
||||
const onFileUpload = useCallback(() => {
|
||||
usageTracker.click(AnalyticsEvents.createIndexFileUploadClick);
|
||||
application.navigateToApp('ml', { path: 'filedatavisualizer' });
|
||||
}, [usageTracker, application]);
|
||||
|
||||
return (
|
||||
<CreateIndexForm
|
||||
indexName={formState.indexName}
|
||||
indexNameHasError={indexNameHasError}
|
||||
isLoading={isLoading}
|
||||
onCreateIndex={onCreateIndex}
|
||||
onFileUpload={onFileUpload}
|
||||
onIndexNameChange={onIndexNameChange}
|
||||
userPrivileges={userPrivileges}
|
||||
showAPIKeyCreateLabel={false}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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 { useEffect, useState } from 'react';
|
||||
|
||||
import type { IndicesStatusResponse } from '../../../../common';
|
||||
|
||||
import { useKibana } from '../../../hooks/use_kibana';
|
||||
|
||||
import { getFirstNewIndexName } from '../../../utils/indices';
|
||||
import { navigateToIndexDetails } from '../../utils';
|
||||
import { useUsageTracker } from '../../../contexts/usage_tracker_context';
|
||||
import { AnalyticsEvents } from '../../../analytics/constants';
|
||||
|
||||
export const useIndicesRedirect = (indicesStatus?: IndicesStatusResponse) => {
|
||||
const { application, http } = useKibana().services;
|
||||
const [initialStatus, setInitialStatus] = useState<IndicesStatusResponse | undefined>(undefined);
|
||||
const [hasDoneRedirect, setHasDoneRedirect] = useState(() => false);
|
||||
const usageTracker = useUsageTracker();
|
||||
return useEffect(() => {
|
||||
if (hasDoneRedirect) {
|
||||
return;
|
||||
}
|
||||
if (!indicesStatus) {
|
||||
return;
|
||||
}
|
||||
if (initialStatus === undefined) {
|
||||
setInitialStatus(indicesStatus);
|
||||
return;
|
||||
}
|
||||
const newIndexName = getFirstNewIndexName(initialStatus.indexNames, indicesStatus.indexNames);
|
||||
if (newIndexName) {
|
||||
navigateToIndexDetails(application, http, newIndexName);
|
||||
setHasDoneRedirect(true);
|
||||
usageTracker.click(AnalyticsEvents.createIndexIndexCreatedRedirect);
|
||||
return;
|
||||
}
|
||||
}, [
|
||||
application,
|
||||
http,
|
||||
indicesStatus,
|
||||
initialStatus,
|
||||
setHasDoneRedirect,
|
||||
usageTracker,
|
||||
hasDoneRedirect,
|
||||
]);
|
||||
};
|
|
@ -37,20 +37,14 @@ import { SearchIndexDetailsPageMenuItemPopover } from './details_page_menu_item'
|
|||
import { useIndexDocumentSearch } from '../../hooks/api/use_document_search';
|
||||
import { useUsageTracker } from '../../contexts/usage_tracker_context';
|
||||
import { AnalyticsEvents } from '../../analytics/constants';
|
||||
import { usePageChrome } from '../../hooks/use_page_chrome';
|
||||
import { IndexManagementBreadcrumbs } from '../shared/breadcrumbs';
|
||||
|
||||
export const SearchIndexDetailsPage = () => {
|
||||
const indexName = decodeURIComponent(useParams<{ indexName: string }>().indexName);
|
||||
const tabId = decodeURIComponent(useParams<{ tabId: string }>().tabId);
|
||||
|
||||
const {
|
||||
console: consolePlugin,
|
||||
docLinks,
|
||||
application,
|
||||
history,
|
||||
share,
|
||||
chrome,
|
||||
serverless,
|
||||
} = useKibana().services;
|
||||
const { console: consolePlugin, docLinks, application, history, share } = useKibana().services;
|
||||
const {
|
||||
data: index,
|
||||
refetch,
|
||||
|
@ -82,23 +76,12 @@ export const SearchIndexDetailsPage = () => {
|
|||
setHasDocuments(!(!isInitialLoading && indexDocuments?.results?.data.length === 0));
|
||||
}, [indexDocuments, isInitialLoading, setHasDocuments, setDocumentsLoading]);
|
||||
|
||||
useEffect(() => {
|
||||
chrome.docTitle.change(indexName);
|
||||
|
||||
if (serverless) {
|
||||
serverless.setBreadcrumbs([
|
||||
{
|
||||
text: i18n.translate('xpack.searchIndices.indexBreadcrumbLabel', {
|
||||
defaultMessage: 'Index Management',
|
||||
}),
|
||||
href: '/app/management/data/index_management/indices',
|
||||
},
|
||||
{
|
||||
text: indexName,
|
||||
},
|
||||
]);
|
||||
}
|
||||
}, [chrome, indexName, serverless]);
|
||||
usePageChrome(indexName, [
|
||||
...IndexManagementBreadcrumbs,
|
||||
{
|
||||
text: indexName,
|
||||
},
|
||||
]);
|
||||
|
||||
const usageTracker = useUsageTracker();
|
||||
|
||||
|
|
|
@ -7,13 +7,17 @@
|
|||
import React from 'react';
|
||||
import { Route, Router, Routes } from '@kbn/shared-ux-router';
|
||||
import { Redirect } from 'react-router-dom';
|
||||
import { useKibana } from '../../hooks/use_kibana';
|
||||
|
||||
import { useKibana } from '../hooks/use_kibana';
|
||||
import {
|
||||
SearchIndexDetailsTabs,
|
||||
SEARCH_INDICES_DETAILS_PATH,
|
||||
SEARCH_INDICES_DETAILS_TABS_PATH,
|
||||
} from '../../routes';
|
||||
import { SearchIndexDetailsPage } from './details_page';
|
||||
CREATE_INDEX_PATH,
|
||||
} from '../routes';
|
||||
import { SearchIndexDetailsPage } from './indices/details_page';
|
||||
import { CreateIndexPage } from './create_index/create_index_page';
|
||||
|
||||
export const SearchIndicesRouter: React.FC = () => {
|
||||
const { application, history } = useKibana().services;
|
||||
return (
|
||||
|
@ -29,6 +33,7 @@ export const SearchIndicesRouter: React.FC = () => {
|
|||
/>
|
||||
</Routes>
|
||||
</Route>
|
||||
<Route exact path={CREATE_INDEX_PATH} component={CreateIndexPage} />
|
||||
<Route
|
||||
render={() => {
|
||||
application.navigateToApp('elasticsearchStart');
|
|
@ -17,19 +17,19 @@ interface APIKeyCalloutProps {
|
|||
|
||||
export const APIKeyCallout = ({ apiKey }: APIKeyCalloutProps) => {
|
||||
const title = apiKey
|
||||
? i18n.translate('xpack.searchIndices.startPage.codeView.apiKeyTitle', {
|
||||
? i18n.translate('xpack.searchIndices.shared.codeView.apiKeyTitle', {
|
||||
defaultMessage: 'Copy your API key',
|
||||
})
|
||||
: i18n.translate('xpack.searchIndices.startPage.codeView.explicitGenerate.apiKeyTitle', {
|
||||
: i18n.translate('xpack.searchIndices.shared.codeView.explicitGenerate.apiKeyTitle', {
|
||||
defaultMessage: 'Create an API key',
|
||||
});
|
||||
|
||||
const description = apiKey
|
||||
? i18n.translate('xpack.searchIndices.startPage.codeView.apiKeyDescription', {
|
||||
? i18n.translate('xpack.searchIndices.shared.codeView.apiKeyDescription', {
|
||||
defaultMessage:
|
||||
'Make sure you keep it somewhere safe. You won’t be able to retrieve it later.',
|
||||
})
|
||||
: i18n.translate('xpack.searchIndices.startPage.codeView.explicitGenerate.apiKeyDescription', {
|
||||
: i18n.translate('xpack.searchIndices.shared.codeView.explicitGenerate.apiKeyDescription', {
|
||||
defaultMessage: 'Create an API key to connect to Elasticsearch.',
|
||||
});
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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 { ChromeBreadcrumb } from '@kbn/core-chrome-browser';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export const IndexManagementBreadcrumbs: ChromeBreadcrumb[] = [
|
||||
{
|
||||
text: i18n.translate('xpack.searchIndices.breadcrumbs.indexManagement.label', {
|
||||
defaultMessage: 'Index Management',
|
||||
}),
|
||||
href: '/app/management/data/index_management',
|
||||
},
|
||||
{
|
||||
text: i18n.translate('xpack.searchIndices.breadcrumbs.indexManagement.indices.label', {
|
||||
defaultMessage: 'Indices',
|
||||
}),
|
||||
href: '/app/management/data/index_management/indices',
|
||||
},
|
||||
];
|
|
@ -4,61 +4,55 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import { TryInConsoleButton } from '@kbn/try-in-console';
|
||||
|
||||
import { useSearchApiKey } from '@kbn/search-api-keys-components';
|
||||
import { AnalyticsEvents } from '../../analytics/constants';
|
||||
import { Languages, AvailableLanguages, LanguageOptions } from '../../code_examples';
|
||||
|
||||
import { useUsageTracker } from '../../hooks/use_usage_tracker';
|
||||
import { useKibana } from '../../hooks/use_kibana';
|
||||
import { useElasticsearchUrl } from '../../hooks/use_elasticsearch_url';
|
||||
|
||||
import { CodeSample } from '../shared/code_sample';
|
||||
import { LanguageSelector } from '../shared/language_selector';
|
||||
|
||||
import { CreateIndexFormState } from './types';
|
||||
import { useStartPageCodingExamples } from './hooks/use_coding_examples';
|
||||
import { APIKeyCallout } from './api_key_callout';
|
||||
import { CodeSample } from './code_sample';
|
||||
import { useCreateIndexCodingExamples } from './hooks/use_create_index_coding_examples';
|
||||
import { LanguageSelector } from './language_selector';
|
||||
|
||||
export interface CreateIndexCodeViewProps {
|
||||
createIndexForm: CreateIndexFormState;
|
||||
selectedLanguage: AvailableLanguages;
|
||||
indexName: string;
|
||||
changeCodingLanguage: (language: AvailableLanguages) => void;
|
||||
canCreateApiKey?: boolean;
|
||||
analyticsEvents: {
|
||||
runInConsole: string;
|
||||
installCommands: string;
|
||||
createIndex: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const CreateIndexCodeView = ({
|
||||
createIndexForm,
|
||||
changeCodingLanguage,
|
||||
analyticsEvents,
|
||||
canCreateApiKey,
|
||||
changeCodingLanguage,
|
||||
indexName,
|
||||
selectedLanguage,
|
||||
}: CreateIndexCodeViewProps) => {
|
||||
const { application, share, console: consolePlugin } = useKibana().services;
|
||||
const usageTracker = useUsageTracker();
|
||||
const selectedCodeExamples = useStartPageCodingExamples();
|
||||
const selectedCodeExamples = useCreateIndexCodingExamples();
|
||||
|
||||
const { codingLanguage: selectedLanguage } = createIndexForm;
|
||||
const onSelectLanguage = useCallback(
|
||||
(value: AvailableLanguages) => {
|
||||
changeCodingLanguage(value);
|
||||
usageTracker.count([
|
||||
AnalyticsEvents.startCreateIndexLanguageSelect,
|
||||
`${AnalyticsEvents.startCreateIndexLanguageSelect}_${value}`,
|
||||
]);
|
||||
},
|
||||
[usageTracker, changeCodingLanguage]
|
||||
);
|
||||
const elasticsearchUrl = useElasticsearchUrl();
|
||||
const { apiKey, apiKeyIsVisible } = useSearchApiKey();
|
||||
|
||||
const codeParams = useMemo(() => {
|
||||
return {
|
||||
indexName: createIndexForm.indexName || undefined,
|
||||
indexName: indexName || undefined,
|
||||
elasticsearchURL: elasticsearchUrl,
|
||||
apiKey: apiKeyIsVisible && apiKey ? apiKey : undefined,
|
||||
};
|
||||
}, [createIndexForm.indexName, elasticsearchUrl, apiKeyIsVisible, apiKey]);
|
||||
}, [indexName, elasticsearchUrl, apiKeyIsVisible, apiKey]);
|
||||
const selectedCodeExample = useMemo(() => {
|
||||
return selectedCodeExamples[selectedLanguage];
|
||||
}, [selectedLanguage, selectedCodeExamples]);
|
||||
|
@ -75,7 +69,7 @@ export const CreateIndexCodeView = ({
|
|||
<LanguageSelector
|
||||
options={LanguageOptions}
|
||||
selectedLanguage={selectedLanguage}
|
||||
onSelectLanguage={onSelectLanguage}
|
||||
onSelectLanguage={changeCodingLanguage}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
|
@ -87,8 +81,8 @@ export const CreateIndexCodeView = ({
|
|||
telemetryId={`${selectedLanguage}_create_index`}
|
||||
onClick={() => {
|
||||
usageTracker.click([
|
||||
AnalyticsEvents.startCreateIndexRunInConsole,
|
||||
`${AnalyticsEvents.startCreateIndexRunInConsole}_${selectedLanguage}`,
|
||||
analyticsEvents.runInConsole,
|
||||
`${analyticsEvents.runInConsole}_${selectedLanguage}`,
|
||||
]);
|
||||
}}
|
||||
/>
|
||||
|
@ -102,8 +96,8 @@ export const CreateIndexCodeView = ({
|
|||
code={selectedCodeExample.installCommand}
|
||||
onCodeCopyClick={() => {
|
||||
usageTracker.click([
|
||||
AnalyticsEvents.startCreateIndexCodeCopyInstall,
|
||||
`${AnalyticsEvents.startCreateIndexCodeCopyInstall}_${selectedLanguage}`,
|
||||
analyticsEvents.installCommands,
|
||||
`${analyticsEvents.installCommands}_${selectedLanguage}`,
|
||||
]);
|
||||
}}
|
||||
/>
|
||||
|
@ -116,9 +110,9 @@ export const CreateIndexCodeView = ({
|
|||
code={selectedCodeExample.createIndex(codeParams)}
|
||||
onCodeCopyClick={() => {
|
||||
usageTracker.click([
|
||||
AnalyticsEvents.startCreateIndexCodeCopy,
|
||||
`${AnalyticsEvents.startCreateIndexCodeCopy}_${selectedLanguage}`,
|
||||
`${AnalyticsEvents.startCreateIndexCodeCopy}_${selectedLanguage}_${selectedCodeExamples.exampleType}`,
|
||||
analyticsEvents.createIndex,
|
||||
`${analyticsEvents.createIndex}_${selectedLanguage}`,
|
||||
`${analyticsEvents.createIndex}_${selectedLanguage}_${selectedCodeExamples.exampleType}`,
|
||||
]);
|
||||
}}
|
||||
/>
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* 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 {
|
||||
EuiButton,
|
||||
EuiFieldText,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiForm,
|
||||
EuiFormRow,
|
||||
EuiHorizontalRule,
|
||||
EuiIcon,
|
||||
EuiLink,
|
||||
EuiPanel,
|
||||
EuiSpacer,
|
||||
EuiText,
|
||||
EuiToolTip,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
|
||||
import type { UserStartPrivilegesResponse } from '../../../common';
|
||||
|
||||
export interface CreateIndexFormProps {
|
||||
indexName: string;
|
||||
indexNameHasError: boolean;
|
||||
isLoading: boolean;
|
||||
onCreateIndex: (e: React.FormEvent<HTMLFormElement>) => void;
|
||||
onFileUpload: () => void;
|
||||
onIndexNameChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
showAPIKeyCreateLabel: boolean;
|
||||
userPrivileges?: UserStartPrivilegesResponse;
|
||||
}
|
||||
|
||||
export const CreateIndexForm = ({
|
||||
indexName,
|
||||
indexNameHasError,
|
||||
isLoading,
|
||||
onCreateIndex,
|
||||
onFileUpload,
|
||||
onIndexNameChange,
|
||||
showAPIKeyCreateLabel,
|
||||
userPrivileges,
|
||||
}: CreateIndexFormProps) => {
|
||||
return (
|
||||
<>
|
||||
<EuiForm
|
||||
data-test-subj="createIndexUIView"
|
||||
fullWidth
|
||||
component="form"
|
||||
onSubmit={onCreateIndex}
|
||||
>
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.searchIndices.shared.createIndex.name.label', {
|
||||
defaultMessage: 'Name your index',
|
||||
})}
|
||||
helpText={i18n.translate('xpack.searchIndices.shared.createIndex.name.helpText', {
|
||||
defaultMessage:
|
||||
'Index names must be lowercase and can only contain hyphens and numbers',
|
||||
})}
|
||||
fullWidth
|
||||
isInvalid={indexNameHasError}
|
||||
>
|
||||
<EuiFieldText
|
||||
autoFocus
|
||||
fullWidth
|
||||
data-test-subj="indexNameField"
|
||||
name="indexName"
|
||||
value={indexName}
|
||||
isInvalid={indexNameHasError}
|
||||
disabled={userPrivileges?.privileges?.canCreateIndex === false}
|
||||
onChange={onIndexNameChange}
|
||||
placeholder={i18n.translate('xpack.searchIndices.shared.createIndex.name.placeholder', {
|
||||
defaultMessage: 'Enter a name for your index',
|
||||
})}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiSpacer />
|
||||
<EuiFlexGroup alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiToolTip
|
||||
content={
|
||||
userPrivileges?.privileges?.canCreateIndex === false ? (
|
||||
<p>
|
||||
{i18n.translate('xpack.searchIndices.shared.createIndex.permissionTooltip', {
|
||||
defaultMessage: 'You do not have permission to create an index.',
|
||||
})}
|
||||
</p>
|
||||
) : undefined
|
||||
}
|
||||
>
|
||||
<EuiButton
|
||||
fill
|
||||
color="primary"
|
||||
iconSide="left"
|
||||
iconType="sparkles"
|
||||
data-test-subj="createIndexBtn"
|
||||
disabled={
|
||||
userPrivileges?.privileges?.canCreateIndex === false ||
|
||||
indexNameHasError ||
|
||||
isLoading
|
||||
}
|
||||
isLoading={isLoading}
|
||||
type="submit"
|
||||
>
|
||||
{i18n.translate('xpack.searchIndices.shared.createIndex.action.text', {
|
||||
defaultMessage: 'Create my index',
|
||||
})}
|
||||
</EuiButton>
|
||||
</EuiToolTip>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
{showAPIKeyCreateLabel && (
|
||||
<EuiFlexGroup gutterSize="s">
|
||||
<EuiIcon size="m" type="key" color="subdued" />
|
||||
<EuiText size="s" data-test-subj="apiKeyLabel">
|
||||
<p>
|
||||
{i18n.translate(
|
||||
'xpack.searchIndices.shared.createIndex.apiKeyCreation.description',
|
||||
{
|
||||
defaultMessage: "We'll create an API key for this index",
|
||||
}
|
||||
)}
|
||||
</p>
|
||||
</EuiText>
|
||||
</EuiFlexGroup>
|
||||
)}
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiForm>
|
||||
<EuiHorizontalRule margin="none" />
|
||||
<EuiPanel color="transparent" paddingSize="s">
|
||||
<EuiFlexGroup gutterSize="s" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiIcon type="documents" />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiText color="subdued" size="s">
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.searchIndices.shared.createIndex.fileUpload.text"
|
||||
defaultMessage="Already have some data? {link}"
|
||||
values={{
|
||||
link: (
|
||||
<EuiLink data-test-subj="uploadFileLink" onClick={onFileUpload}>
|
||||
{i18n.translate('xpack.searchIndices.shared.createIndex.fileUpload.link', {
|
||||
defaultMessage: 'Upload a file',
|
||||
})}
|
||||
</EuiLink>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
* 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, { useMemo } from 'react';
|
||||
import {
|
||||
EuiButtonEmpty,
|
||||
EuiButtonGroup,
|
||||
EuiButtonIcon,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiIcon,
|
||||
EuiPanel,
|
||||
EuiSpacer,
|
||||
EuiText,
|
||||
EuiTextAlign,
|
||||
EuiTitle,
|
||||
useEuiTheme,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { docLinks } from '../../../common/doc_links';
|
||||
import { useKibana } from '../../hooks/use_kibana';
|
||||
import { CreateIndexViewMode } from '../../types';
|
||||
|
||||
const MAX_WIDTH = '650px';
|
||||
|
||||
export interface CreateIndexPanelProps {
|
||||
children: React.ReactNode | React.ReactNode[];
|
||||
createIndexView: CreateIndexViewMode;
|
||||
onChangeView: (id: string) => void;
|
||||
onClose: () => void;
|
||||
showCallouts?: boolean;
|
||||
showSkip?: boolean;
|
||||
title?: React.ReactNode;
|
||||
}
|
||||
|
||||
export const CreateIndexPanel = ({
|
||||
children,
|
||||
createIndexView,
|
||||
onChangeView,
|
||||
onClose,
|
||||
showCallouts,
|
||||
showSkip,
|
||||
title,
|
||||
}: CreateIndexPanelProps) => {
|
||||
const { cloud, http } = useKibana().services;
|
||||
const { euiTheme } = useEuiTheme();
|
||||
|
||||
const o11yTrialLink = useMemo(() => {
|
||||
if (cloud && cloud.isServerlessEnabled) {
|
||||
const baseUrl = cloud?.projectsUrl ?? 'https://cloud.elastic.co/projects/';
|
||||
return `${baseUrl}create/observability/start`;
|
||||
}
|
||||
return http.basePath.prepend('/app/observability/onboarding');
|
||||
}, [cloud, http]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<EuiPanel
|
||||
color="subdued"
|
||||
hasShadow={false}
|
||||
hasBorder
|
||||
style={{
|
||||
maxWidth: MAX_WIDTH,
|
||||
margin: '0 auto',
|
||||
padding: euiTheme.size.l,
|
||||
paddingTop: euiTheme.size.m,
|
||||
}}
|
||||
>
|
||||
<EuiFlexGroup justifyContent="flexEnd">
|
||||
<EuiButtonIcon
|
||||
data-test-subj="closeCreateIndex"
|
||||
iconType="cross"
|
||||
onClick={onClose}
|
||||
color="text"
|
||||
aria-label={i18n.translate('xpack.searchIndices.shared.createIndex.closeAriaLabel', {
|
||||
defaultMessage: 'Close create index',
|
||||
})}
|
||||
/>
|
||||
</EuiFlexGroup>
|
||||
<EuiPanel
|
||||
color="transparent"
|
||||
paddingSize="none"
|
||||
style={{
|
||||
paddingLeft: euiTheme.size.m,
|
||||
paddingRight: euiTheme.size.m,
|
||||
}}
|
||||
>
|
||||
<EuiFlexGroup alignItems="center" gutterSize="m">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiIcon type="logoElasticsearch" size="xl" />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="xs">
|
||||
<h1>
|
||||
{i18n.translate('xpack.searchIndices.shared.createIndex.pageTitle', {
|
||||
defaultMessage: 'Elasticsearch',
|
||||
})}
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiTitle size="l">
|
||||
<h2>
|
||||
{i18n.translate('xpack.searchIndices.shared.createIndex.pageDescription', {
|
||||
defaultMessage: 'Get started with Elasticsearch',
|
||||
})}
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
</EuiPanel>
|
||||
<EuiSpacer size="l" />
|
||||
<EuiPanel>
|
||||
<EuiFlexGroup direction="column" gutterSize="m">
|
||||
<EuiFlexGroup alignItems="center">
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="xs">
|
||||
<h4>
|
||||
{title ??
|
||||
i18n.translate('xpack.searchIndices.shared.createIndex.defaultTitle', {
|
||||
defaultMessage: 'Create an index',
|
||||
})}
|
||||
</h4>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonGroup
|
||||
legend={i18n.translate(
|
||||
'xpack.searchIndices.shared.createIndex.viewSelect.legend',
|
||||
{
|
||||
defaultMessage: 'Create index view selection',
|
||||
}
|
||||
)}
|
||||
options={[
|
||||
{
|
||||
id: CreateIndexViewMode.UI,
|
||||
label: i18n.translate(
|
||||
'xpack.searchIndices.shared.createIndex.viewSelect.ui',
|
||||
{
|
||||
defaultMessage: 'UI',
|
||||
}
|
||||
),
|
||||
'data-test-subj': 'createIndexUIViewBtn',
|
||||
},
|
||||
{
|
||||
id: CreateIndexViewMode.Code,
|
||||
label: i18n.translate(
|
||||
'xpack.searchIndices.shared.createIndex.viewSelect.code',
|
||||
{
|
||||
defaultMessage: 'Code',
|
||||
}
|
||||
),
|
||||
'data-test-subj': 'createIndexCodeViewBtn',
|
||||
},
|
||||
]}
|
||||
buttonSize="compressed"
|
||||
idSelected={createIndexView}
|
||||
onChange={onChangeView}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiText color="subdued">
|
||||
<p>
|
||||
{i18n.translate('xpack.searchIndices.shared.createIndex.description', {
|
||||
defaultMessage:
|
||||
'An index stores your data and defines the schema, or field mappings, for your searches',
|
||||
})}
|
||||
</p>
|
||||
</EuiText>
|
||||
{children}
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
{showCallouts && (
|
||||
<>
|
||||
<EuiSpacer />
|
||||
<EuiPanel color="transparent">
|
||||
<EuiTextAlign textAlign="center">
|
||||
<EuiTitle size="xs">
|
||||
<h5>
|
||||
{i18n.translate(
|
||||
'xpack.searchIndices.shared.createIndex.observabilityCallout.title',
|
||||
{
|
||||
defaultMessage: 'Looking to store your logs or metrics data?',
|
||||
}
|
||||
)}
|
||||
</h5>
|
||||
</EuiTitle>
|
||||
</EuiTextAlign>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiFlexGroup alignItems="center" justifyContent="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
color="text"
|
||||
iconSide="right"
|
||||
iconType="popout"
|
||||
data-test-subj="analyzeLogsBtn"
|
||||
href={docLinks.analyzeLogs}
|
||||
target="_blank"
|
||||
>
|
||||
{i18n.translate(
|
||||
'xpack.searchIndices.shared.createIndex.observabilityCallout.logs.button',
|
||||
{
|
||||
defaultMessage: 'Collect and analyze logs',
|
||||
}
|
||||
)}
|
||||
</EuiButtonEmpty>
|
||||
<EuiText color="subdued" size="s" textAlign="center">
|
||||
<small>
|
||||
{i18n.translate(
|
||||
'xpack.searchIndices.shared.createIndex.observabilityCallout.logs.subTitle',
|
||||
{
|
||||
defaultMessage: 'Explore Logstash and Beats',
|
||||
}
|
||||
)}
|
||||
</small>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText>or</EuiText>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
color="text"
|
||||
iconSide="right"
|
||||
iconType="popout"
|
||||
data-test-subj="startO11yTrialBtn"
|
||||
href={o11yTrialLink}
|
||||
target="_blank"
|
||||
>
|
||||
{i18n.translate(
|
||||
'xpack.searchIndices.shared.createIndex.observabilityCallout.o11yTrial.button',
|
||||
{
|
||||
defaultMessage: 'Start an Observability trial',
|
||||
}
|
||||
)}
|
||||
</EuiButtonEmpty>
|
||||
<EuiText color="subdued" size="s" textAlign="center">
|
||||
<small>
|
||||
{i18n.translate(
|
||||
'xpack.searchIndices.shared.createIndex.observabilityCallout.o11yTrial.subTitle',
|
||||
{
|
||||
defaultMessage: 'Powerful performance monitoring',
|
||||
}
|
||||
)}
|
||||
</small>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
</>
|
||||
)}
|
||||
</EuiPanel>
|
||||
{showSkip === true && (
|
||||
<>
|
||||
<EuiSpacer />
|
||||
<EuiFlexGroup justifyContent="center">
|
||||
<EuiButtonEmpty onClick={onClose} data-test-subj="createIndexSkipBtn">
|
||||
{i18n.translate('xpack.searchIndices.shared.createIndex.skipLabel', {
|
||||
defaultMessage: 'Skip',
|
||||
})}
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexGroup>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -11,7 +11,7 @@ import { useCreateIndex as useCreateIndexApi } from '../../../hooks/api/use_crea
|
|||
|
||||
import { useKibana } from '../../../hooks/use_kibana';
|
||||
|
||||
import { navigateToIndexDetails } from './utils';
|
||||
import { navigateToIndexDetails } from '../../utils';
|
||||
|
||||
export const useCreateIndex = () => {
|
||||
const { application, http } = useKibana().services;
|
|
@ -8,7 +8,7 @@
|
|||
import { CreateIndexCodeExamples } from '../../../types';
|
||||
import { DenseVectorSeverlessCodeExamples } from '../../../code_examples/create_index';
|
||||
|
||||
export const useStartPageCodingExamples = (): CreateIndexCodeExamples => {
|
||||
export const useCreateIndexCodingExamples = (): CreateIndexCodeExamples => {
|
||||
// TODO: in the future this will be dynamic based on the onboarding token
|
||||
// or project sub-type
|
||||
return DenseVectorSeverlessCodeExamples;
|
|
@ -15,14 +15,14 @@ export interface StartPageErrorProps {
|
|||
error: unknown;
|
||||
}
|
||||
|
||||
export const StartPageError = ({ error }: StartPageErrorProps) => {
|
||||
export const LoadIndicesStatusError = ({ error }: StartPageErrorProps) => {
|
||||
return (
|
||||
<EuiEmptyPrompt
|
||||
iconType="error"
|
||||
color="danger"
|
||||
title={
|
||||
<h2>
|
||||
{i18n.translate('xpack.searchIndices.startPage.statusFetchError.title', {
|
||||
{i18n.translate('xpack.searchIndices.shared.statusFetchError.title', {
|
||||
defaultMessage: 'Error loading indices',
|
||||
})}
|
||||
</h2>
|
||||
|
@ -31,7 +31,7 @@ export const StartPageError = ({ error }: StartPageErrorProps) => {
|
|||
<EuiCodeBlock css={{ textAlign: 'left' }}>
|
||||
{getErrorMessage(
|
||||
error,
|
||||
i18n.translate('xpack.searchIndices.startPage.statusFetchError.unknownError', {
|
||||
i18n.translate('xpack.searchIndices.shared.statusFetchError.unknownError', {
|
||||
defaultMessage: 'Unknown error fetching indices.',
|
||||
})
|
||||
)}
|
|
@ -6,52 +6,29 @@
|
|||
*/
|
||||
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import {
|
||||
EuiButton,
|
||||
EuiFieldText,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiForm,
|
||||
EuiFormRow,
|
||||
EuiHorizontalRule,
|
||||
EuiIcon,
|
||||
EuiLink,
|
||||
EuiPanel,
|
||||
EuiSpacer,
|
||||
EuiText,
|
||||
EuiToolTip,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
|
||||
import type { UserStartPrivilegesResponse } from '../../../common';
|
||||
import { AnalyticsEvents } from '../../analytics/constants';
|
||||
import { useUsageTracker } from '../../hooks/use_usage_tracker';
|
||||
import { CreateIndexFormState } from '../../types';
|
||||
import { isValidIndexName } from '../../utils/indices';
|
||||
|
||||
import { useCreateIndex } from './hooks/use_create_index';
|
||||
import { useCreateIndex } from '../shared/hooks/use_create_index';
|
||||
import { CreateIndexForm } from '../shared/create_index_form';
|
||||
|
||||
import { CreateIndexFormState } from './types';
|
||||
import { useKibana } from '../../hooks/use_kibana';
|
||||
|
||||
const CREATE_INDEX_CONTENT = i18n.translate(
|
||||
'xpack.searchIndices.startPage.createIndex.action.text',
|
||||
{
|
||||
defaultMessage: 'Create my index',
|
||||
}
|
||||
);
|
||||
|
||||
export interface CreateIndexFormProps {
|
||||
export interface CreateIndexUIViewProps {
|
||||
formState: CreateIndexFormState;
|
||||
setFormState: React.Dispatch<React.SetStateAction<CreateIndexFormState>>;
|
||||
userPrivileges?: UserStartPrivilegesResponse;
|
||||
}
|
||||
|
||||
export const CreateIndexForm = ({
|
||||
export const CreateIndexUIView = ({
|
||||
userPrivileges,
|
||||
formState,
|
||||
setFormState,
|
||||
}: CreateIndexFormProps) => {
|
||||
}: CreateIndexUIViewProps) => {
|
||||
const { application } = useKibana().services;
|
||||
const [indexNameHasError, setIndexNameHasError] = useState<boolean>(false);
|
||||
const usageTracker = useUsageTracker();
|
||||
|
@ -86,129 +63,15 @@ export const CreateIndexForm = ({
|
|||
}, [usageTracker, application]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<EuiForm
|
||||
data-test-subj="createIndexUIView"
|
||||
fullWidth
|
||||
component="form"
|
||||
onSubmit={onCreateIndex}
|
||||
>
|
||||
<EuiFormRow
|
||||
label={i18n.translate('xpack.searchIndices.startPage.createIndex.name.label', {
|
||||
defaultMessage: 'Name your index',
|
||||
})}
|
||||
helpText={i18n.translate('xpack.searchIndices.startPage.createIndex.name.helpText', {
|
||||
defaultMessage:
|
||||
'Index names must be lowercase and can only contain hyphens and numbers',
|
||||
})}
|
||||
fullWidth
|
||||
isInvalid={indexNameHasError}
|
||||
>
|
||||
<EuiFieldText
|
||||
autoFocus
|
||||
fullWidth
|
||||
data-test-subj="indexNameField"
|
||||
name="indexName"
|
||||
value={formState.indexName}
|
||||
isInvalid={indexNameHasError}
|
||||
disabled={userPrivileges?.privileges?.canCreateIndex === false}
|
||||
onChange={onIndexNameChange}
|
||||
placeholder={i18n.translate(
|
||||
'xpack.searchIndices.startPage.createIndex.name.placeholder',
|
||||
{
|
||||
defaultMessage: 'Enter a name for your index',
|
||||
}
|
||||
)}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiSpacer />
|
||||
<EuiFlexGroup alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
{userPrivileges?.privileges?.canCreateIndex === false ? (
|
||||
<EuiToolTip
|
||||
content={
|
||||
<p>
|
||||
{i18n.translate('xpack.searchIndices.startPage.createIndex.permissionTooltip', {
|
||||
defaultMessage: 'You do not have permission to create an index.',
|
||||
})}
|
||||
</p>
|
||||
}
|
||||
>
|
||||
<EuiButton
|
||||
fill
|
||||
color="primary"
|
||||
iconSide="left"
|
||||
iconType="sparkles"
|
||||
data-test-subj="createIndexBtn"
|
||||
disabled={true}
|
||||
>
|
||||
{CREATE_INDEX_CONTENT}
|
||||
</EuiButton>
|
||||
</EuiToolTip>
|
||||
) : (
|
||||
<EuiButton
|
||||
fill
|
||||
color="primary"
|
||||
iconSide="left"
|
||||
iconType="sparkles"
|
||||
data-test-subj="createIndexBtn"
|
||||
disabled={indexNameHasError || isLoading}
|
||||
isLoading={isLoading}
|
||||
type="submit"
|
||||
>
|
||||
{CREATE_INDEX_CONTENT}
|
||||
</EuiButton>
|
||||
)}
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
{userPrivileges?.privileges?.canCreateApiKeys && (
|
||||
<EuiFlexGroup gutterSize="s">
|
||||
<EuiIcon size="m" type="key" color="subdued" />
|
||||
<EuiText size="s" data-test-subj="apiKeyLabel">
|
||||
<p>
|
||||
{i18n.translate(
|
||||
'xpack.searchIndices.startPage.createIndex.apiKeyCreation.description',
|
||||
{
|
||||
defaultMessage: "We'll create an API key for this index",
|
||||
}
|
||||
)}
|
||||
</p>
|
||||
</EuiText>
|
||||
</EuiFlexGroup>
|
||||
)}
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiForm>
|
||||
<EuiHorizontalRule margin="none" />
|
||||
<EuiPanel color="transparent" paddingSize="s">
|
||||
<EuiFlexGroup gutterSize="s" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiIcon type="documents" />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiText color="subdued" size="s">
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.searchIndices.startPage.createIndex.fileUpload.text"
|
||||
defaultMessage="Already have some data? {link}"
|
||||
values={{
|
||||
link: (
|
||||
<EuiLink data-test-subj="uploadFileLink" onClick={onFileUpload}>
|
||||
{i18n.translate(
|
||||
'xpack.searchIndices.startPage.createIndex.fileUpload.link',
|
||||
{
|
||||
defaultMessage: 'Upload a file',
|
||||
}
|
||||
)}
|
||||
</EuiLink>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
</>
|
||||
<CreateIndexForm
|
||||
indexName={formState.indexName}
|
||||
indexNameHasError={indexNameHasError}
|
||||
isLoading={isLoading}
|
||||
onCreateIndex={onCreateIndex}
|
||||
onFileUpload={onFileUpload}
|
||||
onIndexNameChange={onIndexNameChange}
|
||||
showAPIKeyCreateLabel={userPrivileges?.privileges.canCreateApiKeys ?? false}
|
||||
userPrivileges={userPrivileges}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -5,23 +5,10 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import {
|
||||
EuiButtonEmpty,
|
||||
EuiButtonGroup,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiIcon,
|
||||
EuiPanel,
|
||||
EuiSpacer,
|
||||
EuiText,
|
||||
EuiTextAlign,
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import type { IndicesStatusResponse, UserStartPrivilegesResponse } from '../../../common';
|
||||
import { docLinks } from '../../../common/doc_links';
|
||||
|
||||
import { AnalyticsEvents } from '../../analytics/constants';
|
||||
import { AvailableLanguages } from '../../code_examples';
|
||||
|
@ -29,9 +16,11 @@ import { useUsageTracker } from '../../hooks/use_usage_tracker';
|
|||
import { generateRandomIndexName } from '../../utils/indices';
|
||||
import { getDefaultCodingLanguage } from '../../utils/language';
|
||||
|
||||
import { CreateIndexForm } from './create_index';
|
||||
import { CreateIndexCodeView } from './create_index_code';
|
||||
import { CreateIndexFormState } from './types';
|
||||
import { CreateIndexUIView } from './create_index';
|
||||
import { CreateIndexCodeView } from '../shared/create_index_code_view';
|
||||
import { CreateIndexFormState, CreateIndexViewMode } from '../../types';
|
||||
|
||||
import { CreateIndexPanel } from '../shared/create_index_panel';
|
||||
import { useKibana } from '../../hooks/use_kibana';
|
||||
|
||||
function initCreateIndexState(): CreateIndexFormState {
|
||||
|
@ -43,21 +32,17 @@ function initCreateIndexState(): CreateIndexFormState {
|
|||
};
|
||||
}
|
||||
|
||||
const MAX_WIDTH = '650px';
|
||||
|
||||
enum CreateIndexView {
|
||||
UI = 'ui',
|
||||
Code = 'code',
|
||||
}
|
||||
export interface ElasticsearchStartProps {
|
||||
indicesData?: IndicesStatusResponse;
|
||||
userPrivileges?: UserStartPrivilegesResponse;
|
||||
}
|
||||
|
||||
export const ElasticsearchStart = ({ userPrivileges }: ElasticsearchStartProps) => {
|
||||
const { cloud, http } = useKibana().services;
|
||||
const [createIndexView, setCreateIndexView] = useState<CreateIndexView>(
|
||||
userPrivileges?.privileges.canCreateIndex === false ? CreateIndexView.Code : CreateIndexView.UI
|
||||
const { application } = useKibana().services;
|
||||
const [createIndexView, setCreateIndexViewMode] = useState<CreateIndexViewMode>(
|
||||
userPrivileges?.privileges.canCreateIndex === false
|
||||
? CreateIndexViewMode.Code
|
||||
: CreateIndexViewMode.UI
|
||||
);
|
||||
const [formState, setFormState] = useState<CreateIndexFormState>(initCreateIndexState);
|
||||
const usageTracker = useUsageTracker();
|
||||
|
@ -68,28 +53,20 @@ export const ElasticsearchStart = ({ userPrivileges }: ElasticsearchStartProps)
|
|||
useEffect(() => {
|
||||
if (userPrivileges === undefined) return;
|
||||
if (userPrivileges.privileges.canCreateIndex === false) {
|
||||
setCreateIndexView(CreateIndexView.Code);
|
||||
setCreateIndexViewMode(CreateIndexViewMode.Code);
|
||||
}
|
||||
}, [userPrivileges]);
|
||||
|
||||
const o11yTrialLink = useMemo(() => {
|
||||
if (cloud && cloud.isServerlessEnabled) {
|
||||
const baseUrl = cloud?.projectsUrl ?? 'https://cloud.elastic.co/projects/';
|
||||
return `${baseUrl}create/observability/start`;
|
||||
}
|
||||
return http.basePath.prepend('/app/observability/onboarding');
|
||||
}, [cloud, http]);
|
||||
|
||||
const onChangeView = useCallback(
|
||||
(id: string) => {
|
||||
switch (id) {
|
||||
case CreateIndexView.UI:
|
||||
case CreateIndexViewMode.UI:
|
||||
usageTracker.click(AnalyticsEvents.startPageShowCreateIndexUIClick);
|
||||
setCreateIndexView(CreateIndexView.UI);
|
||||
setCreateIndexViewMode(CreateIndexViewMode.UI);
|
||||
return;
|
||||
case CreateIndexView.Code:
|
||||
case CreateIndexViewMode.Code:
|
||||
usageTracker.click(AnalyticsEvents.startPageShowCodeClick);
|
||||
setCreateIndexView(CreateIndexView.Code);
|
||||
setCreateIndexViewMode(CreateIndexViewMode.Code);
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
@ -101,178 +78,48 @@ export const ElasticsearchStart = ({ userPrivileges }: ElasticsearchStartProps)
|
|||
...formState,
|
||||
codingLanguage: language,
|
||||
});
|
||||
usageTracker.count([
|
||||
AnalyticsEvents.startCreateIndexLanguageSelect,
|
||||
`${AnalyticsEvents.startCreateIndexLanguageSelect}_${language}`,
|
||||
]);
|
||||
},
|
||||
[formState, setFormState]
|
||||
[usageTracker, formState, setFormState]
|
||||
);
|
||||
const onClose = useCallback(() => {
|
||||
application.navigateToApp('management', { deepLinkId: 'index_management' });
|
||||
}, [application]);
|
||||
|
||||
return (
|
||||
<EuiPanel
|
||||
color="subdued"
|
||||
hasShadow={false}
|
||||
hasBorder
|
||||
paddingSize="l"
|
||||
style={{ maxWidth: MAX_WIDTH, margin: '0 auto' }}
|
||||
<CreateIndexPanel
|
||||
title={i18n.translate('xpack.searchIndices.startPage.createIndex.title', {
|
||||
defaultMessage: 'Create your first index',
|
||||
})}
|
||||
createIndexView={createIndexView}
|
||||
onChangeView={onChangeView}
|
||||
onClose={onClose}
|
||||
showSkip
|
||||
showCallouts
|
||||
>
|
||||
<EuiPanel color="transparent" paddingSize="m">
|
||||
<EuiFlexGroup alignItems="center" gutterSize="m">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiIcon type="logoElasticsearch" size="xl" />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="xs">
|
||||
<h1>
|
||||
{i18n.translate('xpack.searchIndices.startPage.pageTitle', {
|
||||
defaultMessage: 'Elasticsearch',
|
||||
})}
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiTitle size="l">
|
||||
<h2>
|
||||
{i18n.translate('xpack.searchIndices.startPage.pageDescription', {
|
||||
defaultMessage: 'Vectorize, search, and visualize your data',
|
||||
})}
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
</EuiPanel>
|
||||
<EuiSpacer />
|
||||
<EuiPanel>
|
||||
<EuiFlexGroup direction="column" gutterSize="m">
|
||||
<EuiFlexGroup alignItems="center">
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="xs">
|
||||
<h4>
|
||||
{i18n.translate('xpack.searchIndices.startPage.createIndex.title', {
|
||||
defaultMessage: 'Create your first index',
|
||||
})}
|
||||
</h4>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonGroup
|
||||
legend={i18n.translate(
|
||||
'xpack.searchIndices.startPage.createIndex.viewSelec.legend',
|
||||
{ defaultMessage: 'Create index view selection' }
|
||||
)}
|
||||
options={[
|
||||
{
|
||||
id: CreateIndexView.UI,
|
||||
label: i18n.translate(
|
||||
'xpack.searchIndices.startPage.createIndex.viewSelect.ui',
|
||||
{ defaultMessage: 'UI' }
|
||||
),
|
||||
'data-test-subj': 'createIndexUIViewBtn',
|
||||
},
|
||||
{
|
||||
id: CreateIndexView.Code,
|
||||
label: i18n.translate(
|
||||
'xpack.searchIndices.startPage.createIndex.viewSelect.code',
|
||||
{ defaultMessage: 'Code' }
|
||||
),
|
||||
'data-test-subj': 'createIndexCodeViewBtn',
|
||||
},
|
||||
]}
|
||||
buttonSize="compressed"
|
||||
idSelected={createIndexView}
|
||||
onChange={onChangeView}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiText color="subdued">
|
||||
<p>
|
||||
{i18n.translate('xpack.searchIndices.startPage.createIndex.description', {
|
||||
defaultMessage:
|
||||
'An index stores your data and defines the schema, or field mappings, for your searches',
|
||||
})}
|
||||
</p>
|
||||
</EuiText>
|
||||
{createIndexView === CreateIndexView.UI && (
|
||||
<CreateIndexForm
|
||||
userPrivileges={userPrivileges}
|
||||
formState={formState}
|
||||
setFormState={setFormState}
|
||||
/>
|
||||
)}
|
||||
{createIndexView === CreateIndexView.Code && (
|
||||
<CreateIndexCodeView
|
||||
createIndexForm={formState}
|
||||
changeCodingLanguage={onChangeCodingLanguage}
|
||||
canCreateApiKey={userPrivileges?.privileges.canCreateApiKeys}
|
||||
/>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
<EuiSpacer />
|
||||
<EuiPanel color="transparent">
|
||||
<EuiTextAlign textAlign="center">
|
||||
<EuiTitle size="xs">
|
||||
<h5>
|
||||
{i18n.translate('xpack.searchIndices.startPage.observabilityCallout.title', {
|
||||
defaultMessage: 'Looking to store your logs or metrics data?',
|
||||
})}
|
||||
</h5>
|
||||
</EuiTitle>
|
||||
</EuiTextAlign>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiFlexGroup alignItems="center" justifyContent="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
color="text"
|
||||
iconSide="right"
|
||||
iconType="popout"
|
||||
data-test-subj="analyzeLogsBtn"
|
||||
href={docLinks.analyzeLogs}
|
||||
target="_blank"
|
||||
>
|
||||
{i18n.translate('xpack.searchIndices.startPage.observabilityCallout.logs.button', {
|
||||
defaultMessage: 'Collect and analyze logs',
|
||||
})}
|
||||
</EuiButtonEmpty>
|
||||
<EuiText color="subdued" size="s" textAlign="center">
|
||||
<small>
|
||||
{i18n.translate(
|
||||
'xpack.searchIndices.startPage.observabilityCallout.logs.subTitle',
|
||||
{
|
||||
defaultMessage: 'Explore Logstash and Beats',
|
||||
}
|
||||
)}
|
||||
</small>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText>or</EuiText>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
color="text"
|
||||
iconSide="right"
|
||||
iconType="popout"
|
||||
data-test-subj="startO11yTrialBtn"
|
||||
href={o11yTrialLink}
|
||||
target="_blank"
|
||||
>
|
||||
{i18n.translate(
|
||||
'xpack.searchIndices.startPage.observabilityCallout.o11yTrial.button',
|
||||
{
|
||||
defaultMessage: 'Start an Observability trial',
|
||||
}
|
||||
)}
|
||||
</EuiButtonEmpty>
|
||||
<EuiText color="subdued" size="s" textAlign="center">
|
||||
<small>
|
||||
{i18n.translate(
|
||||
'xpack.searchIndices.startPage.observabilityCallout.o11yTrial.subTitle',
|
||||
{
|
||||
defaultMessage: 'Powerful performance monitoring',
|
||||
}
|
||||
)}
|
||||
</small>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
</EuiPanel>
|
||||
{createIndexView === CreateIndexViewMode.UI && (
|
||||
<CreateIndexUIView
|
||||
userPrivileges={userPrivileges}
|
||||
formState={formState}
|
||||
setFormState={setFormState}
|
||||
/>
|
||||
)}
|
||||
{createIndexView === CreateIndexViewMode.Code && (
|
||||
<CreateIndexCodeView
|
||||
selectedLanguage={formState.codingLanguage}
|
||||
indexName={formState.indexName}
|
||||
changeCodingLanguage={onChangeCodingLanguage}
|
||||
canCreateApiKey={userPrivileges?.privileges.canCreateApiKeys}
|
||||
analyticsEvents={{
|
||||
runInConsole: AnalyticsEvents.startCreateIndexRunInConsole,
|
||||
installCommands: AnalyticsEvents.startCreateIndexCodeCopyInstall,
|
||||
createIndex: AnalyticsEvents.startCreateIndexCodeCopy,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</CreateIndexPanel>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -11,7 +11,7 @@ import type { IndicesStatusResponse } from '../../../../common';
|
|||
|
||||
import { useKibana } from '../../../hooks/use_kibana';
|
||||
|
||||
import { navigateToIndexDetails } from './utils';
|
||||
import { navigateToIndexDetails } from '../../utils';
|
||||
import { useUsageTracker } from '../../../contexts/usage_tracker_context';
|
||||
import { AnalyticsEvents } from '../../../analytics/constants';
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
import React, { useMemo } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { EuiLoadingLogo, EuiPageTemplate } from '@elastic/eui';
|
||||
import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';
|
||||
|
@ -16,7 +17,13 @@ import { useUserPrivilegesQuery } from '../../hooks/api/use_user_permissions';
|
|||
|
||||
import { useIndicesRedirect } from './hooks/use_indices_redirect';
|
||||
import { ElasticsearchStart } from './elasticsearch_start';
|
||||
import { StartPageError } from './status_error';
|
||||
import { LoadIndicesStatusError } from '../shared/load_indices_status_error';
|
||||
import { IndexManagementBreadcrumbs } from '../shared/breadcrumbs';
|
||||
import { usePageChrome } from '../../hooks/use_page_chrome';
|
||||
|
||||
const PageTitle = i18n.translate('xpack.searchIndices.startPage.docTitle', {
|
||||
defaultMessage: 'Create your first index',
|
||||
});
|
||||
|
||||
export const ElasticsearchStartPage = () => {
|
||||
const { console: consolePlugin } = useKibana().services;
|
||||
|
@ -27,6 +34,7 @@ export const ElasticsearchStartPage = () => {
|
|||
error: indicesFetchError,
|
||||
} = useIndicesStatusQuery();
|
||||
const { data: userPrivileges } = useUserPrivilegesQuery();
|
||||
usePageChrome(PageTitle, [...IndexManagementBreadcrumbs, { text: PageTitle }]);
|
||||
|
||||
const embeddableConsole = useMemo(
|
||||
() => (consolePlugin?.EmbeddableConsole ? <consolePlugin.EmbeddableConsole /> : null),
|
||||
|
@ -43,7 +51,7 @@ export const ElasticsearchStartPage = () => {
|
|||
>
|
||||
<KibanaPageTemplate.Section alignment="center" restrictWidth={false} grow>
|
||||
{isInitialLoading && <EuiLoadingLogo />}
|
||||
{hasIndicesStatusFetchError && <StartPageError error={indicesFetchError} />}
|
||||
{hasIndicesStatusFetchError && <LoadIndicesStatusError error={indicesFetchError} />}
|
||||
{!isInitialLoading && !hasIndicesStatusFetchError && (
|
||||
<ElasticsearchStart indicesData={indicesData} userPrivileges={userPrivileges} />
|
||||
)}
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
/*
|
||||
* 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 type { AvailableLanguages } from '../../code_examples';
|
||||
|
||||
export interface CreateIndexFormState {
|
||||
indexName: string;
|
||||
defaultIndexName: string;
|
||||
codingLanguage: AvailableLanguages;
|
||||
}
|
|
@ -5,12 +5,15 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { ApplicationStart, HttpSetup } from '@kbn/core/public';
|
||||
import { generatePath } from 'react-router-dom';
|
||||
|
||||
const INDEX_DETAILS_PATH = '/app/elasticsearch/indices/index_details';
|
||||
import type { ApplicationStart, HttpSetup } from '@kbn/core/public';
|
||||
import { INDICES_APP_BASE, SEARCH_INDICES_DETAILS_PATH } from '../routes';
|
||||
|
||||
const INDEX_DETAILS_FULL_PATH = `${INDICES_APP_BASE}${SEARCH_INDICES_DETAILS_PATH}`;
|
||||
|
||||
function getIndexDetailsPath(http: HttpSetup, indexName: string) {
|
||||
return http.basePath.prepend(`${INDEX_DETAILS_PATH}/${encodeURIComponent(indexName)}`);
|
||||
return http.basePath.prepend(generatePath(INDEX_DETAILS_FULL_PATH, { indexName }));
|
||||
}
|
||||
|
||||
export const navigateToIndexDetails = (
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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 { useEffect } from 'react';
|
||||
import type { ChromeBreadcrumb } from '@kbn/core-chrome-browser';
|
||||
import { useKibana } from './use_kibana';
|
||||
|
||||
export const usePageChrome = (docTitle: string, breadcrumbs: ChromeBreadcrumb[]) => {
|
||||
const { chrome, http, serverless } = useKibana().services;
|
||||
|
||||
useEffect(() => {
|
||||
chrome.docTitle.change(docTitle);
|
||||
const newBreadcrumbs = breadcrumbs.map((breadcrumb) => {
|
||||
if (breadcrumb.href && http.basePath.get().length > 0) {
|
||||
breadcrumb.href = http.basePath.prepend(breadcrumb.href);
|
||||
}
|
||||
return breadcrumb;
|
||||
});
|
||||
if (serverless) {
|
||||
serverless.setBreadcrumbs(newBreadcrumbs);
|
||||
} else {
|
||||
chrome.setBreadcrumbs(newBreadcrumbs);
|
||||
}
|
||||
return () => {
|
||||
// clear manually set breadcrumbs
|
||||
if (serverless) {
|
||||
serverless.setBreadcrumbs([]);
|
||||
} else {
|
||||
chrome.setBreadcrumbs([]);
|
||||
}
|
||||
};
|
||||
}, [breadcrumbs, chrome, docTitle, http.basePath, serverless]);
|
||||
};
|
29
x-pack/plugins/search_indices/public/locators.ts
Normal file
29
x-pack/plugins/search_indices/public/locators.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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 type { LocatorDefinition } from '@kbn/share-plugin/common';
|
||||
import type { SharePluginSetup } from '@kbn/share-plugin/public';
|
||||
import type { SerializableRecord } from '@kbn/utility-types';
|
||||
|
||||
import { INDICES_APP_ID } from '../common';
|
||||
import { CREATE_INDEX_PATH } from './routes';
|
||||
|
||||
export function registerLocators(share: SharePluginSetup) {
|
||||
share.url.locators.create<SerializableRecord>(new CreateIndexLocatorDefinition());
|
||||
}
|
||||
|
||||
class CreateIndexLocatorDefinition implements LocatorDefinition<SerializableRecord> {
|
||||
public readonly getLocation = async () => {
|
||||
return {
|
||||
app: INDICES_APP_ID,
|
||||
path: CREATE_INDEX_PATH,
|
||||
state: {},
|
||||
};
|
||||
};
|
||||
|
||||
public readonly id = 'SEARCH_CREATE_INDEX';
|
||||
}
|
|
@ -6,10 +6,12 @@
|
|||
*/
|
||||
|
||||
import type { CoreSetup, CoreStart, Plugin } from '@kbn/core/public';
|
||||
import { SEARCH_INDICES_CREATE_INDEX } from '@kbn/deeplinks-search/constants';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { docLinks } from '../common/doc_links';
|
||||
import type {
|
||||
AppPluginSetupDependencies,
|
||||
SearchIndicesAppPluginStartDependencies,
|
||||
SearchIndicesPluginSetup,
|
||||
SearchIndicesPluginStart,
|
||||
|
@ -17,7 +19,13 @@ import type {
|
|||
} from './types';
|
||||
import { initQueryClient } from './services/query_client';
|
||||
import { INDICES_APP_ID, START_APP_ID } from '../common';
|
||||
import { INDICES_APP_BASE, START_APP_BASE, SearchIndexDetailsTabValues } from './routes';
|
||||
import {
|
||||
CREATE_INDEX_PATH,
|
||||
INDICES_APP_BASE,
|
||||
START_APP_BASE,
|
||||
SearchIndexDetailsTabValues,
|
||||
} from './routes';
|
||||
import { registerLocators } from './locators';
|
||||
|
||||
export class SearchIndicesPlugin
|
||||
implements Plugin<SearchIndicesPluginSetup, SearchIndicesPluginStart>
|
||||
|
@ -25,7 +33,8 @@ export class SearchIndicesPlugin
|
|||
private pluginEnabled: boolean = false;
|
||||
|
||||
public setup(
|
||||
core: CoreSetup<SearchIndicesAppPluginStartDependencies, SearchIndicesPluginStart>
|
||||
core: CoreSetup<SearchIndicesAppPluginStartDependencies, SearchIndicesPluginStart>,
|
||||
plugins: AppPluginSetupDependencies
|
||||
): SearchIndicesPluginSetup {
|
||||
this.pluginEnabled = true;
|
||||
|
||||
|
@ -51,12 +60,21 @@ export class SearchIndicesPlugin
|
|||
core.application.register({
|
||||
id: INDICES_APP_ID,
|
||||
appRoute: INDICES_APP_BASE,
|
||||
deepLinks: [
|
||||
{
|
||||
id: SEARCH_INDICES_CREATE_INDEX,
|
||||
path: CREATE_INDEX_PATH,
|
||||
title: i18n.translate('xpack.searchIndices.elasticsearchIndices.createIndexTitle', {
|
||||
defaultMessage: 'Create index',
|
||||
}),
|
||||
},
|
||||
],
|
||||
title: i18n.translate('xpack.searchIndices.elasticsearchIndices.startAppTitle', {
|
||||
defaultMessage: 'Elasticsearch Indices',
|
||||
}),
|
||||
async mount({ element, history }) {
|
||||
const { renderApp } = await import('./application');
|
||||
const { SearchIndicesRouter } = await import('./components/indices/indices_router');
|
||||
const { SearchIndicesRouter } = await import('./components/indices_router');
|
||||
const [coreStart, depsStart] = await core.getStartServices();
|
||||
const startDeps: SearchIndicesServicesContextDeps = {
|
||||
...depsStart,
|
||||
|
@ -66,6 +84,8 @@ export class SearchIndicesPlugin
|
|||
},
|
||||
});
|
||||
|
||||
registerLocators(plugins.share);
|
||||
|
||||
return {
|
||||
enabled: true,
|
||||
startAppId: START_APP_ID,
|
||||
|
|
|
@ -13,6 +13,7 @@ export enum SearchIndexDetailsTabs {
|
|||
MAPPINGS = 'mappings',
|
||||
SETTINGS = 'settings',
|
||||
}
|
||||
export const CREATE_INDEX_PATH = `${ROOT_PATH}create`;
|
||||
|
||||
export const SearchIndexDetailsTabValues: string[] = Object.values(SearchIndexDetailsTabs);
|
||||
export const START_APP_BASE = '/app/elasticsearch/start';
|
||||
|
|
|
@ -5,19 +5,25 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { CloudStart } from '@kbn/cloud-plugin/public';
|
||||
import type { ConsolePluginStart } from '@kbn/console-plugin/public';
|
||||
import type { CloudSetup, CloudStart } from '@kbn/cloud-plugin/public';
|
||||
import type { ConsolePluginSetup, ConsolePluginStart } from '@kbn/console-plugin/public';
|
||||
import type { AppMountParameters, CoreStart } from '@kbn/core/public';
|
||||
import type { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public';
|
||||
import type { SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import type { UsageCollectionStart } from '@kbn/usage-collection-plugin/public';
|
||||
import type { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import type {
|
||||
UsageCollectionSetup,
|
||||
UsageCollectionStart,
|
||||
} from '@kbn/usage-collection-plugin/public';
|
||||
import type {
|
||||
MappingProperty,
|
||||
MappingPropertyBase,
|
||||
} from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import type { IndexManagementPluginStart } from '@kbn/index-management-shared-types';
|
||||
import type {
|
||||
IndexManagementPluginSetup,
|
||||
IndexManagementPluginStart,
|
||||
} from '@kbn/index-management-shared-types';
|
||||
import type { AppDeepLinkId } from '@kbn/core-chrome-browser';
|
||||
import { ServerlessPluginStart } from '@kbn/serverless/public';
|
||||
import type { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/public';
|
||||
import type { AvailableLanguages } from './code_examples';
|
||||
|
||||
export interface SearchIndicesPluginSetup {
|
||||
enabled: boolean;
|
||||
|
@ -31,14 +37,20 @@ export interface SearchIndicesPluginStart {
|
|||
startRoute: string;
|
||||
}
|
||||
|
||||
export interface AppPluginStartDependencies {
|
||||
navigation: NavigationPublicPluginStart;
|
||||
export interface AppPluginSetupDependencies {
|
||||
console?: ConsolePluginSetup;
|
||||
cloud?: CloudSetup;
|
||||
indexManagement: IndexManagementPluginSetup;
|
||||
share: SharePluginSetup;
|
||||
serverless?: ServerlessPluginSetup;
|
||||
usageCollection?: UsageCollectionSetup;
|
||||
}
|
||||
|
||||
export interface SearchIndicesAppPluginStartDependencies {
|
||||
console?: ConsolePluginStart;
|
||||
cloud?: CloudStart;
|
||||
share: SharePluginStart;
|
||||
serverless?: ServerlessPluginStart;
|
||||
usageCollection?: UsageCollectionStart;
|
||||
indexManagement: IndexManagementPluginStart;
|
||||
}
|
||||
|
@ -50,8 +62,6 @@ export interface SearchIndicesServicesContextDeps {
|
|||
export type SearchIndicesServicesContext = CoreStart &
|
||||
SearchIndicesAppPluginStartDependencies & {
|
||||
history: AppMountParameters['history'];
|
||||
indexManagement: IndexManagementPluginStart;
|
||||
serverless: ServerlessPluginStart;
|
||||
};
|
||||
|
||||
export interface AppUsageTracker {
|
||||
|
@ -123,3 +133,14 @@ export interface IngestDataCodeExamples {
|
|||
python: IngestDataCodeDefinition;
|
||||
javascript: IngestDataCodeDefinition;
|
||||
}
|
||||
|
||||
export interface CreateIndexFormState {
|
||||
indexName: string;
|
||||
defaultIndexName: string;
|
||||
codingLanguage: AvailableLanguages;
|
||||
}
|
||||
|
||||
export enum CreateIndexViewMode {
|
||||
UI = 'ui',
|
||||
Code = 'code',
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { generateRandomIndexName, isValidIndexName } from './indices';
|
||||
import { generateRandomIndexName, isValidIndexName, getFirstNewIndexName } from './indices';
|
||||
|
||||
describe('indices utils', function () {
|
||||
describe('generateRandomIndexName', function () {
|
||||
|
@ -46,4 +46,31 @@ describe('indices utils', function () {
|
|||
expect(isValidIndexName(indexName)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFirstNewIndexName', function () {
|
||||
it('returns undefined when lists are the same', () => {
|
||||
expect(getFirstNewIndexName([], [])).toEqual(undefined);
|
||||
expect(getFirstNewIndexName(['index'], ['index'])).toEqual(undefined);
|
||||
expect(getFirstNewIndexName(['index', 'test'], ['index', 'test'])).toEqual(undefined);
|
||||
});
|
||||
|
||||
it('returns new item when it exists', () => {
|
||||
expect(getFirstNewIndexName([], ['index'])).toEqual('index');
|
||||
expect(getFirstNewIndexName(['index'], ['index', 'test'])).toEqual('test');
|
||||
expect(getFirstNewIndexName(['index', 'test'], ['index', 'test', 'unit-test'])).toEqual(
|
||||
'unit-test'
|
||||
);
|
||||
expect(getFirstNewIndexName(['index', 'test'], ['unit-test', 'index', 'test'])).toEqual(
|
||||
'unit-test'
|
||||
);
|
||||
});
|
||||
it('returns first new item when it multiple new indices exists', () => {
|
||||
expect(getFirstNewIndexName([], ['index', 'test'])).toEqual('index');
|
||||
expect(getFirstNewIndexName(['index'], ['test', 'index', 'unit-test'])).toEqual('test');
|
||||
});
|
||||
it('can handle old indices being removed', () => {
|
||||
expect(getFirstNewIndexName(['index'], ['test'])).toEqual('test');
|
||||
expect(getFirstNewIndexName(['test', 'index', 'unit-test'], ['index', 'new'])).toEqual('new');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -35,3 +35,12 @@ export function generateRandomIndexName(
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function getFirstNewIndexName(startingIndexNames: string[], currentIndexNames: string[]) {
|
||||
for (const index of currentIndexNames) {
|
||||
if (startingIndexNames.indexOf(index) === -1) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
],
|
||||
"kbn_references": [
|
||||
"@kbn/core",
|
||||
"@kbn/navigation-plugin",
|
||||
"@kbn/config-schema",
|
||||
"@kbn/core-elasticsearch-server",
|
||||
"@kbn/logging",
|
||||
|
@ -39,7 +38,8 @@
|
|||
"@kbn/search-shared-ui",
|
||||
"@kbn/deeplinks-search",
|
||||
"@kbn/core-chrome-browser",
|
||||
"@kbn/serverless"
|
||||
"@kbn/serverless",
|
||||
"@kbn/utility-types"
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -16,7 +16,9 @@ export const CreateIndexButton: React.FC = () => {
|
|||
services: { application, share },
|
||||
} = useKibana();
|
||||
const createIndexLocator = useMemo(
|
||||
() => share.url.locators.get('CREATE_INDEX_LOCATOR_ID'),
|
||||
() =>
|
||||
share.url.locators.get('CREATE_INDEX_LOCATOR_ID') ??
|
||||
share.url.locators.get('SEARCH_CREATE_INDEX'),
|
||||
[share.url.locators]
|
||||
);
|
||||
const handleNavigateToIndex = useCallback(async () => {
|
||||
|
|
|
@ -21,45 +21,9 @@ export const navigationTree = (): NavigationTreeDefinition => ({
|
|||
breadcrumbStatus: 'hidden',
|
||||
children: [
|
||||
{
|
||||
id: 'home',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.home', {
|
||||
defaultMessage: 'Home',
|
||||
}),
|
||||
link: 'elasticsearchStart',
|
||||
spaceBefore: 'm',
|
||||
},
|
||||
{
|
||||
id: 'dev_tools',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.devTools', {
|
||||
defaultMessage: 'Dev Tools',
|
||||
}),
|
||||
link: 'dev_tools:console',
|
||||
getIsActive: ({ pathNameSerialized, prepend }) => {
|
||||
return pathNameSerialized.startsWith(prepend('/app/dev_tools'));
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'kibana',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.kibana', {
|
||||
defaultMessage: 'Kibana',
|
||||
}),
|
||||
spaceBefore: 'm',
|
||||
children: [
|
||||
{
|
||||
link: 'discover',
|
||||
},
|
||||
{
|
||||
link: 'dashboards',
|
||||
getIsActive: ({ pathNameSerialized, prepend }) => {
|
||||
return pathNameSerialized.startsWith(prepend('/app/dashboards'));
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'content',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.content', {
|
||||
defaultMessage: 'Content',
|
||||
id: 'data',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.data', {
|
||||
defaultMessage: 'Data',
|
||||
}),
|
||||
spaceBefore: 'm',
|
||||
children: [
|
||||
|
@ -75,9 +39,8 @@ export const navigationTree = (): NavigationTreeDefinition => ({
|
|||
pathNameSerialized.startsWith(
|
||||
prepend('/app/management/data/index_management/')
|
||||
) ||
|
||||
pathNameSerialized.startsWith(
|
||||
prepend('/app/elasticsearch/indices/index_details/')
|
||||
)
|
||||
pathNameSerialized.startsWith(prepend('/app/elasticsearch/indices')) ||
|
||||
pathNameSerialized.startsWith(prepend('/app/elasticsearch/start'))
|
||||
);
|
||||
},
|
||||
},
|
||||
|
@ -94,6 +57,16 @@ export const navigationTree = (): NavigationTreeDefinition => ({
|
|||
}),
|
||||
spaceBefore: 'm',
|
||||
children: [
|
||||
{
|
||||
id: 'dev_tools',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.devTools', {
|
||||
defaultMessage: 'Dev Tools',
|
||||
}),
|
||||
link: 'dev_tools',
|
||||
getIsActive: ({ pathNameSerialized, prepend }) => {
|
||||
return pathNameSerialized.startsWith(prepend('/app/dev_tools'));
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'searchPlayground',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.build.searchPlayground', {
|
||||
|
@ -148,18 +121,19 @@ export const navigationTree = (): NavigationTreeDefinition => ({
|
|||
spaceBefore: 'm',
|
||||
children: [{ link: 'maps' }],
|
||||
},
|
||||
{
|
||||
id: 'gettingStarted',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.gettingStarted', {
|
||||
defaultMessage: 'Getting Started',
|
||||
}),
|
||||
link: 'serverlessElasticsearch',
|
||||
spaceBefore: 'm',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
footer: [
|
||||
{
|
||||
id: 'gettingStarted',
|
||||
type: 'navItem',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.gettingStarted', {
|
||||
defaultMessage: 'Getting Started',
|
||||
}),
|
||||
link: 'serverlessElasticsearch',
|
||||
icon: 'launch',
|
||||
},
|
||||
{
|
||||
type: 'navGroup',
|
||||
id: 'project_settings_project_nav',
|
||||
|
@ -169,12 +143,22 @@ export const navigationTree = (): NavigationTreeDefinition => ({
|
|||
icon: 'gear',
|
||||
breadcrumbStatus: 'hidden',
|
||||
children: [
|
||||
{
|
||||
link: 'ml:modelManagement',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.trainedModels', {
|
||||
defaultMessage: 'Trained models',
|
||||
}),
|
||||
},
|
||||
{
|
||||
link: 'management',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.mngt', {
|
||||
defaultMessage: 'Management',
|
||||
}),
|
||||
},
|
||||
{
|
||||
id: 'cloudLinkUserAndRoles',
|
||||
cloudLink: 'userAndRoles',
|
||||
},
|
||||
{
|
||||
id: 'cloudLinkDeployment',
|
||||
cloudLink: 'deployment',
|
||||
|
@ -182,10 +166,6 @@ export const navigationTree = (): NavigationTreeDefinition => ({
|
|||
defaultMessage: 'Performance',
|
||||
}),
|
||||
},
|
||||
{
|
||||
id: 'cloudLinkUserAndRoles',
|
||||
cloudLink: 'userAndRoles',
|
||||
},
|
||||
{
|
||||
id: 'cloudLinkBilling',
|
||||
cloudLink: 'billingAndSub',
|
||||
|
|
|
@ -36109,32 +36109,31 @@
|
|||
"xpack.searchIndices.server.createIndex.errorMessage": "Échec de la création de l'index en raison d'une exception. {errorMessage}",
|
||||
"xpack.searchIndices.server.deleteDocument.errorMessage": "Impossible de supprimer le document",
|
||||
"xpack.searchIndices.settingsTabLabel": "Paramètres",
|
||||
"xpack.searchIndices.startPage.codeView.apiKeyDescription": "Assurez-vous de le conserver dans un endroit sûr. Vous ne pourrez pas le récupérer plus tard.",
|
||||
"xpack.searchIndices.startPage.codeView.apiKeyTitle": "Copier votre clé d'API",
|
||||
"xpack.searchIndices.startPage.codeView.explicitGenerate.apiKeyDescription": "Créez une clé d'API pour vous connecter à Elasticsearch.",
|
||||
"xpack.searchIndices.startPage.codeView.explicitGenerate.apiKeyTitle": "Créer une clé d'API",
|
||||
"xpack.searchIndices.startPage.createIndex.action.text": "Créer mon index",
|
||||
"xpack.searchIndices.startPage.createIndex.apiKeyCreation.description": "Nous allons créer une clé d'API pour cet index",
|
||||
"xpack.searchIndices.startPage.createIndex.description": "Un index stocke vos données et définit le schéma, ou les mappings de champs, pour vos recherches",
|
||||
"xpack.searchIndices.startPage.createIndex.fileUpload.link": "Charger un fichier",
|
||||
"xpack.searchIndices.startPage.createIndex.fileUpload.text": "Vous disposez déjà de données ? {link}",
|
||||
"xpack.searchIndices.startPage.createIndex.name.helpText": "Les noms d'index doivent être en minuscules et ne peuvent contenir que des tirets et des chiffres",
|
||||
"xpack.searchIndices.startPage.createIndex.name.label": "Nommer votre index",
|
||||
"xpack.searchIndices.startPage.createIndex.name.placeholder": "Définir un nom pour votre index",
|
||||
"xpack.searchIndices.startPage.createIndex.permissionTooltip": "Vous ne disposez pas d'autorisation pour créer un index.",
|
||||
"xpack.searchIndices.shared.codeView.apiKeyDescription": "Assurez-vous de le conserver dans un endroit sûr. Vous ne pourrez pas le récupérer plus tard.",
|
||||
"xpack.searchIndices.shared.codeView.apiKeyTitle": "Copier votre clé d'API",
|
||||
"xpack.searchIndices.shared.codeView.explicitGenerate.apiKeyDescription": "Créez une clé d'API pour vous connecter à Elasticsearch.",
|
||||
"xpack.searchIndices.shared.codeView.explicitGenerate.apiKeyTitle": "Créer une clé d'API",
|
||||
"xpack.searchIndices.shared.createIndex.action.text": "Créer mon index",
|
||||
"xpack.searchIndices.shared.createIndex.apiKeyCreation.description": "Nous allons créer une clé d'API pour cet index",
|
||||
"xpack.searchIndices.shared.createIndex.description": "Un index stocke vos données et définit le schéma, ou les mappings de champs, pour vos recherches",
|
||||
"xpack.searchIndices.shared.createIndex.fileUpload.link": "Charger un fichier",
|
||||
"xpack.searchIndices.shared.createIndex.fileUpload.text": "Vous disposez déjà de données ? {link}",
|
||||
"xpack.searchIndices.shared.createIndex.name.helpText": "Les noms d'index doivent être en minuscules et ne peuvent contenir que des tirets et des chiffres",
|
||||
"xpack.searchIndices.shared.createIndex.name.label": "Nommer votre index",
|
||||
"xpack.searchIndices.shared.createIndex.name.placeholder": "Définir un nom pour votre index",
|
||||
"xpack.searchIndices.shared.createIndex.observabilityCallout.logs.button": "Collectez et analysez les logs",
|
||||
"xpack.searchIndices.shared.createIndex.observabilityCallout.logs.subTitle": "Explorer Logstash et Beats",
|
||||
"xpack.searchIndices.shared.createIndex.observabilityCallout.o11yTrial.button": "Démarrer un essai d'Observability",
|
||||
"xpack.searchIndices.shared.createIndex.observabilityCallout.o11yTrial.subTitle": "Puissant monitoring des performances",
|
||||
"xpack.searchIndices.shared.createIndex.observabilityCallout.title": "Vous cherchez à stocker vos logs ou vos données d'indicateurs ?",
|
||||
"xpack.searchIndices.shared.createIndex.pageTitle": "Elasticsearch",
|
||||
"xpack.searchIndices.shared.createIndex.permissionTooltip": "Vous ne disposez pas d'autorisation pour créer un index.",
|
||||
"xpack.searchIndices.shared.createIndex.viewSelect.code": "Code",
|
||||
"xpack.searchIndices.shared.createIndex.viewSelect.legend": "Créer une sélection de vue d'index",
|
||||
"xpack.searchIndices.shared.createIndex.viewSelect.ui": "Interface utilisateur",
|
||||
"xpack.searchIndices.shared.statusFetchError.title": "Erreur lors du chargement des index",
|
||||
"xpack.searchIndices.shared.statusFetchError.unknownError": "Erreur inconnue lors de la récupération des index.",
|
||||
"xpack.searchIndices.startPage.createIndex.title": "Créer votre premier index",
|
||||
"xpack.searchIndices.startPage.createIndex.viewSelec.legend": "Créer une sélection de vue d'index",
|
||||
"xpack.searchIndices.startPage.createIndex.viewSelect.code": "Code",
|
||||
"xpack.searchIndices.startPage.createIndex.viewSelect.ui": "Interface utilisateur",
|
||||
"xpack.searchIndices.startPage.observabilityCallout.logs.button": "Collectez et analysez les logs",
|
||||
"xpack.searchIndices.startPage.observabilityCallout.logs.subTitle": "Explorer Logstash et Beats",
|
||||
"xpack.searchIndices.startPage.observabilityCallout.o11yTrial.button": "Démarrer un essai d'Observability",
|
||||
"xpack.searchIndices.startPage.observabilityCallout.o11yTrial.subTitle": "Puissant monitoring des performances",
|
||||
"xpack.searchIndices.startPage.observabilityCallout.title": "Vous cherchez à stocker vos logs ou vos données d'indicateurs ?",
|
||||
"xpack.searchIndices.startPage.pageDescription": "Vectorisez, recherchez et visualisez vos données",
|
||||
"xpack.searchIndices.startPage.pageTitle": "Elasticsearch",
|
||||
"xpack.searchIndices.startPage.statusFetchError.title": "Erreur lors du chargement des index",
|
||||
"xpack.searchIndices.startPage.statusFetchError.unknownError": "Erreur inconnue lors de la récupération des index.",
|
||||
"xpack.searchInferenceEndpoints.actions.copyID": "Copier l'identifiant du point de terminaison d'inférence {inferenceId}",
|
||||
"xpack.searchInferenceEndpoints.actions.copyIDSuccess": "Identifiant du point de terminaison d'inférence {inferenceId} copié",
|
||||
"xpack.searchInferenceEndpoints.actions.deleteEndpoint": "Supprimer le point de terminaison d'inférence {selectedEndpointName}",
|
||||
|
@ -43293,12 +43292,9 @@
|
|||
"xpack.serverlessSearch.learnMore": "En savoir plus",
|
||||
"xpack.serverlessSearch.nav.build": "Développer",
|
||||
"xpack.serverlessSearch.nav.build.searchPlayground": "Playground",
|
||||
"xpack.serverlessSearch.nav.content": "Contenu",
|
||||
"xpack.serverlessSearch.nav.content.indices": "Gestion des index",
|
||||
"xpack.serverlessSearch.nav.devTools": "Outils de développement",
|
||||
"xpack.serverlessSearch.nav.gettingStarted": "Commencer",
|
||||
"xpack.serverlessSearch.nav.home": "Accueil",
|
||||
"xpack.serverlessSearch.nav.kibana": "Kibana",
|
||||
"xpack.serverlessSearch.nav.mngt": "Gestion",
|
||||
"xpack.serverlessSearch.nav.performance": "Performances",
|
||||
"xpack.serverlessSearch.nav.projectSettings": "Paramètres de projet",
|
||||
|
|
|
@ -36077,32 +36077,31 @@
|
|||
"xpack.searchIndices.server.createIndex.errorMessage": "例外が発生したため、インデックスを作成できませんでした。{errorMessage}",
|
||||
"xpack.searchIndices.server.deleteDocument.errorMessage": "ドキュメントを削除できませんでした",
|
||||
"xpack.searchIndices.settingsTabLabel": "設定",
|
||||
"xpack.searchIndices.startPage.codeView.apiKeyDescription": "必ず安全に保管してください。後から取得することはできません。",
|
||||
"xpack.searchIndices.startPage.codeView.apiKeyTitle": "APIキーをコピー",
|
||||
"xpack.searchIndices.startPage.codeView.explicitGenerate.apiKeyDescription": "Elasticsearchに接続するためのAPIキーを作成します。",
|
||||
"xpack.searchIndices.startPage.codeView.explicitGenerate.apiKeyTitle": "APIキーを作成する",
|
||||
"xpack.searchIndices.startPage.createIndex.action.text": "インデックスを作成",
|
||||
"xpack.searchIndices.startPage.createIndex.apiKeyCreation.description": "このインデックスのAPIキーを作成します",
|
||||
"xpack.searchIndices.startPage.createIndex.description": "インデックスはデータを格納し、検索のためのスキーマ、つまりフィールドマッピングを定義します。",
|
||||
"xpack.searchIndices.startPage.createIndex.fileUpload.link": "ファイルをアップロード",
|
||||
"xpack.searchIndices.startPage.createIndex.fileUpload.text": "すでに一部のデータがありますか?{link}",
|
||||
"xpack.searchIndices.startPage.createIndex.name.helpText": "インデックス名は小文字で、ハイフンと数字のみを使用する必要があります。",
|
||||
"xpack.searchIndices.startPage.createIndex.name.label": "インデックスの名前を指定",
|
||||
"xpack.searchIndices.startPage.createIndex.name.placeholder": "インデックスの名前を入力",
|
||||
"xpack.searchIndices.startPage.createIndex.permissionTooltip": "APIキーを作成する権限がありません。",
|
||||
"xpack.searchIndices.shared.codeView.apiKeyDescription": "必ず安全に保管してください。後から取得することはできません。",
|
||||
"xpack.searchIndices.shared.codeView.apiKeyTitle": "APIキーをコピー",
|
||||
"xpack.searchIndices.shared.codeView.explicitGenerate.apiKeyDescription": "Elasticsearchに接続するためのAPIキーを作成します。",
|
||||
"xpack.searchIndices.shared.codeView.explicitGenerate.apiKeyTitle": "APIキーを作成する",
|
||||
"xpack.searchIndices.shared.createIndex.action.text": "インデックスを作成",
|
||||
"xpack.searchIndices.shared.createIndex.apiKeyCreation.description": "このインデックスのAPIキーを作成します",
|
||||
"xpack.searchIndices.shared.createIndex.description": "インデックスはデータを格納し、検索のためのスキーマ、つまりフィールドマッピングを定義します。",
|
||||
"xpack.searchIndices.shared.createIndex.fileUpload.link": "ファイルをアップロード",
|
||||
"xpack.searchIndices.shared.createIndex.fileUpload.text": "すでに一部のデータがありますか?{link}",
|
||||
"xpack.searchIndices.shared.createIndex.name.helpText": "インデックス名は小文字で、ハイフンと数字のみを使用する必要があります。",
|
||||
"xpack.searchIndices.shared.createIndex.name.label": "インデックスの名前を指定",
|
||||
"xpack.searchIndices.shared.createIndex.name.placeholder": "インデックスの名前を入力",
|
||||
"xpack.searchIndices.shared.createIndex.observabilityCallout.logs.button": "ログを収集して分析",
|
||||
"xpack.searchIndices.shared.createIndex.observabilityCallout.logs.subTitle": "LogstashとBeatsを探索",
|
||||
"xpack.searchIndices.shared.createIndex.observabilityCallout.o11yTrial.button": "オブザーバビリティの試用を開始",
|
||||
"xpack.searchIndices.shared.createIndex.observabilityCallout.o11yTrial.subTitle": "強力なパフォーマンス監視",
|
||||
"xpack.searchIndices.shared.createIndex.observabilityCallout.title": "ログとメトリックデータを格納する方法をお探しですか?",
|
||||
"xpack.searchIndices.shared.createIndex.pageTitle": "Elasticsearch",
|
||||
"xpack.searchIndices.shared.createIndex.permissionTooltip": "APIキーを作成する権限がありません。",
|
||||
"xpack.searchIndices.shared.createIndex.viewSelect.code": "コード",
|
||||
"xpack.searchIndices.shared.createIndex.viewSelect.legend": "インデックスビュー選択を作成",
|
||||
"xpack.searchIndices.shared.createIndex.viewSelect.ui": "UI",
|
||||
"xpack.searchIndices.shared.statusFetchError.title": "インデックスの読み込み中にエラーが発生",
|
||||
"xpack.searchIndices.shared.statusFetchError.unknownError": "インデックスの取得中の不明なエラー",
|
||||
"xpack.searchIndices.startPage.createIndex.title": "最初のインデックスを作成",
|
||||
"xpack.searchIndices.startPage.createIndex.viewSelec.legend": "インデックスビュー選択を作成",
|
||||
"xpack.searchIndices.startPage.createIndex.viewSelect.code": "コード",
|
||||
"xpack.searchIndices.startPage.createIndex.viewSelect.ui": "UI",
|
||||
"xpack.searchIndices.startPage.observabilityCallout.logs.button": "ログを収集して分析",
|
||||
"xpack.searchIndices.startPage.observabilityCallout.logs.subTitle": "LogstashとBeatsを探索",
|
||||
"xpack.searchIndices.startPage.observabilityCallout.o11yTrial.button": "オブザーバビリティの試用を開始",
|
||||
"xpack.searchIndices.startPage.observabilityCallout.o11yTrial.subTitle": "強力なパフォーマンス監視",
|
||||
"xpack.searchIndices.startPage.observabilityCallout.title": "ログとメトリックデータを格納する方法をお探しですか?",
|
||||
"xpack.searchIndices.startPage.pageDescription": "データをベクトル化、検索、可視化",
|
||||
"xpack.searchIndices.startPage.pageTitle": "Elasticsearch",
|
||||
"xpack.searchIndices.startPage.statusFetchError.title": "インデックスの読み込み中にエラーが発生",
|
||||
"xpack.searchIndices.startPage.statusFetchError.unknownError": "インデックスの取得中の不明なエラー",
|
||||
"xpack.searchInferenceEndpoints.actions.copyID": "推論エンドポイント ID {inferenceId}をコピー",
|
||||
"xpack.searchInferenceEndpoints.actions.copyIDSuccess": "推論エンドポイント ID {inferenceId}がコピーされました",
|
||||
"xpack.searchInferenceEndpoints.actions.deleteEndpoint": "推論エンドポイント{selectedEndpointName}を削除",
|
||||
|
@ -43258,12 +43257,9 @@
|
|||
"xpack.serverlessSearch.learnMore": "詳細",
|
||||
"xpack.serverlessSearch.nav.build": "ビルド",
|
||||
"xpack.serverlessSearch.nav.build.searchPlayground": "Playground",
|
||||
"xpack.serverlessSearch.nav.content": "コンテンツ",
|
||||
"xpack.serverlessSearch.nav.content.indices": "インデックス管理",
|
||||
"xpack.serverlessSearch.nav.devTools": "開発ツール",
|
||||
"xpack.serverlessSearch.nav.gettingStarted": "はじめに",
|
||||
"xpack.serverlessSearch.nav.home": "ホーム",
|
||||
"xpack.serverlessSearch.nav.kibana": "Kibana",
|
||||
"xpack.serverlessSearch.nav.mngt": "管理",
|
||||
"xpack.serverlessSearch.nav.performance": "パフォーマンス",
|
||||
"xpack.serverlessSearch.nav.projectSettings": "プロジェクト設定",
|
||||
|
|
|
@ -36145,32 +36145,30 @@
|
|||
"xpack.searchIndices.server.createIndex.errorMessage": "由于出现异常,无法创建索引。{errorMessage}",
|
||||
"xpack.searchIndices.server.deleteDocument.errorMessage": "无法删除文档",
|
||||
"xpack.searchIndices.settingsTabLabel": "设置",
|
||||
"xpack.searchIndices.startPage.codeView.apiKeyDescription": "请确保将其存放在某个安全位置。稍后您将无法对其进行检索。",
|
||||
"xpack.searchIndices.startPage.codeView.apiKeyTitle": "复制您的 API 密钥",
|
||||
"xpack.searchIndices.startPage.codeView.explicitGenerate.apiKeyDescription": "创建 API 密钥以连接到 Elasticsearch。",
|
||||
"xpack.searchIndices.startPage.codeView.explicitGenerate.apiKeyTitle": "创建 API 密钥",
|
||||
"xpack.searchIndices.startPage.createIndex.action.text": "创建我的索引",
|
||||
"xpack.searchIndices.startPage.createIndex.apiKeyCreation.description": "我们将为此索引创建 API 密钥",
|
||||
"xpack.searchIndices.startPage.createIndex.description": "索引存储您的数据并为您的搜索定义架构或字段映射",
|
||||
"xpack.searchIndices.startPage.createIndex.fileUpload.link": "上传文件",
|
||||
"xpack.searchIndices.startPage.createIndex.fileUpload.text": "已具有某些数据?{link}",
|
||||
"xpack.searchIndices.startPage.createIndex.name.helpText": "索引名称必须为小写,并且只能包含连字符和数字",
|
||||
"xpack.searchIndices.startPage.createIndex.name.label": "命名您的索引",
|
||||
"xpack.searchIndices.startPage.createIndex.name.placeholder": "输入索引的名称",
|
||||
"xpack.searchIndices.startPage.createIndex.permissionTooltip": "您无权创建索引。",
|
||||
"xpack.searchIndices.shared.codeView.apiKeyDescription": "请确保将其存放在某个安全位置。稍后您将无法对其进行检索。",
|
||||
"xpack.searchIndices.shared.codeView.apiKeyTitle": "复制您的 API 密钥",
|
||||
"xpack.searchIndices.shared.codeView.explicitGenerate.apiKeyDescription": "创建 API 密钥以连接到 Elasticsearch。",
|
||||
"xpack.searchIndices.shared.codeView.explicitGenerate.apiKeyTitle": "创建 API 密钥",
|
||||
"xpack.searchIndices.shared.createIndex.action.text": "创建我的索引",
|
||||
"xpack.searchIndices.shared.createIndex.apiKeyCreation.description": "我们将为此索引创建 API 密钥",
|
||||
"xpack.searchIndices.shared.createIndex.description": "索引存储您的数据并为您的搜索定义架构或字段映射",
|
||||
"xpack.searchIndices.shared.createIndex.fileUpload.link": "上传文件",
|
||||
"xpack.searchIndices.shared.createIndex.fileUpload.text": "已具有某些数据?{link}",
|
||||
"xpack.searchIndices.shared.createIndex.name.helpText": "索引名称必须为小写,并且只能包含连字符和数字",
|
||||
"xpack.searchIndices.shared.createIndex.name.label": "命名您的索引",
|
||||
"xpack.searchIndices.shared.createIndex.name.placeholder": "输入索引的名称",
|
||||
"xpack.searchIndices.shared.createIndex.observabilityCallout.logs.button": "收集和分析日志",
|
||||
"xpack.searchIndices.shared.createIndex.observabilityCallout.logs.subTitle": "浏览 Logstash 和 Beats",
|
||||
"xpack.searchIndices.shared.createIndex.observabilityCallout.o11yTrial.button": "开始 Observability 试用",
|
||||
"xpack.searchIndices.shared.createIndex.observabilityCallout.o11yTrial.subTitle": "强大的性能监测",
|
||||
"xpack.searchIndices.shared.createIndex.observabilityCallout.title": "计划存储您的日志或指标数据?",
|
||||
"xpack.searchIndices.shared.createIndex.pageTitle": "Elasticsearch",
|
||||
"xpack.searchIndices.shared.createIndex.permissionTooltip": "您无权创建索引。",
|
||||
"xpack.searchIndices.shared.createIndex.viewSelect.code": "Code",
|
||||
"xpack.searchIndices.shared.createIndex.viewSelect.ui": "UI",
|
||||
"xpack.searchIndices.shared.statusFetchError.title": "加载索引时出错",
|
||||
"xpack.searchIndices.shared.statusFetchError.unknownError": "提取索引时出现未知错误。",
|
||||
"xpack.searchIndices.startPage.createIndex.title": "创建您的首个索引",
|
||||
"xpack.searchIndices.startPage.createIndex.viewSelec.legend": "创建索引视图选择",
|
||||
"xpack.searchIndices.startPage.createIndex.viewSelect.code": "Code",
|
||||
"xpack.searchIndices.startPage.createIndex.viewSelect.ui": "UI",
|
||||
"xpack.searchIndices.startPage.observabilityCallout.logs.button": "收集和分析日志",
|
||||
"xpack.searchIndices.startPage.observabilityCallout.logs.subTitle": "浏览 Logstash 和 Beats",
|
||||
"xpack.searchIndices.startPage.observabilityCallout.o11yTrial.button": "开始 Observability 试用",
|
||||
"xpack.searchIndices.startPage.observabilityCallout.o11yTrial.subTitle": "强大的性能监测",
|
||||
"xpack.searchIndices.startPage.observabilityCallout.title": "计划存储您的日志或指标数据?",
|
||||
"xpack.searchIndices.startPage.pageDescription": "向量化、搜索和可视化您的数据",
|
||||
"xpack.searchIndices.startPage.pageTitle": "Elasticsearch",
|
||||
"xpack.searchIndices.startPage.statusFetchError.title": "加载索引时出错",
|
||||
"xpack.searchIndices.startPage.statusFetchError.unknownError": "提取索引时出现未知错误。",
|
||||
"xpack.searchInferenceEndpoints.actions.copyID": "复制推理终端 ID {inferenceId}",
|
||||
"xpack.searchInferenceEndpoints.actions.copyIDSuccess": "已复制推理终端 ID {inferenceId}",
|
||||
"xpack.searchInferenceEndpoints.actions.deleteEndpoint": "删除推理终端 {selectedEndpointName}",
|
||||
|
@ -43329,12 +43327,9 @@
|
|||
"xpack.serverlessSearch.learnMore": "了解详情",
|
||||
"xpack.serverlessSearch.nav.build": "构建",
|
||||
"xpack.serverlessSearch.nav.build.searchPlayground": "Playground",
|
||||
"xpack.serverlessSearch.nav.content": "内容",
|
||||
"xpack.serverlessSearch.nav.content.indices": "索引管理",
|
||||
"xpack.serverlessSearch.nav.devTools": "开发工具",
|
||||
"xpack.serverlessSearch.nav.gettingStarted": "入门",
|
||||
"xpack.serverlessSearch.nav.home": "主页",
|
||||
"xpack.serverlessSearch.nav.kibana": "Kibana",
|
||||
"xpack.serverlessSearch.nav.mngt": "管理",
|
||||
"xpack.serverlessSearch.nav.performance": "性能",
|
||||
"xpack.serverlessSearch.nav.projectSettings": "项目设置",
|
||||
|
|
|
@ -162,13 +162,13 @@ export function IndexManagementPageProvider({ getService }: FtrProviderContext)
|
|||
},
|
||||
async clickCreateIndexButton() {
|
||||
await testSubjects.click('createIndexButton');
|
||||
await testSubjects.existOrFail('createIndexSaveButton');
|
||||
},
|
||||
async setCreateIndexName(value: string) {
|
||||
await testSubjects.existOrFail('createIndexNameFieldText');
|
||||
await testSubjects.setValue('createIndexNameFieldText', value);
|
||||
},
|
||||
async clickCreateIndexSaveButton() {
|
||||
await testSubjects.existOrFail('createIndexSaveButton');
|
||||
await testSubjects.click('createIndexSaveButton');
|
||||
// Wait for modal to close
|
||||
await testSubjects.missingOrFail('createIndexSaveButton', {
|
||||
|
|
|
@ -24,6 +24,7 @@ import { SvlSearchHomePageProvider } from './svl_search_homepage';
|
|||
import { SvlSearchIndexDetailPageProvider } from './svl_search_index_detail_page';
|
||||
import { SvlSearchElasticsearchStartPageProvider } from './svl_search_elasticsearch_start_page';
|
||||
import { SvlApiKeysProvider } from './svl_api_keys';
|
||||
import { SvlSearchCreateIndexPageProvider } from './svl_search_create_index_page';
|
||||
|
||||
export const pageObjects = {
|
||||
...xpackFunctionalPageObjects,
|
||||
|
@ -45,4 +46,5 @@ export const pageObjects = {
|
|||
svlSearchIndexDetailPage: SvlSearchIndexDetailPageProvider,
|
||||
svlSearchElasticsearchStartPage: SvlSearchElasticsearchStartPageProvider,
|
||||
svlApiKeys: SvlApiKeysProvider,
|
||||
svlSearchCreateIndexPage: SvlSearchCreateIndexPageProvider,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* 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 expect from '@kbn/expect';
|
||||
import { FtrProviderContext } from '../ftr_provider_context';
|
||||
|
||||
export function SvlSearchCreateIndexPageProvider({ getService }: FtrProviderContext) {
|
||||
const testSubjects = getService('testSubjects');
|
||||
const browser = getService('browser');
|
||||
const retry = getService('retry');
|
||||
|
||||
return {
|
||||
async expectToBeOnCreateIndexPage() {
|
||||
expect(await browser.getCurrentUrl()).contain('/app/elasticsearch/indices/create');
|
||||
await testSubjects.existOrFail('elasticsearchCreateIndexPage', { timeout: 2000 });
|
||||
},
|
||||
async expectToBeOnIndexDetailsPage() {
|
||||
await retry.tryForTime(60 * 1000, async () => {
|
||||
expect(await browser.getCurrentUrl()).contain('/app/elasticsearch/indices/index_details');
|
||||
});
|
||||
},
|
||||
async expectToBeOnIndexListPage() {
|
||||
await retry.tryForTime(60 * 1000, async () => {
|
||||
expect(await browser.getCurrentUrl()).contain(
|
||||
'/app/management/data/index_management/indices'
|
||||
);
|
||||
});
|
||||
},
|
||||
async expectToBeOnMLFileUploadPage() {
|
||||
await retry.tryForTime(60 * 1000, async () => {
|
||||
expect(await browser.getCurrentUrl()).contain('/app/ml/filedatavisualizer');
|
||||
});
|
||||
},
|
||||
async expectIndexNameToExist() {
|
||||
await testSubjects.existOrFail('indexNameField');
|
||||
},
|
||||
async setIndexNameValue(value: string) {
|
||||
await testSubjects.existOrFail('indexNameField');
|
||||
await testSubjects.setValue('indexNameField', value);
|
||||
},
|
||||
async expectCloseCreateIndexButtonExists() {
|
||||
await testSubjects.existOrFail('closeCreateIndex');
|
||||
},
|
||||
async clickCloseCreateIndexButton() {
|
||||
await testSubjects.existOrFail('closeCreateIndex');
|
||||
await testSubjects.click('closeCreateIndex');
|
||||
},
|
||||
async expectCreateIndexButtonToExist() {
|
||||
await testSubjects.existOrFail('createIndexBtn');
|
||||
},
|
||||
async expectCreateIndexButtonToBeEnabled() {
|
||||
await testSubjects.existOrFail('createIndexBtn');
|
||||
expect(await testSubjects.isEnabled('createIndexBtn')).equal(true);
|
||||
},
|
||||
async expectCreateIndexButtonToBeDisabled() {
|
||||
await testSubjects.existOrFail('createIndexBtn');
|
||||
expect(await testSubjects.isEnabled('createIndexBtn')).equal(false);
|
||||
},
|
||||
async clickCreateIndexButton() {
|
||||
await testSubjects.existOrFail('createIndexBtn');
|
||||
expect(await testSubjects.isEnabled('createIndexBtn')).equal(true);
|
||||
await testSubjects.click('createIndexBtn');
|
||||
},
|
||||
async expectCreateIndexCodeView() {
|
||||
await testSubjects.existOrFail('createIndexCodeView');
|
||||
},
|
||||
async expectCreateIndexUIView() {
|
||||
await testSubjects.existOrFail('createIndexUIView');
|
||||
},
|
||||
async clickUIViewButton() {
|
||||
await testSubjects.existOrFail('createIndexUIViewBtn');
|
||||
await testSubjects.click('createIndexUIViewBtn');
|
||||
},
|
||||
async clickCodeViewButton() {
|
||||
await testSubjects.existOrFail('createIndexCodeViewBtn');
|
||||
await testSubjects.click('createIndexCodeViewBtn');
|
||||
},
|
||||
async clickFileUploadLink() {
|
||||
await testSubjects.existOrFail('uploadFileLink');
|
||||
await testSubjects.click('uploadFileLink');
|
||||
},
|
||||
async expectAPIKeyVisibleInCodeBlock(apiKey: string) {
|
||||
await testSubjects.existOrFail('createIndex-code-block');
|
||||
await retry.try(async () => {
|
||||
expect(await testSubjects.getVisibleText('createIndex-code-block')).to.contain(apiKey);
|
||||
});
|
||||
},
|
||||
|
||||
async expectAPIKeyPreGenerated() {
|
||||
await testSubjects.existOrFail('apiKeyHasBeenGenerated');
|
||||
},
|
||||
|
||||
async expectAPIKeyNotPreGenerated() {
|
||||
await testSubjects.existOrFail('apiKeyHasNotBeenGenerated');
|
||||
},
|
||||
|
||||
async expectAPIKeyFormNotAvailable() {
|
||||
await testSubjects.missingOrFail('apiKeyHasNotBeenGenerated');
|
||||
await testSubjects.missingOrFail('apiKeyHasBeenGenerated');
|
||||
},
|
||||
};
|
||||
}
|
|
@ -42,6 +42,20 @@ export function SvlSearchElasticsearchStartPageProvider({ getService }: FtrProvi
|
|||
await testSubjects.existOrFail('indexNameField');
|
||||
await testSubjects.setValue('indexNameField', value);
|
||||
},
|
||||
async expectCloseCreateIndexButtonExists() {
|
||||
await testSubjects.existOrFail('closeCreateIndex');
|
||||
},
|
||||
async clickCloseCreateIndexButton() {
|
||||
await testSubjects.existOrFail('closeCreateIndex');
|
||||
await testSubjects.click('closeCreateIndex');
|
||||
},
|
||||
async expectSkipButtonExists() {
|
||||
await testSubjects.existOrFail('createIndexSkipBtn');
|
||||
},
|
||||
async clickSkipButton() {
|
||||
await testSubjects.existOrFail('createIndexSkipBtn');
|
||||
await testSubjects.click('createIndexSkipBtn');
|
||||
},
|
||||
async expectCreateIndexButtonToExist() {
|
||||
await testSubjects.existOrFail('createIndexBtn');
|
||||
},
|
||||
|
|
|
@ -14,6 +14,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
const security = getService('security');
|
||||
const testIndexName = `index-ftr-test-${Math.random()}`;
|
||||
describe('Index Details ', function () {
|
||||
this.tags(['skipSvlSearch']);
|
||||
before(async () => {
|
||||
await security.testUser.setRoles(['index_management_user']);
|
||||
await pageObjects.svlCommonPage.loginAsAdmin();
|
||||
|
@ -34,7 +35,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
await pageObjects.indexManagement.expectIndexToExist(testIndexName);
|
||||
});
|
||||
describe('can view index details', function () {
|
||||
this.tags(['skipSvlSearch']);
|
||||
it('index with no documents', async () => {
|
||||
await pageObjects.indexManagement.indexDetailsPage.openIndexDetailsPage(0);
|
||||
await pageObjects.indexManagement.indexDetailsPage.expectIndexDetailsPageIsLoaded();
|
||||
|
|
|
@ -17,6 +17,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
const es = getService('es');
|
||||
|
||||
describe('Indices', function () {
|
||||
this.tags(['skipSvlSearch']);
|
||||
before(async () => {
|
||||
await security.testUser.setRoles(['index_management_user']);
|
||||
await pageObjects.svlCommonPage.loginAsAdmin();
|
||||
|
@ -53,7 +54,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
after(async () => {
|
||||
await esDeleteAllIndices(testIndexName);
|
||||
});
|
||||
this.tags('skipSvlSearch');
|
||||
it('navigates to overview', async () => {
|
||||
await pageObjects.indexManagement.changeManageIndexTab('showOverviewIndexMenuButton');
|
||||
await pageObjects.indexManagement.indexDetailsPage.expectIndexDetailsPageIsLoaded();
|
||||
|
|
|
@ -156,6 +156,19 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
await pageObjects.svlSearchElasticsearchStartPage.expectAnalyzeLogsLink();
|
||||
await pageObjects.svlSearchElasticsearchStartPage.expectO11yTrialLink();
|
||||
});
|
||||
|
||||
it('should have close button', async () => {
|
||||
await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnStartPage();
|
||||
await pageObjects.svlSearchElasticsearchStartPage.expectCloseCreateIndexButtonExists();
|
||||
await pageObjects.svlSearchElasticsearchStartPage.clickCloseCreateIndexButton();
|
||||
await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnIndexListPage();
|
||||
});
|
||||
it('should have skip button', async () => {
|
||||
await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnStartPage();
|
||||
await pageObjects.svlSearchElasticsearchStartPage.expectSkipButtonExists();
|
||||
await pageObjects.svlSearchElasticsearchStartPage.clickSkipButton();
|
||||
await pageObjects.svlSearchElasticsearchStartPage.expectToBeOnIndexListPage();
|
||||
});
|
||||
});
|
||||
describe('viewer', function () {
|
||||
before(async () => {
|
||||
|
|
|
@ -15,6 +15,7 @@ export default function ({ loadTestFile }: FtrProviderContext) {
|
|||
loadTestFile(require.resolve('./elasticsearch_start.ts'));
|
||||
loadTestFile(require.resolve('./search_index_detail.ts'));
|
||||
loadTestFile(require.resolve('./getting_started'));
|
||||
loadTestFile(require.resolve('./index_management'));
|
||||
loadTestFile(require.resolve('./connectors/connectors_overview'));
|
||||
loadTestFile(require.resolve('./default_dataview'));
|
||||
loadTestFile(require.resolve('./pipelines'));
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
||||
import { testHasEmbeddedConsole } from './embedded_console';
|
||||
|
@ -16,9 +17,15 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
'common',
|
||||
'header',
|
||||
'indexManagement',
|
||||
'svlSearchCreateIndexPage',
|
||||
]);
|
||||
const browser = getService('browser');
|
||||
const security = getService('security');
|
||||
const es = getService('es');
|
||||
const esDeleteAllIndices = getService('esDeleteAllIndices');
|
||||
|
||||
const testIndexName = `test-index-ftr-${Math.random()}`;
|
||||
const testAPIIndexName = `test-api-index-ftr-${Math.random()}`;
|
||||
describe('index management', function () {
|
||||
before(async () => {
|
||||
await security.testUser.setRoles(['index_management_user']);
|
||||
|
@ -29,9 +36,82 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
await pageObjects.indexManagement.changeTabs('indicesTab');
|
||||
await pageObjects.header.waitUntilLoadingHasFinished();
|
||||
});
|
||||
after(async () => {
|
||||
await esDeleteAllIndices([testIndexName, testAPIIndexName]);
|
||||
});
|
||||
|
||||
it('renders the indices tab', async () => {
|
||||
const url = await browser.getCurrentUrl();
|
||||
expect(url).to.contain(`/indices`);
|
||||
});
|
||||
|
||||
it('has embedded dev console', async () => {
|
||||
await testHasEmbeddedConsole(pageObjects);
|
||||
});
|
||||
|
||||
describe('create index', function () {
|
||||
beforeEach(async () => {
|
||||
await pageObjects.common.navigateToApp('indexManagement');
|
||||
// Navigate to the indices tab
|
||||
await pageObjects.indexManagement.changeTabs('indicesTab');
|
||||
await pageObjects.header.waitUntilLoadingHasFinished();
|
||||
});
|
||||
it('can create an index', async () => {
|
||||
await pageObjects.indexManagement.clickCreateIndexButton();
|
||||
await pageObjects.svlSearchCreateIndexPage.expectToBeOnCreateIndexPage();
|
||||
await pageObjects.svlSearchCreateIndexPage.expectCreateIndexUIView();
|
||||
await pageObjects.svlSearchCreateIndexPage.expectCreateIndexButtonToBeEnabled();
|
||||
await pageObjects.svlSearchCreateIndexPage.setIndexNameValue(testIndexName);
|
||||
await pageObjects.svlSearchCreateIndexPage.clickCreateIndexButton();
|
||||
await pageObjects.svlSearchCreateIndexPage.expectToBeOnIndexDetailsPage();
|
||||
await pageObjects.common.navigateToApp('indexManagement');
|
||||
await pageObjects.indexManagement.changeTabs('indicesTab');
|
||||
await pageObjects.indexManagement.expectIndexToExist(testIndexName);
|
||||
});
|
||||
it('should redirect to index details when index is created via API and on the code view', async () => {
|
||||
await pageObjects.indexManagement.clickCreateIndexButton();
|
||||
|
||||
await pageObjects.svlSearchCreateIndexPage.expectToBeOnCreateIndexPage();
|
||||
await pageObjects.svlSearchCreateIndexPage.expectCreateIndexUIView();
|
||||
await pageObjects.svlSearchCreateIndexPage.clickCodeViewButton();
|
||||
await pageObjects.svlSearchCreateIndexPage.expectCreateIndexCodeView();
|
||||
await es.indices.create({ index: testAPIIndexName });
|
||||
await pageObjects.svlSearchCreateIndexPage.expectToBeOnIndexDetailsPage();
|
||||
});
|
||||
it('should have file upload link', async () => {
|
||||
await pageObjects.indexManagement.clickCreateIndexButton();
|
||||
|
||||
await pageObjects.svlSearchCreateIndexPage.expectToBeOnCreateIndexPage();
|
||||
await pageObjects.svlSearchCreateIndexPage.clickFileUploadLink();
|
||||
await pageObjects.svlSearchCreateIndexPage.expectToBeOnMLFileUploadPage();
|
||||
});
|
||||
it('should support closing create index page', async () => {
|
||||
await pageObjects.indexManagement.clickCreateIndexButton();
|
||||
|
||||
await pageObjects.svlSearchCreateIndexPage.expectCloseCreateIndexButtonExists();
|
||||
await pageObjects.svlSearchCreateIndexPage.clickCloseCreateIndexButton();
|
||||
await pageObjects.svlSearchCreateIndexPage.expectToBeOnIndexListPage();
|
||||
});
|
||||
it('should have the embedded console', async () => {
|
||||
await pageObjects.indexManagement.clickCreateIndexButton();
|
||||
|
||||
await testHasEmbeddedConsole(pageObjects);
|
||||
});
|
||||
});
|
||||
|
||||
describe('manage index', function () {
|
||||
beforeEach(async () => {
|
||||
await pageObjects.common.navigateToApp('indexManagement');
|
||||
// Navigate to the indices tab
|
||||
await pageObjects.indexManagement.changeTabs('indicesTab');
|
||||
await pageObjects.header.waitUntilLoadingHasFinished();
|
||||
await pageObjects.indexManagement.manageIndex(testIndexName);
|
||||
await pageObjects.indexManagement.manageIndexContextMenuExists();
|
||||
});
|
||||
it('can delete index', async () => {
|
||||
await pageObjects.indexManagement.confirmDeleteModalIsVisible();
|
||||
await pageObjects.indexManagement.expectIndexIsDeleted(testIndexName);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -34,10 +34,11 @@ export default function ({ getPageObject, getService }: FtrProviderContext) {
|
|||
// check side nav links
|
||||
await solutionNavigation.sidenav.expectSectionExists('search_project_nav');
|
||||
await solutionNavigation.sidenav.expectLinkActive({
|
||||
deepLinkId: 'elasticsearchStart',
|
||||
deepLinkId: 'management:index_management',
|
||||
});
|
||||
await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Indices' });
|
||||
await solutionNavigation.breadcrumbs.expectBreadcrumbExists({
|
||||
deepLinkId: 'elasticsearchStart',
|
||||
text: 'Create your first index',
|
||||
});
|
||||
await testSubjects.existOrFail(`elasticsearchStartPage`);
|
||||
|
||||
|
@ -58,6 +59,7 @@ export default function ({ getPageObject, getService }: FtrProviderContext) {
|
|||
});
|
||||
await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Data' });
|
||||
await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Index Management' });
|
||||
await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Indices' });
|
||||
|
||||
// > Connectors
|
||||
await solutionNavigation.sidenav.clickLink({
|
||||
|
@ -196,9 +198,9 @@ export default function ({ getPageObject, getService }: FtrProviderContext) {
|
|||
// navigate back to serverless search overview
|
||||
await svlCommonNavigation.clickLogo();
|
||||
await svlCommonNavigation.sidenav.expectLinkActive({
|
||||
deepLinkId: 'elasticsearchStart',
|
||||
deepLinkId: 'management:index_management',
|
||||
});
|
||||
await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ text: `Home` });
|
||||
await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ text: `Indices` });
|
||||
await testSubjects.existOrFail(`elasticsearchStartPage`);
|
||||
|
||||
await expectNoPageReload();
|
||||
|
@ -256,7 +258,6 @@ export default function ({ getPageObject, getService }: FtrProviderContext) {
|
|||
it('renders expected side navigation items', async () => {
|
||||
await solutionNavigation.sidenav.openSection('project_settings_project_nav');
|
||||
// Verify all expected top-level links exist
|
||||
await solutionNavigation.sidenav.expectLinkExists({ text: 'Home' });
|
||||
await solutionNavigation.sidenav.expectLinkExists({ text: 'Data' });
|
||||
await solutionNavigation.sidenav.expectLinkExists({ text: 'Index Management' });
|
||||
await solutionNavigation.sidenav.expectLinkExists({ text: 'Connectors' });
|
||||
|
@ -281,7 +282,6 @@ export default function ({ getPageObject, getService }: FtrProviderContext) {
|
|||
await solutionNavigation.sidenav.openSection('project_settings_project_nav');
|
||||
await solutionNavigation.sidenav.expectOnlyDefinedLinks([
|
||||
'search_project_nav',
|
||||
'home',
|
||||
'data',
|
||||
'management:index_management',
|
||||
'serverlessConnectors',
|
||||
|
|
|
@ -69,7 +69,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectPlaygroundHeaderComponentsToExist();
|
||||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectPlaygroundHeaderComponentsToDisabled();
|
||||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectPlaygroundStartChatPageComponentsToExist();
|
||||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectPlaygroundStartChatPageIndexCalloutExists();
|
||||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectPlaygroundStartChatPageIndexButtonExists();
|
||||
});
|
||||
|
||||
describe('with gen ai connectors', () => {
|
||||
|
@ -106,7 +106,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
});
|
||||
|
||||
describe('without any indices', () => {
|
||||
it('hide no index callout when index added', async () => {
|
||||
it('hide no create index button when index added', async () => {
|
||||
await createIndex();
|
||||
await pageObjects.searchPlayground.PlaygroundStartChatPage.expectOpenFlyoutAndSelectIndex();
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue