From de9376504f5eefc07c665629555cda537d1a2a12 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher Date: Tue, 6 Aug 2019 11:34:25 +0100 Subject: [PATCH] [LogsUI] [InfraUI] Turn source configuration into a tab and standardize the main navigation (#42243) * Setup Logs routing for multiple pages * Adds nested routing for logs * Adds an index page to handle shared concerns * Adds the Stream page at /logs/stream * Introduce shared settings page * Introduces shared/settings page * Adds shared/settings page as a tab in the Logs routes * Removes previous source configuration flyout traces from Logs pages * Begin styling adjustments to settings page * Implements use of EUI Panels * Centers page content * Add discard button * Add discard button to allow resetting the form * Fix button alignment * Align Apply and Discard buttons to the right * Align Loading button to the right * Add EuiDescribedFormGroup for all form fields * Add EuiDescribedFormGroup for name panel * Add EuiDescribedFormGroup for indices panel * Add EuiDescribedFormGroup for fields panel * Remove all SourceConfigurationFlyout traces from the Infrastructure UI * Add a ViewSourceConfigurationButton * Adds a ViewSourceConfigurationButton component that will route to the /settings page * Replace all instances of "View Configuration" buttons that were opening the flyout with the new button * Enable settings tab amongst Infrastructure routes * Change navigation to mimic SIEM * Introduces an AppNavigation component * Amends styling / handling of RoutedTabs to match SIEM implementation * Adds new AppNavigation component to Infrastructure and Logs indexe pages * Functional test amendments (WIP) * Temporarily disable certain functional tests * Remove unused imports * Disable imports so build can pass * Amend I18N errors * I18N * Automatically fix issues with i18n (node scripts/i18n_check --fix result) * Functional tests * Amend tests so they pass locally. Pending CI test. * Amend RoutedTabs (without link focus style) * Tweak RoutedTabs and AppNavigation for better performance / visuals * Ensure outline isn't cut off * Ensure only the react-router instance is hit for performance * Ensure links still have href attributes for things like "Open in a new tab" even if history.push ultimately navigates * Fix i18n usages * node scripts/i18n_check --fix * Amend functional test config (post Master merge fix) * Remove unused function and fix unused import * Add a Prompt to notify users when form changes will be lost * Add aria-label to Button --- .../log_text_stream/column_headers.tsx | 23 +- .../scrollable_log_text_stream_view.tsx | 3 - .../components/metrics/invalid_node.tsx | 16 +- .../components/navigation/app_navigation.tsx | 33 ++ .../components/navigation/routed_tabs.tsx | 34 +- .../fields_configuration_panel.tsx | 295 ++++++++++++------ .../components/source_configuration/index.ts | 9 +- .../indices_configuration_panel.tsx | 128 +++++--- .../log_columns_configuration_panel.tsx | 3 +- .../name_configuration_panel.tsx | 49 ++- .../source_configuration_button.tsx | 31 -- .../source_configuration_flyout.tsx | 281 ----------------- .../source_configuration_flyout_state.tsx | 51 --- .../source_configuration_settings.tsx | 213 +++++++++++++ .../view_source_configuration_button.tsx | 40 +++ .../public/pages/infrastructure/index.tsx | 85 ++--- .../pages/infrastructure/snapshot/index.tsx | 17 +- .../pages/infrastructure/snapshot/toolbar.tsx | 4 - .../plugins/infra/public/pages/logs/index.tsx | 69 ++++ .../infra/public/pages/logs/page_header.tsx | 57 ---- .../public/pages/logs/page_providers.tsx | 33 -- .../public/pages/logs/{ => stream}/index.ts | 2 +- .../public/pages/logs/{ => stream}/page.tsx | 14 +- .../pages/logs/{ => stream}/page_content.tsx | 8 +- .../public/pages/logs/stream/page_header.tsx | 45 +++ .../logs/{ => stream}/page_logs_content.tsx | 37 +-- .../{ => stream}/page_no_indices_content.tsx | 19 +- .../pages/logs/stream/page_providers.tsx | 30 ++ .../pages/logs/{ => stream}/page_toolbar.tsx | 34 +- .../infra/public/pages/metrics/index.tsx | 4 - .../public/pages/metrics/page_providers.tsx | 9 +- .../public/pages/shared/settings/index.tsx | 18 ++ x-pack/legacy/plugins/infra/public/routes.tsx | 1 + .../translations/translations/ja-JP.json | 29 +- .../translations/translations/zh-CN.json | 29 +- .../apps/infra/logs_source_configuration.ts | 63 ++-- .../infra/metrics_source_configuration.ts | 29 +- .../page_objects/infra_home_page.ts | 7 + .../page_objects/infra_logs_page.ts | 5 - x-pack/test/functional/services/index.ts | 4 +- .../functional/services/infra_log_stream.ts | 10 +- ....ts => infra_source_configuration_form.ts} | 71 ++--- 42 files changed, 1013 insertions(+), 929 deletions(-) create mode 100644 x-pack/legacy/plugins/infra/public/components/navigation/app_navigation.tsx delete mode 100644 x-pack/legacy/plugins/infra/public/components/source_configuration/source_configuration_button.tsx delete mode 100644 x-pack/legacy/plugins/infra/public/components/source_configuration/source_configuration_flyout.tsx delete mode 100644 x-pack/legacy/plugins/infra/public/components/source_configuration/source_configuration_flyout_state.tsx create mode 100644 x-pack/legacy/plugins/infra/public/components/source_configuration/source_configuration_settings.tsx create mode 100644 x-pack/legacy/plugins/infra/public/components/source_configuration/view_source_configuration_button.tsx create mode 100644 x-pack/legacy/plugins/infra/public/pages/logs/index.tsx delete mode 100644 x-pack/legacy/plugins/infra/public/pages/logs/page_header.tsx delete mode 100644 x-pack/legacy/plugins/infra/public/pages/logs/page_providers.tsx rename x-pack/legacy/plugins/infra/public/pages/logs/{ => stream}/index.ts (86%) rename x-pack/legacy/plugins/infra/public/pages/logs/{ => stream}/page.tsx (65%) rename x-pack/legacy/plugins/infra/public/pages/logs/{ => stream}/page_content.tsx (77%) create mode 100644 x-pack/legacy/plugins/infra/public/pages/logs/stream/page_header.tsx rename x-pack/legacy/plugins/infra/public/pages/logs/{ => stream}/page_logs_content.tsx (77%) rename x-pack/legacy/plugins/infra/public/pages/logs/{ => stream}/page_no_indices_content.tsx (82%) create mode 100644 x-pack/legacy/plugins/infra/public/pages/logs/stream/page_providers.tsx rename x-pack/legacy/plugins/infra/public/pages/logs/{ => stream}/page_toolbar.tsx (78%) create mode 100644 x-pack/legacy/plugins/infra/public/pages/shared/settings/index.tsx rename x-pack/test/functional/services/{infra_source_configuration_flyout.ts => infra_source_configuration_form.ts} (66%) diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/column_headers.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/column_headers.tsx index 398ef42048d70..ba8e6d90ca7ad 100644 --- a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/column_headers.tsx +++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/column_headers.tsx @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiButtonIcon } from '@elastic/eui'; import { injectI18n } from '@kbn/i18n/react'; import React from 'react'; @@ -20,20 +19,13 @@ import { LogEntryColumnContent, LogEntryColumnWidth, LogEntryColumnWidths, - iconColumnId, } from './log_entry_column'; import { ASSUMED_SCROLLBAR_WIDTH } from './vertical_scroll_panel'; export const LogColumnHeaders = injectI18n<{ columnConfigurations: LogColumnConfiguration[]; columnWidths: LogEntryColumnWidths; - showColumnConfiguration: () => void; -}>(({ columnConfigurations, columnWidths, intl, showColumnConfiguration }) => { - const showColumnConfigurationLabel = intl.formatMessage({ - id: 'xpack.infra.logColumnHeaders.configureColumnsLabel', - defaultMessage: 'Configure source', - }); - +}>(({ columnConfigurations, columnWidths, intl }) => { return ( {columnConfigurations.map(columnConfiguration => { @@ -69,19 +61,6 @@ export const LogColumnHeaders = injectI18n<{ ); } })} - - - ); }); diff --git a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/scrollable_log_text_stream_view.tsx b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/scrollable_log_text_stream_view.tsx index c765531f90831..b9a4d4244a1ff 100644 --- a/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/scrollable_log_text_stream_view.tsx +++ b/x-pack/legacy/plugins/infra/public/components/logging/log_text_stream/scrollable_log_text_stream_view.tsx @@ -48,7 +48,6 @@ interface ScrollableLogTextStreamViewProps { loadNewerItems: () => void; setFlyoutItem: (id: string) => void; setFlyoutVisibility: (visible: boolean) => void; - showColumnConfiguration: () => void; intl: InjectedIntl; highlightedItem: string | null; currentHighlightKey: UniqueTimeKey | null; @@ -109,7 +108,6 @@ class ScrollableLogTextStreamViewClass extends React.PureComponent< items, lastLoadedTime, scale, - showColumnConfiguration, wrap, } = this.props; const { targetId } = this.state; @@ -153,7 +151,6 @@ class ScrollableLogTextStreamViewClass extends React.PureComponent< {({ measureRef, bounds: { height = 0 }, content: { width = 0 } }) => ( diff --git a/x-pack/legacy/plugins/infra/public/components/metrics/invalid_node.tsx b/x-pack/legacy/plugins/infra/public/components/metrics/invalid_node.tsx index 60bd51f0ba6de..673bca91904c7 100644 --- a/x-pack/legacy/plugins/infra/public/components/metrics/invalid_node.tsx +++ b/x-pack/legacy/plugins/infra/public/components/metrics/invalid_node.tsx @@ -6,19 +6,20 @@ import { EuiButton, EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import React, { useContext } from 'react'; +import React from 'react'; import euiStyled from '../../../../../common/eui_styled_components'; -import { SourceConfigurationFlyoutState } from '../../components/source_configuration'; import { WithKibanaChrome } from '../../containers/with_kibana_chrome'; +import { + ViewSourceConfigurationButton, + ViewSourceConfigurationButtonHrefBase, +} from '../../components/source_configuration'; interface InvalidNodeErrorProps { nodeName: string; } export const InvalidNodeError: React.FunctionComponent = ({ nodeName }) => { - const { showIndicesConfiguration } = useContext(SourceConfigurationFlyoutState.Context); - return ( {({ basePath }) => ( @@ -57,12 +58,15 @@ export const InvalidNodeError: React.FunctionComponent = - + - + } diff --git a/x-pack/legacy/plugins/infra/public/components/navigation/app_navigation.tsx b/x-pack/legacy/plugins/infra/public/components/navigation/app_navigation.tsx new file mode 100644 index 0000000000000..b1eef34001750 --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/components/navigation/app_navigation.tsx @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import React from 'react'; +import euiStyled from '../../../../../common/eui_styled_components'; + +interface AppNavigationProps { + children: React.ReactNode; +} + +export const AppNavigation = ({ children }: AppNavigationProps) => ( + +); + +const Nav = euiStyled.nav` + background: ${props => props.theme.eui.euiColorEmptyShade}; + border-bottom: ${props => props.theme.eui.euiBorderThin}; + padding: ${props => + `${props.theme.eui.euiSize} ${props.theme.eui.euiSizeL} ${props.theme.eui.euiSize} ${props.theme.eui.euiSizeL}`} + + .euiTabs { + padding-left: 3px; + margin-left: -3px; + } +`; diff --git a/x-pack/legacy/plugins/infra/public/components/navigation/routed_tabs.tsx b/x-pack/legacy/plugins/infra/public/components/navigation/routed_tabs.tsx index 5c510fb2d3a6a..5fe36d8c5af0c 100644 --- a/x-pack/legacy/plugins/infra/public/components/navigation/routed_tabs.tsx +++ b/x-pack/legacy/plugins/infra/public/components/navigation/routed_tabs.tsx @@ -4,9 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiTab, EuiTabs } from '@elastic/eui'; +import { EuiTab, EuiTabs, EuiLink } from '@elastic/eui'; import React from 'react'; import { Route } from 'react-router-dom'; +import euiStyled from '../../../../../common/eui_styled_components'; interface TabConfiguration { title: string; @@ -17,27 +18,42 @@ interface RoutedTabsProps { tabs: TabConfiguration[]; } +const noop = () => {}; + export class RoutedTabs extends React.Component { public render() { - return {this.renderTabs()}; + return {this.renderTabs()}; } private renderTabs() { return this.props.tabs.map(tab => { return ( ( - (match ? undefined : history.push(tab.path))} - isSelected={match !== null} - > - {tab.title} - + + { + e.preventDefault(); + history.push(tab.path); + }} + > + + {tab.title} + + + )} /> ); }); } } + +const TabContainer = euiStyled.div` + .euiLink { + color: inherit !important; + } +`; diff --git a/x-pack/legacy/plugins/infra/public/components/source_configuration/fields_configuration_panel.tsx b/x-pack/legacy/plugins/infra/public/components/source_configuration/fields_configuration_panel.tsx index 5b79132ecf1f5..771285e8ccee4 100644 --- a/x-pack/legacy/plugins/infra/public/components/source_configuration/fields_configuration_panel.tsx +++ b/x-pack/legacy/plugins/infra/public/components/source_configuration/fields_configuration_panel.tsx @@ -4,7 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiCode, EuiFieldText, EuiForm, EuiFormRow, EuiSpacer, EuiTitle } from '@elastic/eui'; +import { + EuiDescribedFormGroup, + EuiCode, + EuiFieldText, + EuiForm, + EuiFormRow, + EuiSpacer, + EuiTitle, +} from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import React from 'react'; @@ -39,145 +47,230 @@ export const FieldsConfigurationPanel = ({ - @timestamp, - }} + id="xpack.infra.sourceConfiguration.timestampFieldLabel" + defaultMessage="Timestamp" /> } - isInvalid={timestampFieldProps.isInvalid} - label={ + description={ } > - - - _doc, - }} + helpText={ + @timestamp, + }} + /> + } + isInvalid={timestampFieldProps.isInvalid} + label={ + + } + > + - } - isInvalid={tiebreakerFieldProps.isInvalid} - label={ + + + } - > - - - container.id, - }} + id="xpack.infra.sourceConfiguration.tiebreakerFieldDescription" + defaultMessage="Field used to break ties between two entries with the same timestamp" /> } - isInvalid={containerFieldProps.isInvalid} - label={ + > + _doc, + }} + /> + } + isInvalid={tiebreakerFieldProps.isInvalid} + label={ + + } + > + + + + } + description={ + + } > - - - container.id, + }} + /> + } + isInvalid={containerFieldProps.isInvalid} + label={ + + } + > + + + + host.name, - }} + id="xpack.infra.sourceConfiguration.hostNameFieldLabel" + defaultMessage="Host name" /> } - isInvalid={hostFieldProps.isInvalid} - label={ + description={ } > - - - kubernetes.pod.uid, - }} + helpText={ + host.name, + }} + /> + } + isInvalid={hostFieldProps.isInvalid} + label={ + + } + > + - } - isInvalid={podFieldProps.isInvalid} - label={ + + + } + description={ + + } > - - + helpText={ + kubernetes.pod.uid, + }} + /> + } + isInvalid={podFieldProps.isInvalid} + label={ + + } + > + + + ); diff --git a/x-pack/legacy/plugins/infra/public/components/source_configuration/index.ts b/x-pack/legacy/plugins/infra/public/components/source_configuration/index.ts index d1640f3e34708..4879a53ca329d 100644 --- a/x-pack/legacy/plugins/infra/public/components/source_configuration/index.ts +++ b/x-pack/legacy/plugins/infra/public/components/source_configuration/index.ts @@ -4,9 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -export { SourceConfigurationButton } from './source_configuration_button'; -export { SourceConfigurationFlyout } from './source_configuration_flyout'; +export { SourceConfigurationSettings } from './source_configuration_settings'; export { - SourceConfigurationFlyoutState, - useSourceConfigurationFlyoutState, -} from './source_configuration_flyout_state'; + ViewSourceConfigurationButton, + ViewSourceConfigurationButtonHrefBase, +} from './view_source_configuration_button'; diff --git a/x-pack/legacy/plugins/infra/public/components/source_configuration/indices_configuration_panel.tsx b/x-pack/legacy/plugins/infra/public/components/source_configuration/indices_configuration_panel.tsx index d2129345d71b3..ee0e605baaf5c 100644 --- a/x-pack/legacy/plugins/infra/public/components/source_configuration/indices_configuration_panel.tsx +++ b/x-pack/legacy/plugins/infra/public/components/source_configuration/indices_configuration_panel.tsx @@ -4,7 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiCode, EuiFieldText, EuiForm, EuiFormRow, EuiSpacer, EuiTitle } from '@elastic/eui'; +import { + EuiCode, + EuiDescribedFormGroup, + EuiFieldText, + EuiForm, + EuiFormRow, + EuiSpacer, + EuiTitle, +} from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import React from 'react'; @@ -33,63 +41,97 @@ export const IndicesConfigurationPanel = ({ - metricbeat-*, - }} + id="xpack.infra.sourceConfiguration.metricIndicesTitle" + defaultMessage="Metric Indices" /> } - isInvalid={metricAliasFieldProps.isInvalid} - label={ + description={ } > - - - metricbeat-*, + }} + /> + } + isInvalid={metricAliasFieldProps.isInvalid} + label={ + + } + > + + + + filebeat-*, - }} + id="xpack.infra.sourceConfiguration.logIndicesTitle" + defaultMessage="Log Indices" /> } - isInvalid={logAliasFieldProps.isInvalid} - label={ + description={ } > - - + helpText={ + filebeat-*, + }} + /> + } + isInvalid={logAliasFieldProps.isInvalid} + label={ + + } + > + + + ); diff --git a/x-pack/legacy/plugins/infra/public/components/source_configuration/log_columns_configuration_panel.tsx b/x-pack/legacy/plugins/infra/public/components/source_configuration/log_columns_configuration_panel.tsx index 53d426eba0449..708fd34f23257 100644 --- a/x-pack/legacy/plugins/infra/public/components/source_configuration/log_columns_configuration_panel.tsx +++ b/x-pack/legacy/plugins/infra/public/components/source_configuration/log_columns_configuration_panel.tsx @@ -56,7 +56,7 @@ export const LogColumnsConfigurationPanel: React.FunctionComponent<

@@ -245,6 +245,7 @@ const RemoveLogColumnButton: React.FunctionComponent<{ iconType="trash" onClick={onClick} title={removeColumnLabel} + aria-label={removeColumnLabel} /> ); }; diff --git a/x-pack/legacy/plugins/infra/public/components/source_configuration/name_configuration_panel.tsx b/x-pack/legacy/plugins/infra/public/components/source_configuration/name_configuration_panel.tsx index 5d4f63f2c019f..7129097cff160 100644 --- a/x-pack/legacy/plugins/infra/public/components/source_configuration/name_configuration_panel.tsx +++ b/x-pack/legacy/plugins/infra/public/components/source_configuration/name_configuration_panel.tsx @@ -4,7 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiFieldText, EuiForm, EuiFormRow, EuiSpacer, EuiTitle } from '@elastic/eui'; +import { + EuiDescribedFormGroup, + EuiFieldText, + EuiForm, + EuiFormRow, + EuiSpacer, + EuiTitle, +} from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import React from 'react'; @@ -31,22 +38,36 @@ export const NameConfigurationPanel = ({ - } + description={ + + } > - - + isInvalid={nameFieldProps.isInvalid} + label={ + + } + > + + + ); diff --git a/x-pack/legacy/plugins/infra/public/components/source_configuration/source_configuration_button.tsx b/x-pack/legacy/plugins/infra/public/components/source_configuration/source_configuration_button.tsx deleted file mode 100644 index b05e5d9e34e08..0000000000000 --- a/x-pack/legacy/plugins/infra/public/components/source_configuration/source_configuration_button.tsx +++ /dev/null @@ -1,31 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { EuiButtonEmpty } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import React, { useContext } from 'react'; - -import { SourceConfigurationFlyoutState } from './source_configuration_flyout_state'; - -export const SourceConfigurationButton: React.FunctionComponent = () => { - const { toggleIsVisible } = useContext(SourceConfigurationFlyoutState.Context); - - return ( - - - - ); -}; diff --git a/x-pack/legacy/plugins/infra/public/components/source_configuration/source_configuration_flyout.tsx b/x-pack/legacy/plugins/infra/public/components/source_configuration/source_configuration_flyout.tsx deleted file mode 100644 index 4fea7b76e4f1f..0000000000000 --- a/x-pack/legacy/plugins/infra/public/components/source_configuration/source_configuration_flyout.tsx +++ /dev/null @@ -1,281 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { - EuiButton, - EuiButtonEmpty, - EuiCallOut, - EuiFlexGroup, - EuiFlexItem, - EuiFlyout, - EuiFlyoutBody, - EuiFlyoutFooter, - EuiFlyoutHeader, - EuiTabbedContent, - EuiTabbedContentTab, - EuiSpacer, - EuiTitle, -} from '@elastic/eui'; -import { FormattedMessage, injectI18n, InjectedIntl } from '@kbn/i18n/react'; -import React, { useCallback, useContext, useMemo } from 'react'; - -import { Source } from '../../containers/source'; -import { FieldsConfigurationPanel } from './fields_configuration_panel'; -import { IndicesConfigurationPanel } from './indices_configuration_panel'; -import { NameConfigurationPanel } from './name_configuration_panel'; -import { LogColumnsConfigurationPanel } from './log_columns_configuration_panel'; -import { isValidTabId, SourceConfigurationFlyoutState } from './source_configuration_flyout_state'; -import { useSourceConfigurationFormState } from './source_configuration_form_state'; - -const noop = () => undefined; - -interface SourceConfigurationFlyoutProps { - intl: InjectedIntl; - shouldAllowEdit: boolean; -} - -export const SourceConfigurationFlyout = injectI18n( - ({ intl, shouldAllowEdit }: SourceConfigurationFlyoutProps) => { - const { activeTabId, hide, isVisible, setActiveTab } = useContext( - SourceConfigurationFlyoutState.Context - ); - - const { - createSourceConfiguration, - source, - sourceExists, - isLoading, - updateSourceConfiguration, - } = useContext(Source.Context); - const availableFields = useMemo( - () => (source && source.status ? source.status.indexFields.map(field => field.name) : []), - [source] - ); - - const { - addLogColumn, - moveLogColumn, - indicesConfigurationProps, - logColumnConfigurationProps, - errors, - resetForm, - isFormDirty, - isFormValid, - formState, - formStateChanges, - } = useSourceConfigurationFormState(source && source.configuration); - - const persistUpdates = useCallback(async () => { - if (sourceExists) { - await updateSourceConfiguration(formStateChanges); - } else { - await createSourceConfiguration(formState); - } - resetForm(); - }, [ - sourceExists, - updateSourceConfiguration, - createSourceConfiguration, - resetForm, - formState, - formStateChanges, - ]); - - const isWriteable = useMemo(() => shouldAllowEdit && source && source.origin !== 'internal', [ - shouldAllowEdit, - source, - ]); - - const tabs: EuiTabbedContentTab[] = useMemo( - () => - isVisible - ? [ - { - id: 'indicesAndFieldsTab', - name: intl.formatMessage({ - id: 'xpack.infra.sourceConfiguration.sourceConfigurationIndicesTabTitle', - defaultMessage: 'Indices and fields', - }), - content: ( - <> - - - - - - - - ), - }, - { - id: 'logsTab', - name: intl.formatMessage({ - id: 'xpack.infra.sourceConfiguration.sourceConfigurationLogColumnsTabTitle', - defaultMessage: 'Log Columns', - }), - content: ( - <> - - - - ), - }, - ] - : [], - [ - addLogColumn, - moveLogColumn, - availableFields, - indicesConfigurationProps, - intl.formatMessage, - isLoading, - isVisible, - logColumnConfigurationProps, - isWriteable, - ] - ); - const activeTab = useMemo(() => tabs.filter(tab => tab.id === activeTabId)[0] || tabs[0], [ - activeTabId, - tabs, - ]); - const activateTab = useCallback( - (tab: EuiTabbedContentTab) => { - const tabId = tab.id; - if (isValidTabId(tabId)) { - setActiveTab(tabId); - } - }, - [setActiveTab, isValidTabId] - ); - - if (!isVisible || !source || !source.configuration) { - return null; - } - - return ( - - - -

- {isWriteable ? ( - - ) : ( - - )} -

-
-
- - - - - {errors.length > 0 ? ( - <> - -
    - {errors.map((error, errorIndex) => ( -
  • {error}
  • - ))} -
-
- - - ) : null} - - - {!isFormDirty ? ( - hide()} - > - - - ) : ( - { - resetForm(); - hide(); - }} - > - - - )} - - - {isWriteable && ( - - {isLoading ? ( - - Loading - - ) : ( - - - - )} - - )} - -
-
- ); - } -); diff --git a/x-pack/legacy/plugins/infra/public/components/source_configuration/source_configuration_flyout_state.tsx b/x-pack/legacy/plugins/infra/public/components/source_configuration/source_configuration_flyout_state.tsx deleted file mode 100644 index 6b12a4638d1e6..0000000000000 --- a/x-pack/legacy/plugins/infra/public/components/source_configuration/source_configuration_flyout_state.tsx +++ /dev/null @@ -1,51 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import createContainer from 'constate-latest'; -import { useCallback, useState } from 'react'; - -import { useVisibilityState } from '../../utils/use_visibility_state'; - -type TabId = 'indicesAndFieldsTab' | 'logsTab'; -const validTabIds: TabId[] = ['indicesAndFieldsTab', 'logsTab']; - -export const useSourceConfigurationFlyoutState = ({ - initialVisibility = false, - initialTab = 'indicesAndFieldsTab', -}: { - initialVisibility?: boolean; - initialTab?: TabId; -} = {}) => { - const { isVisible, show, hide, toggle: toggleIsVisible } = useVisibilityState(initialVisibility); - const [activeTabId, setActiveTab] = useState(initialTab); - - const showWithTab = useCallback( - (tabId?: TabId) => { - if (tabId != null) { - setActiveTab(tabId); - } - show(); - }, - [show] - ); - const showIndicesConfiguration = useCallback(() => showWithTab('indicesAndFieldsTab'), [show]); - const showLogsConfiguration = useCallback(() => showWithTab('logsTab'), [show]); - - return { - activeTabId, - hide, - isVisible, - setActiveTab, - show: showWithTab, - showIndicesConfiguration, - showLogsConfiguration, - toggleIsVisible, - }; -}; - -export const isValidTabId = (value: any): value is TabId => validTabIds.includes(value); - -export const SourceConfigurationFlyoutState = createContainer(useSourceConfigurationFlyoutState); diff --git a/x-pack/legacy/plugins/infra/public/components/source_configuration/source_configuration_settings.tsx b/x-pack/legacy/plugins/infra/public/components/source_configuration/source_configuration_settings.tsx new file mode 100644 index 0000000000000..1afdeb887ae1f --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/components/source_configuration/source_configuration_settings.tsx @@ -0,0 +1,213 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { + EuiButton, + EuiCallOut, + EuiFlexGroup, + EuiFlexItem, + EuiPanel, + EuiSpacer, + EuiPage, + EuiPageBody, + EuiPageContent, + EuiPageContentBody, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage, injectI18n, InjectedIntl } from '@kbn/i18n/react'; +import React, { useCallback, useContext, useMemo } from 'react'; +import { Prompt } from 'react-router-dom'; + +import { Source } from '../../containers/source'; +import { FieldsConfigurationPanel } from './fields_configuration_panel'; +import { IndicesConfigurationPanel } from './indices_configuration_panel'; +import { NameConfigurationPanel } from './name_configuration_panel'; +import { LogColumnsConfigurationPanel } from './log_columns_configuration_panel'; +import { useSourceConfigurationFormState } from './source_configuration_form_state'; + +interface SourceConfigurationSettingsProps { + intl: InjectedIntl; + shouldAllowEdit: boolean; +} + +export const SourceConfigurationSettings = injectI18n( + ({ shouldAllowEdit }: SourceConfigurationSettingsProps) => { + const { + createSourceConfiguration, + source, + sourceExists, + isLoading, + updateSourceConfiguration, + } = useContext(Source.Context); + + const availableFields = useMemo( + () => (source && source.status ? source.status.indexFields.map(field => field.name) : []), + [source] + ); + + const { + addLogColumn, + moveLogColumn, + indicesConfigurationProps, + logColumnConfigurationProps, + errors, + resetForm, + isFormDirty, + isFormValid, + formState, + formStateChanges, + } = useSourceConfigurationFormState(source && source.configuration); + + const persistUpdates = useCallback(async () => { + if (sourceExists) { + await updateSourceConfiguration(formStateChanges); + } else { + await createSourceConfiguration(formState); + } + resetForm(); + }, [ + sourceExists, + updateSourceConfiguration, + createSourceConfiguration, + resetForm, + formState, + formStateChanges, + ]); + + const isWriteable = useMemo(() => shouldAllowEdit && source && source.origin !== 'internal', [ + shouldAllowEdit, + source, + ]); + + if (!source || !source.configuration) { + return null; + } + + return ( + <> + + + + + + + + + + + + + + + + + + + + + {errors.length > 0 ? ( + <> + +
    + {errors.map((error, errorIndex) => ( +
  • {error}
  • + ))} +
+
+ + + ) : null} + + + {isWriteable && ( + + {isLoading ? ( + + + + Loading + + + + ) : ( + <> + + + { + resetForm(); + }} + > + + + + + + + + + + + )} + + )} + +
+
+
+
+ + ); + } +); diff --git a/x-pack/legacy/plugins/infra/public/components/source_configuration/view_source_configuration_button.tsx b/x-pack/legacy/plugins/infra/public/components/source_configuration/view_source_configuration_button.tsx new file mode 100644 index 0000000000000..9b584b2ef3bd0 --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/components/source_configuration/view_source_configuration_button.tsx @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { EuiButton } from '@elastic/eui'; +import React from 'react'; +import { Route } from 'react-router-dom'; + +export enum ViewSourceConfigurationButtonHrefBase { + infrastructure = 'infrastructure', + logs = 'logs', +} + +interface ViewSourceConfigurationButtonProps { + 'data-test-subj'?: string; + hrefBase: ViewSourceConfigurationButtonHrefBase; + children: React.ReactNode; +} + +export const ViewSourceConfigurationButton = ({ + 'data-test-subj': dataTestSubj, + hrefBase, + children, +}: ViewSourceConfigurationButtonProps) => { + const href = `/${hrefBase}/settings`; + + return ( + ( + history.push(href)}> + {children} + + )} + /> + ); +}; diff --git a/x-pack/legacy/plugins/infra/public/pages/infrastructure/index.tsx b/x-pack/legacy/plugins/infra/public/pages/infrastructure/index.tsx index 3cc40be7e5fe0..6105a241c0164 100644 --- a/x-pack/legacy/plugins/infra/public/pages/infrastructure/index.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/infrastructure/index.tsx @@ -15,10 +15,11 @@ import { ColumnarPage } from '../../components/page'; import { MetricsExplorerOptionsContainer } from '../../containers/metrics_explorer/use_metrics_explorer_options'; import { WithMetricsExplorerOptionsUrlState } from '../../containers/metrics_explorer/with_metrics_explorer_options_url_state'; import { WithSource } from '../../containers/with_source'; -import { SourceConfigurationFlyoutState } from '../../components/source_configuration'; import { Source } from '../../containers/source'; import { MetricsExplorerPage } from './metrics_explorer'; import { SnapshotPage } from './snapshot'; +import { SettingsPage } from '../shared/settings'; +import { AppNavigation } from '../../components/navigation/app_navigation'; interface InfrastructurePageProps extends RouteComponentProps { intl: InjectedIntl; @@ -26,23 +27,23 @@ interface InfrastructurePageProps extends RouteComponentProps { export const InfrastructurePage = injectI18n(({ match, intl }: InfrastructurePageProps) => ( - - - + + - + + + - - - ( - - {({ configuration, createDerivedIndexPattern }) => ( - - - - - )} - - )} - /> - - - + + + ( + + {({ configuration, createDerivedIndexPattern }) => ( + + + + + )} + + )} + /> + + + )); diff --git a/x-pack/legacy/plugins/infra/public/pages/infrastructure/snapshot/index.tsx b/x-pack/legacy/plugins/infra/public/pages/infrastructure/snapshot/index.tsx index 9b4efa44d483a..7e3c2110f1d12 100644 --- a/x-pack/legacy/plugins/infra/public/pages/infrastructure/snapshot/index.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/infrastructure/snapshot/index.tsx @@ -17,10 +17,12 @@ import { NoIndices } from '../../../components/empty_states/no_indices'; import { Header } from '../../../components/header'; import { ColumnarPage } from '../../../components/page'; -import { SourceConfigurationFlyout } from '../../../components/source_configuration'; -import { SourceConfigurationFlyoutState } from '../../../components/source_configuration'; import { SourceErrorPage } from '../../../components/source_error_page'; import { SourceLoadingPage } from '../../../components/source_loading_page'; +import { + ViewSourceConfigurationButton, + ViewSourceConfigurationButtonHrefBase, +} from '../../../components/source_configuration'; import { Source } from '../../../containers/source'; import { WithWaffleFilterUrlState } from '../../../containers/waffle/with_waffle_filters'; import { WithWaffleOptionsUrlState } from '../../../containers/waffle/with_waffle_options'; @@ -36,7 +38,6 @@ interface SnapshotPageProps { export const SnapshotPage = injectUICapabilities( injectI18n((props: SnapshotPageProps) => { const { intl, uiCapabilities } = props; - const { showIndicesConfiguration } = useContext(SourceConfigurationFlyoutState.Context); const { createDerivedIndexPattern, hasFailedLoadingSource, @@ -76,9 +77,6 @@ export const SnapshotPage = injectUICapabilities( ]} readOnlyBadge={!uiCapabilities.infrastructure.save} /> - {isLoading ? ( ) : metricIndicesExist ? ( @@ -120,16 +118,15 @@ export const SnapshotPage = injectUICapabilities( {uiCapabilities.infrastructure.configureSource ? ( - {intl.formatMessage({ id: 'xpack.infra.configureSourceActionLabel', defaultMessage: 'Change source configuration', })} - + ) : null} diff --git a/x-pack/legacy/plugins/infra/public/pages/infrastructure/snapshot/toolbar.tsx b/x-pack/legacy/plugins/infra/public/pages/infrastructure/snapshot/toolbar.tsx index 0d3fda093b223..5387d4901d24c 100644 --- a/x-pack/legacy/plugins/infra/public/pages/infrastructure/snapshot/toolbar.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/infrastructure/snapshot/toolbar.tsx @@ -10,7 +10,6 @@ import React from 'react'; import { AutocompleteField } from '../../../components/autocomplete_field'; import { Toolbar } from '../../../components/eui/toolbar'; -import { SourceConfigurationButton } from '../../../components/source_configuration'; import { WaffleGroupByControls } from '../../../components/waffle/waffle_group_by_controls'; import { WaffleMetricControls } from '../../../components/waffle/waffle_metric_controls'; import { WaffleNodeTypeSwitcher } from '../../../components/waffle/waffle_node_type_switcher'; @@ -111,9 +110,6 @@ export const SnapshotToolbar = injectI18n(({ intl }) => ( customOptions={customOptions} /> - - - )} diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/index.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/index.tsx new file mode 100644 index 0000000000000..949ad4b222ced --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/pages/logs/index.tsx @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { InjectedIntl, injectI18n } from '@kbn/i18n/react'; +import React from 'react'; +import { Route, RouteComponentProps, Switch } from 'react-router-dom'; + +import { DocumentTitle } from '../../components/document_title'; +import { HelpCenterContent } from '../../components/help_center_content'; +import { RoutedTabs } from '../../components/navigation/routed_tabs'; +import { ColumnarPage } from '../../components/page'; +import { Source } from '../../containers/source'; +import { StreamPage } from './stream'; +import { SettingsPage } from '../shared/settings'; +import { AppNavigation } from '../../components/navigation/app_navigation'; + +interface LogsPageProps extends RouteComponentProps { + intl: InjectedIntl; +} + +export const LogsPage = injectI18n(({ match, intl }: LogsPageProps) => ( + + + + + + + + + + + + + + + + +)); diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/page_header.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/page_header.tsx deleted file mode 100644 index d42a13b0e4de1..0000000000000 --- a/x-pack/legacy/plugins/infra/public/pages/logs/page_header.tsx +++ /dev/null @@ -1,57 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { injectI18n, InjectedIntl } from '@kbn/i18n/react'; -import React from 'react'; - -import { UICapabilities } from 'ui/capabilities'; -import { injectUICapabilities } from 'ui/capabilities/react'; -import { DocumentTitle } from '../../components/document_title'; -import { Header } from '../../components/header'; -import { HelpCenterContent } from '../../components/help_center_content'; -import { SourceConfigurationFlyout } from '../../components/source_configuration'; - -interface LogsPageHeaderProps { - intl: InjectedIntl; - uiCapabilities: UICapabilities; -} - -export const LogsPageHeader = injectUICapabilities( - injectI18n((props: LogsPageHeaderProps) => { - const { intl, uiCapabilities } = props; - return ( - <> -
- - - - - ); - }) -); diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/page_providers.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/page_providers.tsx deleted file mode 100644 index 82aea7b380034..0000000000000 --- a/x-pack/legacy/plugins/infra/public/pages/logs/page_providers.tsx +++ /dev/null @@ -1,33 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; - -import { SourceConfigurationFlyoutState } from '../../components/source_configuration'; -import { LogFlyout } from '../../containers/logs/log_flyout'; -import { LogViewConfiguration } from '../../containers/logs/log_view_configuration'; -import { LogHighlightsState } from '../../containers/logs/log_highlights/log_highlights'; -import { Source, useSource } from '../../containers/source'; -import { useSourceId } from '../../containers/source_id'; - -export const LogsPageProviders: React.FunctionComponent = ({ children }) => { - const [sourceId] = useSourceId(); - const source = useSource({ sourceId }); - - return ( - - - - - - {children} - - - - - - ); -}; diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/index.ts b/x-pack/legacy/plugins/infra/public/pages/logs/stream/index.ts similarity index 86% rename from x-pack/legacy/plugins/infra/public/pages/logs/index.ts rename to x-pack/legacy/plugins/infra/public/pages/logs/stream/index.ts index 1d1c8cc65287f..928c6187ec078 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/index.ts +++ b/x-pack/legacy/plugins/infra/public/pages/logs/stream/index.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { LogsPage } from './page'; +export { StreamPage } from './page'; diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/page.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page.tsx similarity index 65% rename from x-pack/legacy/plugins/infra/public/pages/logs/page.tsx rename to x-pack/legacy/plugins/infra/public/pages/logs/stream/page.tsx index 32c86641d6755..9031a8cb4785d 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/page.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page.tsx @@ -6,20 +6,20 @@ import React from 'react'; -import { ColumnarPage } from '../../components/page'; -import { LogsPageContent } from './page_content'; -import { LogsPageHeader } from './page_header'; +import { ColumnarPage } from '../../../components/page'; +import { StreamPageContent } from './page_content'; +import { StreamPageHeader } from './page_header'; import { LogsPageProviders } from './page_providers'; -import { useTrackPageview } from '../../hooks/use_track_metric'; +import { useTrackPageview } from '../../../hooks/use_track_metric'; -export const LogsPage = () => { +export const StreamPage = () => { useTrackPageview({ app: 'infra_logs', path: 'stream' }); useTrackPageview({ app: 'infra_logs', path: 'stream', delay: 15000 }); return ( - - + + ); diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/page_content.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_content.tsx similarity index 77% rename from x-pack/legacy/plugins/infra/public/pages/logs/page_content.tsx rename to x-pack/legacy/plugins/infra/public/pages/logs/stream/page_content.tsx index a8dde0532283a..abcc881dd250e 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/page_content.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_content.tsx @@ -6,13 +6,13 @@ import React, { useContext } from 'react'; -import { SourceErrorPage } from '../../components/source_error_page'; -import { SourceLoadingPage } from '../../components/source_loading_page'; -import { Source } from '../../containers/source'; +import { SourceErrorPage } from '../../../components/source_error_page'; +import { SourceLoadingPage } from '../../../components/source_loading_page'; +import { Source } from '../../../containers/source'; import { LogsPageLogsContent } from './page_logs_content'; import { LogsPageNoIndicesContent } from './page_no_indices_content'; -export const LogsPageContent: React.FunctionComponent = () => { +export const StreamPageContent: React.FunctionComponent = () => { const { hasFailedLoadingSource, isLoadingSource, diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_header.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_header.tsx new file mode 100644 index 0000000000000..b46189c462c6b --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_header.tsx @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import React from 'react'; + +import { UICapabilities } from 'ui/capabilities'; +import { injectUICapabilities } from 'ui/capabilities/react'; +import { DocumentTitle } from '../../../components/document_title'; +import { Header } from '../../../components/header'; + +interface StreamPageHeaderProps { + uiCapabilities: UICapabilities; +} + +export const StreamPageHeader = injectUICapabilities((props: StreamPageHeaderProps) => { + const { uiCapabilities } = props; + return ( + <> +
+ + i18n.translate('xpack.infra.logs.streamPage.documentTitle', { + defaultMessage: '{previousTitle} | Stream', + values: { + previousTitle, + }, + }) + } + /> + + ); +}); diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/page_logs_content.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_logs_content.tsx similarity index 77% rename from x-pack/legacy/plugins/infra/public/pages/logs/page_logs_content.tsx rename to x-pack/legacy/plugins/infra/public/pages/logs/stream/page_logs_content.tsx index 007584d4cacc8..2ead89f94f812 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/page_logs_content.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_logs_content.tsx @@ -6,30 +6,29 @@ import React, { useContext } from 'react'; -import euiStyled from '../../../../../common/eui_styled_components'; -import { AutoSizer } from '../../components/auto_sizer'; -import { LogEntryFlyout } from '../../components/logging/log_entry_flyout'; -import { LogMinimap } from '../../components/logging/log_minimap'; -import { ScrollableLogTextStreamView } from '../../components/logging/log_text_stream'; -import { PageContent } from '../../components/page'; +import euiStyled from '../../../../../../common/eui_styled_components'; +import { AutoSizer } from '../../../components/auto_sizer'; +import { LogEntryFlyout } from '../../../components/logging/log_entry_flyout'; +import { LogMinimap } from '../../../components/logging/log_minimap'; +import { ScrollableLogTextStreamView } from '../../../components/logging/log_text_stream'; +import { PageContent } from '../../../components/page'; -import { WithSummary } from '../../containers/logs/log_summary'; -import { LogViewConfiguration } from '../../containers/logs/log_view_configuration'; -import { WithLogFilter, WithLogFilterUrlState } from '../../containers/logs/with_log_filter'; +import { WithSummary } from '../../../containers/logs/log_summary'; +import { LogViewConfiguration } from '../../../containers/logs/log_view_configuration'; +import { WithLogFilter, WithLogFilterUrlState } from '../../../containers/logs/with_log_filter'; import { LogFlyout as LogFlyoutState, WithFlyoutOptionsUrlState, -} from '../../containers/logs/log_flyout'; -import { WithLogMinimapUrlState } from '../../containers/logs/with_log_minimap'; -import { WithLogPositionUrlState } from '../../containers/logs/with_log_position'; -import { WithLogPosition } from '../../containers/logs/with_log_position'; -import { WithLogTextviewUrlState } from '../../containers/logs/with_log_textview'; -import { ReduxSourceIdBridge, WithStreamItems } from '../../containers/logs/with_stream_items'; -import { Source } from '../../containers/source'; +} from '../../../containers/logs/log_flyout'; +import { WithLogMinimapUrlState } from '../../../containers/logs/with_log_minimap'; +import { WithLogPositionUrlState } from '../../../containers/logs/with_log_position'; +import { WithLogPosition } from '../../../containers/logs/with_log_position'; +import { WithLogTextviewUrlState } from '../../../containers/logs/with_log_textview'; +import { ReduxSourceIdBridge, WithStreamItems } from '../../../containers/logs/with_stream_items'; +import { Source } from '../../../containers/source'; import { LogsToolbar } from './page_toolbar'; -import { SourceConfigurationFlyoutState } from '../../components/source_configuration'; -import { LogHighlightsBridge } from '../../containers/logs/log_highlights'; +import { LogHighlightsBridge } from '../../../containers/logs/log_highlights'; export const LogsPageLogsContent: React.FunctionComponent = () => { const { createDerivedIndexPattern, source, sourceId, version } = useContext(Source.Context); @@ -43,7 +42,6 @@ export const LogsPageLogsContent: React.FunctionComponent = () => { flyoutItem, isLoading, } = useContext(LogFlyoutState.Context); - const { showLogsConfiguration } = useContext(SourceConfigurationFlyoutState.Context); const derivedIndexPattern = createDerivedIndexPattern('logs'); @@ -105,7 +103,6 @@ export const LogsPageLogsContent: React.FunctionComponent = () => { loadNewerItems={loadNewerEntries} reportVisibleInterval={reportVisiblePositions} scale={textScale} - showColumnConfiguration={showLogsConfiguration} target={targetPosition} wrap={textWrap} setFlyoutItem={setFlyoutId} diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/page_no_indices_content.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_no_indices_content.tsx similarity index 82% rename from x-pack/legacy/plugins/infra/public/pages/logs/page_no_indices_content.tsx rename to x-pack/legacy/plugins/infra/public/pages/logs/stream/page_no_indices_content.tsx index a7392fafbeeae..70de44c37ef54 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/page_no_indices_content.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_no_indices_content.tsx @@ -6,13 +6,16 @@ import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { injectI18n, InjectedIntl } from '@kbn/i18n/react'; -import React, { useContext } from 'react'; +import React from 'react'; import { UICapabilities } from 'ui/capabilities'; import { injectUICapabilities } from 'ui/capabilities/react'; -import { NoIndices } from '../../components/empty_states/no_indices'; -import { SourceConfigurationFlyoutState } from '../../components/source_configuration'; -import { WithKibanaChrome } from '../../containers/with_kibana_chrome'; +import { NoIndices } from '../../../components/empty_states/no_indices'; +import { WithKibanaChrome } from '../../../containers/with_kibana_chrome'; +import { + ViewSourceConfigurationButton, + ViewSourceConfigurationButtonHrefBase, +} from '../../../components/source_configuration'; interface LogsPageNoIndicesContentProps { intl: InjectedIntl; @@ -22,7 +25,6 @@ interface LogsPageNoIndicesContentProps { export const LogsPageNoIndicesContent = injectUICapabilities( injectI18n((props: LogsPageNoIndicesContentProps) => { const { intl, uiCapabilities } = props; - const { showIndicesConfiguration } = useContext(SourceConfigurationFlyoutState.Context); return ( @@ -54,16 +56,15 @@ export const LogsPageNoIndicesContent = injectUICapabilities( {uiCapabilities.logs.configureSource ? ( - {intl.formatMessage({ id: 'xpack.infra.configureSourceActionLabel', defaultMessage: 'Change source configuration', })} - + ) : null} diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_providers.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_providers.tsx new file mode 100644 index 0000000000000..b93cf48bde5e7 --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_providers.tsx @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; + +import { LogFlyout } from '../../../containers/logs/log_flyout'; +import { LogViewConfiguration } from '../../../containers/logs/log_view_configuration'; +import { LogHighlightsState } from '../../../containers/logs/log_highlights/log_highlights'; +import { Source, useSource } from '../../../containers/source'; +import { useSourceId } from '../../../containers/source_id'; + +export const LogsPageProviders: React.FunctionComponent = ({ children }) => { + const [sourceId] = useSourceId(); + const source = useSource({ sourceId }); + + return ( + + + + + {children} + + + + + ); +}; diff --git a/x-pack/legacy/plugins/infra/public/pages/logs/page_toolbar.tsx b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_toolbar.tsx similarity index 78% rename from x-pack/legacy/plugins/infra/public/pages/logs/page_toolbar.tsx rename to x-pack/legacy/plugins/infra/public/pages/logs/stream/page_toolbar.tsx index 8a132fd9e0c71..46cf3aab40e9f 100644 --- a/x-pack/legacy/plugins/infra/public/pages/logs/page_toolbar.tsx +++ b/x-pack/legacy/plugins/infra/public/pages/logs/stream/page_toolbar.tsx @@ -8,22 +8,21 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { injectI18n } from '@kbn/i18n/react'; import React, { useContext } from 'react'; -import { AutocompleteField } from '../../components/autocomplete_field'; -import { Toolbar } from '../../components/eui'; -import { LogCustomizationMenu } from '../../components/logging/log_customization_menu'; -import { LogHighlightsMenu } from '../../components/logging/log_highlights_menu'; -import { LogHighlightsState } from '../../containers/logs/log_highlights/log_highlights'; -import { LogMinimapScaleControls } from '../../components/logging/log_minimap_scale_controls'; -import { LogTextScaleControls } from '../../components/logging/log_text_scale_controls'; -import { LogTextWrapControls } from '../../components/logging/log_text_wrap_controls'; -import { LogTimeControls } from '../../components/logging/log_time_controls'; -import { SourceConfigurationButton } from '../../components/source_configuration'; -import { LogFlyout } from '../../containers/logs/log_flyout'; -import { LogViewConfiguration } from '../../containers/logs/log_view_configuration'; -import { WithLogFilter } from '../../containers/logs/with_log_filter'; -import { WithLogPosition } from '../../containers/logs/with_log_position'; -import { Source } from '../../containers/source'; -import { WithKueryAutocompletion } from '../../containers/with_kuery_autocompletion'; +import { AutocompleteField } from '../../../components/autocomplete_field'; +import { Toolbar } from '../../../components/eui'; +import { LogCustomizationMenu } from '../../../components/logging/log_customization_menu'; +import { LogHighlightsMenu } from '../../../components/logging/log_highlights_menu'; +import { LogHighlightsState } from '../../../containers/logs/log_highlights/log_highlights'; +import { LogMinimapScaleControls } from '../../../components/logging/log_minimap_scale_controls'; +import { LogTextScaleControls } from '../../../components/logging/log_text_scale_controls'; +import { LogTextWrapControls } from '../../../components/logging/log_text_wrap_controls'; +import { LogTimeControls } from '../../../components/logging/log_time_controls'; +import { LogFlyout } from '../../../containers/logs/log_flyout'; +import { LogViewConfiguration } from '../../../containers/logs/log_view_configuration'; +import { WithLogFilter } from '../../../containers/logs/with_log_filter'; +import { WithLogPosition } from '../../../containers/logs/with_log_position'; +import { Source } from '../../../containers/source'; +import { WithKueryAutocompletion } from '../../../containers/with_kuery_autocompletion'; export const LogsToolbar = injectI18n(({ intl }) => { const { createDerivedIndexPattern } = useContext(Source.Context); @@ -91,9 +90,6 @@ export const LogsToolbar = injectI18n(({ intl }) => { )} - - - - (Component: React.Compo props: T ) => ( - - - - - + + + ); diff --git a/x-pack/legacy/plugins/infra/public/pages/shared/settings/index.tsx b/x-pack/legacy/plugins/infra/public/pages/shared/settings/index.tsx new file mode 100644 index 0000000000000..daea6cfabdc2a --- /dev/null +++ b/x-pack/legacy/plugins/infra/public/pages/shared/settings/index.tsx @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { UICapabilities } from 'ui/capabilities'; +import { injectUICapabilities } from 'ui/capabilities/react'; +import { SourceConfigurationSettings } from '../../../components/source_configuration/source_configuration_settings'; + +interface SettingsPageProps { + uiCapabilities: UICapabilities; +} + +export const SettingsPage = injectUICapabilities(({ uiCapabilities }: SettingsPageProps) => ( + +)); diff --git a/x-pack/legacy/plugins/infra/public/routes.tsx b/x-pack/legacy/plugins/infra/public/routes.tsx index e9343c963549f..dcdb40cb5ed7e 100644 --- a/x-pack/legacy/plugins/infra/public/routes.tsx +++ b/x-pack/legacy/plugins/infra/public/routes.tsx @@ -37,6 +37,7 @@ const PageRouterComponent: React.SFC = ({ history, uiCapabilities } {uiCapabilities.infrastructure.show && ( )} + {uiCapabilities.logs.show && } {uiCapabilities.logs.show && } {uiCapabilities.infrastructure.show && ( diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index c514313458239..40cf0509c7c0a 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -484,11 +484,6 @@ "common.ui.indexPattern.unknownFieldHeader": "不明なフィールドタイプ {type}", "common.ui.indexPattern.warningText": "現在 {index} に一致するすべてのインデックスにクエリを実行しています。{title} はワイルドカードベースのインデックスパターンに移行されるはずです。", "common.ui.indexPattern.warningTitle": "時間間隔インデックスパターンのサポートは廃止されました", - "inspector.closeButton": "インスペクターを閉じる", - "inspector.reqTimestampDescription": "リクエストの開始が記録された時刻です", - "inspector.reqTimestampKey": "リクエストのタイムスタンプ", - "inspector.title": "インスペクター", - "inspector.view": "{viewName} を表示", "common.ui.legacyBrowserMessage": "この Kibana インストレーションは、現在ご使用のブラウザが満たしていない厳格なセキュリティ要件が有効になっています。", "common.ui.legacyBrowserTitle": "ブラウザをアップグレードしてください", "common.ui.management.breadcrumb": "管理", @@ -615,6 +610,11 @@ "common.ui.visualize.queryGeohashBounds.unableToGetBoundErrorTitle": "バウンドを取得できませんでした", "common.ui.welcomeErrorMessage": "Kibana が正常に読み込まれませんでした。詳細はサーバーアウトプットを確認してください。", "common.ui.welcomeMessage": "Kibana を読み込み中", + "inspector.closeButton": "インスペクターを閉じる", + "inspector.reqTimestampDescription": "リクエストの開始が記録された時刻です", + "inspector.reqTimestampKey": "リクエストのタイムスタンプ", + "inspector.title": "インスペクター", + "inspector.view": "{viewName} を表示", "core.ui.chrome.headerGlobalNav.goHomePageIconAriaLabel": "ホームページに移動", "core.ui.chrome.headerGlobalNav.helpMenuButtonAriaLabel": "ヘルプメニュー", "core.ui.chrome.headerGlobalNav.helpMenuGoToDocumentation": "ドキュメントに移動", @@ -5081,7 +5081,6 @@ "xpack.infra.linkLogsTitle": "ログ", "xpack.infra.linkTo.hostWithIp.error": "IP アドレス「{hostIp}」でホストが見つかりません.", "xpack.infra.linkTo.hostWithIp.loading": "IP アドレス「{hostIp}」のホストを読み込み中", - "xpack.infra.logColumnHeaders.configureColumnsLabel": "列を構成", "xpack.infra.logEntryActionsMenu.buttonLabel": "アクション", "xpack.infra.logEntryActionsMenu.uptimeActionLabel": "監視ステータスを表示", "xpack.infra.logEntryItemView.viewDetailsToolTip": "詳細を表示", @@ -5114,8 +5113,6 @@ "xpack.infra.logs.stopStreamingButtonLabel": "ストリーム停止", "xpack.infra.logs.streamingDescription": "新しいエントリーをストリーム中...", "xpack.infra.logs.streamingNewEntriesText": "新しいエントリーをストリーム中", - "xpack.infra.logsPage.documentTitle": "ログ", - "xpack.infra.logsPage.logsBreadcrumbsText": "ログ", "xpack.infra.logsPage.logsHelpContent.feedbackLinkText": "ログのフィードバックを提供", "xpack.infra.logsPage.noLoggingIndicesDescription": "追加しましょう!", "xpack.infra.logsPage.noLoggingIndicesInstructionsActionLabel": "セットアップの手順を表示", @@ -5237,10 +5234,7 @@ "xpack.infra.registerFeatures.logsDescription": "ログをリアルタイムでストリーするか、コンソール式の UI で履歴ビューをスクロールします。", "xpack.infra.registerFeatures.logsTitle": "ログ", "xpack.infra.sourceConfiguration.addLogColumnButtonLabel": "列を追加", - "xpack.infra.sourceConfiguration.closeButtonLabel": "閉じる", - "xpack.infra.sourceConfiguration.containerFieldDescription": "Docker コンテナーの識別に使用されるフィールドです。推奨値は {defaultValue} です。", "xpack.infra.sourceConfiguration.containerFieldLabel": "コンテナー ID", - "xpack.infra.sourceConfiguration.discardAndCloseButtonLabel": "破棄して閉じる", "xpack.infra.sourceConfiguration.fieldEmptyErrorMessage": "このフィールドは未入力のままにできません。", "xpack.infra.sourceConfiguration.fieldLogColumnTitle": "フィールド", "xpack.infra.sourceConfiguration.fieldsSectionTitle": "フィールド", @@ -5249,29 +5243,18 @@ "xpack.infra.sourceConfiguration.indicesSectionTitle": "インデックス", "xpack.infra.sourceConfiguration.logColumnListEmptyErrorMessage": "ログ列リストは未入力のままにできません。", "xpack.infra.sourceConfiguration.logColumnsSectionTitle": "列", - "xpack.infra.sourceConfiguration.logIndicesDescription": "ログデータを含む一致するインデックスのインデックスパターンです。推奨値は {defaultValue} です。", "xpack.infra.sourceConfiguration.logIndicesLabel": "ログインデックス", "xpack.infra.sourceConfiguration.messageLogColumnDescription": "このシステムフィールドは、ドキュメントフィールドから取得されたログエントリーメッセージを表示します。", - "xpack.infra.sourceConfiguration.metricIndicesDescription": "Metricbeat データを含む一致するインデックスのインデックスパターンです。推奨値は {defaultValue} です。", "xpack.infra.sourceConfiguration.metricIndicesLabel": "メトリックインデックス", "xpack.infra.sourceConfiguration.nameLabel": "名前", "xpack.infra.sourceConfiguration.nameSectionTitle": "名前", "xpack.infra.sourceConfiguration.noLogColumnsDescription": "上のボタンでこのリストに列を追加します。", "xpack.infra.sourceConfiguration.noLogColumnsTitle": "列がありません", - "xpack.infra.sourceConfiguration.podFieldDescription": "Kubernetes ポッドの識別に使用されるフィールドです。推奨値は {defaultValue} です。", "xpack.infra.sourceConfiguration.podFieldLabel": "ポッド ID", - "xpack.infra.sourceConfiguration.sourceConfigurationButtonLabel": "構成", - "xpack.infra.sourceConfiguration.sourceConfigurationIndicesTabTitle": "インデックスとフィールド", - "xpack.infra.sourceConfiguration.sourceConfigurationLogColumnsTabTitle": "ログ列", - "xpack.infra.sourceConfiguration.sourceConfigurationReadonlyTitle": "ソース構成を表示", - "xpack.infra.sourceConfiguration.sourceConfigurationTitle": "ソースの構成", "xpack.infra.sourceConfiguration.systemColumnBadgeLabel": "システム", - "xpack.infra.sourceConfiguration.tiebreakerFieldDescription": "同じタイムスタンプの 2 つのエントリーを識別するのに使用されるフィールドです。推奨値は {defaultValue} です。", "xpack.infra.sourceConfiguration.tiebreakerFieldLabel": "タイブレーカー", - "xpack.infra.sourceConfiguration.timestampFieldDescription": "ログエントリーの並べ替えに使用されるタイムスタンプです。推奨値は {defaultValue} です。", "xpack.infra.sourceConfiguration.timestampFieldLabel": "タイムスタンプ", "xpack.infra.sourceConfiguration.timestampLogColumnDescription": "このシステムフィールドは、{timestampSetting} フィールド設定から判断されたログエントリーの時刻を表示します。", - "xpack.infra.sourceConfiguration.updateSourceConfigurationButtonLabel": "ソースを更新", "xpack.infra.sourceErrorPage.failedToLoadDataSourcesMessage": "データソースの読み込みに失敗しました。", "xpack.infra.sourceLoadingPage.loadingDataSourcesMessage": "データソースを読み込み中", "xpack.infra.tableView.columnName.avg": "平均", @@ -10646,4 +10629,4 @@ "xpack.watcher.watchActions.logging.logTextIsRequiredValidationMessage": "ログテキストが必要です。", "xpack.watcher.watcherDescription": "アラートの作成、管理、監視によりデータへの変更を検知します。" } -} +} \ No newline at end of file diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 04ee0ff854a35..5beee270a5271 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -484,11 +484,6 @@ "common.ui.indexPattern.unknownFieldHeader": "未知字段类型 {type}", "common.ui.indexPattern.warningText": "当前正在查询所有匹配 {index} 的索引。{title} 应迁移到基于通配符的索引模式。", "common.ui.indexPattern.warningTitle": "已移除对时间间隔索引模式的支持", - "inspector.closeButton": "关闭检查器", - "inspector.reqTimestampDescription": "记录请求启动的时间", - "inspector.reqTimestampKey": "请求时间戳", - "inspector.title": "检查器", - "inspector.view": "视图:{viewName}", "common.ui.legacyBrowserMessage": "此 Kibana 安装启用了当前浏览器未满足的严格安全要求。", "common.ui.legacyBrowserTitle": "请升级您的浏览器", "common.ui.management.breadcrumb": "管理", @@ -616,6 +611,11 @@ "common.ui.visualize.queryGeohashBounds.unableToGetBoundErrorTitle": "无法获取边界", "common.ui.welcomeErrorMessage": "Kibana 未正确加载。检查服务器输出以了解详情。", "common.ui.welcomeMessage": "正在加载 Kibana", + "inspector.closeButton": "关闭检查器", + "inspector.reqTimestampDescription": "记录请求启动的时间", + "inspector.reqTimestampKey": "请求时间戳", + "inspector.title": "检查器", + "inspector.view": "视图:{viewName}", "core.ui.chrome.headerGlobalNav.goHomePageIconAriaLabel": "前往主页", "core.ui.chrome.headerGlobalNav.helpMenuButtonAriaLabel": "帮助菜单", "core.ui.chrome.headerGlobalNav.helpMenuGoToDocumentation": "前往文档", @@ -5224,7 +5224,6 @@ "xpack.infra.linkLogsTitle": "Logs", "xpack.infra.linkTo.hostWithIp.error": "未找到 IP 地址为“{hostIp}”的主机。", "xpack.infra.linkTo.hostWithIp.loading": "正在加载 IP 地址为“{hostIp}”的主机。", - "xpack.infra.logColumnHeaders.configureColumnsLabel": "配置列", "xpack.infra.logEntryActionsMenu.buttonLabel": "操作", "xpack.infra.logEntryActionsMenu.uptimeActionLabel": "查看监测状态", "xpack.infra.logEntryItemView.viewDetailsToolTip": "查看详情", @@ -5257,8 +5256,6 @@ "xpack.infra.logs.stopStreamingButtonLabel": "停止流式传输", "xpack.infra.logs.streamingDescription": "正在流式传输新条目……", "xpack.infra.logs.streamingNewEntriesText": "正在流式传输新条目", - "xpack.infra.logsPage.documentTitle": "Logs", - "xpack.infra.logsPage.logsBreadcrumbsText": "Logs", "xpack.infra.logsPage.logsHelpContent.feedbackLinkText": "提供 Logs 的反馈", "xpack.infra.logsPage.noLoggingIndicesDescription": "让我们添加一些!", "xpack.infra.logsPage.noLoggingIndicesInstructionsActionLabel": "查看设置说明", @@ -5380,10 +5377,7 @@ "xpack.infra.registerFeatures.logsDescription": "实时流式传输日志或在类似控制台的工具中滚动浏览历史视图。", "xpack.infra.registerFeatures.logsTitle": "Logs", "xpack.infra.sourceConfiguration.addLogColumnButtonLabel": "添加列", - "xpack.infra.sourceConfiguration.closeButtonLabel": "关闭", - "xpack.infra.sourceConfiguration.containerFieldDescription": "用于标识 Docker 容器的字段。推荐值为 {defaultValue}。", "xpack.infra.sourceConfiguration.containerFieldLabel": "容器 ID", - "xpack.infra.sourceConfiguration.discardAndCloseButtonLabel": "丢弃并关闭", "xpack.infra.sourceConfiguration.fieldEmptyErrorMessage": "字段不得为空。", "xpack.infra.sourceConfiguration.fieldLogColumnTitle": "字段", "xpack.infra.sourceConfiguration.fieldsSectionTitle": "字段", @@ -5392,29 +5386,18 @@ "xpack.infra.sourceConfiguration.indicesSectionTitle": "索引", "xpack.infra.sourceConfiguration.logColumnListEmptyErrorMessage": "日志列列表不得为空。", "xpack.infra.sourceConfiguration.logColumnsSectionTitle": "列", - "xpack.infra.sourceConfiguration.logIndicesDescription": "用于匹配包含日志数据的索引的索引模式。推荐值为 {defaultValue}。", "xpack.infra.sourceConfiguration.logIndicesLabel": "日志索引", "xpack.infra.sourceConfiguration.messageLogColumnDescription": "此系统字段显示派生自文档字段的日志条目消息。", - "xpack.infra.sourceConfiguration.metricIndicesDescription": "用于匹配包含 Metricbeat 数据的索引的索引模式。推荐值为 {defaultValue}。", "xpack.infra.sourceConfiguration.metricIndicesLabel": "指标索引", "xpack.infra.sourceConfiguration.nameLabel": "名称", "xpack.infra.sourceConfiguration.nameSectionTitle": "名称", "xpack.infra.sourceConfiguration.noLogColumnsDescription": "使用上面的按钮将列添加到此列表。", "xpack.infra.sourceConfiguration.noLogColumnsTitle": "无列", - "xpack.infra.sourceConfiguration.podFieldDescription": "用于标识 Kubernetes Pod 的字段。推荐值为 {defaultValue}。", "xpack.infra.sourceConfiguration.podFieldLabel": "Pod ID", - "xpack.infra.sourceConfiguration.sourceConfigurationButtonLabel": "配置", - "xpack.infra.sourceConfiguration.sourceConfigurationIndicesTabTitle": "索引和字段", - "xpack.infra.sourceConfiguration.sourceConfigurationLogColumnsTabTitle": "日志列", - "xpack.infra.sourceConfiguration.sourceConfigurationReadonlyTitle": "查看源配置", - "xpack.infra.sourceConfiguration.sourceConfigurationTitle": "配置源", "xpack.infra.sourceConfiguration.systemColumnBadgeLabel": "系统", - "xpack.infra.sourceConfiguration.tiebreakerFieldDescription": "用于时间戳相同的两个条目间决胜的字段。推荐值为 {defaultValue}。", "xpack.infra.sourceConfiguration.tiebreakerFieldLabel": "决胜属性", - "xpack.infra.sourceConfiguration.timestampFieldDescription": "用于排序日志条目的时间戳。推荐值为 {defaultValue}。", "xpack.infra.sourceConfiguration.timestampFieldLabel": "时间戳", "xpack.infra.sourceConfiguration.timestampLogColumnDescription": "此系统字段显示 {timestampSetting} 字段设置所确定的日志条目时间。", - "xpack.infra.sourceConfiguration.updateSourceConfigurationButtonLabel": "更新源", "xpack.infra.sourceErrorPage.failedToLoadDataSourcesMessage": "无法加载数据源。", "xpack.infra.sourceLoadingPage.loadingDataSourcesMessage": "正在加载数据源", "xpack.infra.tableView.columnName.avg": "平均值", @@ -10788,4 +10771,4 @@ "xpack.watcher.watchActions.logging.logTextIsRequiredValidationMessage": "“日志文本”必填。", "xpack.watcher.watcherDescription": "通过创建、管理和监测警报来检测数据中的更改。" } -} +} \ No newline at end of file diff --git a/x-pack/test/functional/apps/infra/logs_source_configuration.ts b/x-pack/test/functional/apps/infra/logs_source_configuration.ts index 27a950ef827ee..3447e03a680e1 100644 --- a/x-pack/test/functional/apps/infra/logs_source_configuration.ts +++ b/x-pack/test/functional/apps/infra/logs_source_configuration.ts @@ -11,10 +11,10 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default ({ getPageObjects, getService }: FtrProviderContext) => { const esArchiver = getService('esArchiver'); const infraLogStream = getService('infraLogStream'); - const infraSourceConfigurationFlyout = getService('infraSourceConfigurationFlyout'); - const pageObjects = getPageObjects(['infraLogs']); + const infraSourceConfigurationForm = getService('infraSourceConfigurationForm'); + const pageObjects = getPageObjects(['common', 'infraLogs']); - describe('Logs Page', function() { + describe('Logs Source Configuration', function() { this.tags('smoke'); before(async () => { await esArchiver.load('empty_kibana'); @@ -23,7 +23,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await esArchiver.unload('empty_kibana'); }); - describe('with logs present', () => { + describe('Allows indices configuration', () => { before(async () => { await esArchiver.load('infra/metrics_and_logs'); }); @@ -31,54 +31,44 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await esArchiver.unload('infra/metrics_and_logs'); }); - it('renders the log stream', async () => { - await pageObjects.infraLogs.navigateTo(); - await pageObjects.infraLogs.getLogStream(); - }); - it('can change the log indices to a pattern that matches nothing', async () => { - await pageObjects.infraLogs.openSourceConfigurationFlyout(); - await infraSourceConfigurationFlyout.switchToIndicesAndFieldsTab(); + await pageObjects.common.navigateToActualUrl('infraLogs', 'logs/settings'); + await infraSourceConfigurationForm.getForm(); - const nameInput = await infraSourceConfigurationFlyout.getNameInput(); + const nameInput = await infraSourceConfigurationForm.getNameInput(); await nameInput.clearValueWithKeyboard({ charByChar: true }); await nameInput.type('Modified Source'); - const logIndicesInput = await infraSourceConfigurationFlyout.getLogIndicesInput(); + const logIndicesInput = await infraSourceConfigurationForm.getLogIndicesInput(); await logIndicesInput.clearValueWithKeyboard({ charByChar: true }); await logIndicesInput.type('does-not-exist-*'); - await infraSourceConfigurationFlyout.saveConfiguration(); - await infraSourceConfigurationFlyout.closeFlyout(); + await infraSourceConfigurationForm.saveConfiguration(); }); it('renders the no indices screen when no indices match the pattern', async () => { + await pageObjects.common.navigateToActualUrl('infraLogs', 'logs/stream'); await pageObjects.infraLogs.getNoLogsIndicesPrompt(); }); it('can change the log indices back to a pattern that matches something', async () => { - await pageObjects.infraLogs.openSourceConfigurationFlyout(); - await infraSourceConfigurationFlyout.switchToIndicesAndFieldsTab(); + await pageObjects.common.navigateToActualUrl('infraLogs', 'logs/settings'); + await infraSourceConfigurationForm.getForm(); - const logIndicesInput = await infraSourceConfigurationFlyout.getLogIndicesInput(); + const logIndicesInput = await infraSourceConfigurationForm.getLogIndicesInput(); await logIndicesInput.clearValueWithKeyboard({ charByChar: true }); await logIndicesInput.type('filebeat-*'); - await infraSourceConfigurationFlyout.saveConfiguration(); - await infraSourceConfigurationFlyout.closeFlyout(); - }); - - it('renders the log stream again', async () => { - await pageObjects.infraLogs.getLogStream(); + await infraSourceConfigurationForm.saveConfiguration(); }); it('renders the default log columns with their headers', async () => { + await pageObjects.common.navigateToActualUrl('infraLogs', 'logs/stream'); const columnHeaderLabels = await infraLogStream.getColumnHeaderLabels(); - expect(columnHeaderLabels).to.eql(['Timestamp', 'event.dataset', 'Message', '']); + expect(columnHeaderLabels).to.eql(['Timestamp', 'event.dataset', 'Message']); const logStreamEntries = await infraLogStream.getStreamEntries(); - expect(logStreamEntries.length).to.be.greaterThan(0); const firstLogStreamEntry = logStreamEntries[0]; @@ -90,26 +80,25 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); it('can change the log columns', async () => { - await pageObjects.infraLogs.openSourceConfigurationFlyout(); - await infraSourceConfigurationFlyout.switchToLogsTab(); + await pageObjects.common.navigateToActualUrl('infraLogs', 'logs/settings'); + await infraSourceConfigurationForm.getForm(); - await infraSourceConfigurationFlyout.removeAllLogColumns(); - await infraSourceConfigurationFlyout.addTimestampLogColumn(); - await infraSourceConfigurationFlyout.addFieldLogColumn('host.name'); + await infraSourceConfigurationForm.removeAllLogColumns(); + await infraSourceConfigurationForm.addTimestampLogColumn(); + await infraSourceConfigurationForm.addFieldLogColumn('host.name'); - // TODO: make test more robust - // await infraSourceConfigurationFlyout.moveLogColumn(0, 1); + // await infraSourceConfigurationForm.moveLogColumn(0, 1); - await infraSourceConfigurationFlyout.saveConfiguration(); - await infraSourceConfigurationFlyout.closeFlyout(); + await infraSourceConfigurationForm.saveConfiguration(); }); it('renders the changed log columns with their headers', async () => { + await pageObjects.common.navigateToActualUrl('infraLogs', 'logs/stream'); const columnHeaderLabels = await infraLogStream.getColumnHeaderLabels(); // TODO: make test more robust - // expect(columnHeaderLabels).to.eql(['host.name', 'Timestamp', '']); - expect(columnHeaderLabels).to.eql(['Timestamp', 'host.name', '']); + // expect(columnHeaderLabels).to.eql(['host.name', 'Timestamp']); + expect(columnHeaderLabels).to.eql(['Timestamp', 'host.name']); const logStreamEntries = await infraLogStream.getStreamEntries(); diff --git a/x-pack/test/functional/apps/infra/metrics_source_configuration.ts b/x-pack/test/functional/apps/infra/metrics_source_configuration.ts index 9b22c7ceffb33..8f5c765cec6ad 100644 --- a/x-pack/test/functional/apps/infra/metrics_source_configuration.ts +++ b/x-pack/test/functional/apps/infra/metrics_source_configuration.ts @@ -11,10 +11,10 @@ const DATE_WITH_DATA = DATES.metricsAndLogs.hosts.withData; export default ({ getPageObjects, getService }: FtrProviderContext) => { const esArchiver = getService('esArchiver'); - const infraSourceConfigurationFlyout = getService('infraSourceConfigurationFlyout'); + const infraSourceConfigurationForm = getService('infraSourceConfigurationForm'); const pageObjects = getPageObjects(['common', 'infraHome']); - describe('Infrastructure Snapshot Page', function() { + describe('Infrastructure Source Configuration', function() { this.tags('smoke'); before(async () => { await esArchiver.load('empty_kibana'); @@ -38,38 +38,37 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); it('can change the metric indices to a pattern that matches nothing', async () => { - await pageObjects.infraHome.openSourceConfigurationFlyout(); - await infraSourceConfigurationFlyout.switchToIndicesAndFieldsTab(); + await pageObjects.common.navigateToActualUrl('infraOps', 'infrastructure/settings'); - const nameInput = await infraSourceConfigurationFlyout.getNameInput(); + const nameInput = await infraSourceConfigurationForm.getNameInput(); await nameInput.clearValueWithKeyboard({ charByChar: true }); await nameInput.type('Modified Source'); - const metricIndicesInput = await infraSourceConfigurationFlyout.getMetricIndicesInput(); + const metricIndicesInput = await infraSourceConfigurationForm.getMetricIndicesInput(); await metricIndicesInput.clearValueWithKeyboard({ charByChar: true }); await metricIndicesInput.type('does-not-exist-*'); - await infraSourceConfigurationFlyout.saveConfiguration(); - await infraSourceConfigurationFlyout.closeFlyout(); + await infraSourceConfigurationForm.saveConfiguration(); }); it('renders the no indices screen when no indices match the pattern', async () => { + await pageObjects.common.navigateToApp('infraOps'); await pageObjects.infraHome.getNoMetricsIndicesPrompt(); }); - it('can change the log indices back to a pattern that matches something', async () => { - await pageObjects.infraHome.openSourceConfigurationFlyout(); - await infraSourceConfigurationFlyout.switchToIndicesAndFieldsTab(); + it('can change the metric indices back to a pattern that matches something', async () => { + await pageObjects.common.navigateToActualUrl('infraOps', 'infrastructure/settings'); - const metricIndicesInput = await infraSourceConfigurationFlyout.getMetricIndicesInput(); + const metricIndicesInput = await infraSourceConfigurationForm.getMetricIndicesInput(); await metricIndicesInput.clearValueWithKeyboard({ charByChar: true }); await metricIndicesInput.type('metricbeat-*'); - await infraSourceConfigurationFlyout.saveConfiguration(); - await infraSourceConfigurationFlyout.closeFlyout(); + await infraSourceConfigurationForm.saveConfiguration(); }); - it('renders the log stream again', async () => { + it('renders the waffle map again', async () => { + await pageObjects.common.navigateToApp('infraOps'); + await pageObjects.infraHome.goToTime(DATE_WITH_DATA); await pageObjects.infraHome.getWaffleMap(); }); }); diff --git a/x-pack/test/functional/page_objects/infra_home_page.ts b/x-pack/test/functional/page_objects/infra_home_page.ts index 479468d1f82c6..88501aad57b4a 100644 --- a/x-pack/test/functional/page_objects/infra_home_page.ts +++ b/x-pack/test/functional/page_objects/infra_home_page.ts @@ -10,6 +10,7 @@ import { FtrProviderContext } from '../ftr_provider_context'; export function InfraHomePageProvider({ getService }: FtrProviderContext) { const testSubjects = getService('testSubjects'); + const retry = getService('retry'); const find = getService('find'); const browser = getService('browser'); @@ -23,6 +24,12 @@ export function InfraHomePageProvider({ getService }: FtrProviderContext) { }, async getWaffleMap() { + await retry.try(async () => { + const element = await testSubjects.find('waffleMap'); + if (!element) { + throw new Error(); + } + }); return await testSubjects.find('waffleMap'); }, diff --git a/x-pack/test/functional/page_objects/infra_logs_page.ts b/x-pack/test/functional/page_objects/infra_logs_page.ts index f38740dbb6d13..6eb1349210bae 100644 --- a/x-pack/test/functional/page_objects/infra_logs_page.ts +++ b/x-pack/test/functional/page_objects/infra_logs_page.ts @@ -25,10 +25,5 @@ export function InfraLogsPageProvider({ getPageObjects, getService }: FtrProvide async getNoLogsIndicesPrompt() { return await testSubjects.find('noLogsIndicesPrompt'); }, - - async openSourceConfigurationFlyout() { - await testSubjects.click('configureSourceButton'); - await testSubjects.exists('sourceConfigurationFlyout'); - }, }; } diff --git a/x-pack/test/functional/services/index.ts b/x-pack/test/functional/services/index.ts index aea630241fa74..9a256b3bbb141 100644 --- a/x-pack/test/functional/services/index.ts +++ b/x-pack/test/functional/services/index.ts @@ -44,7 +44,7 @@ import { GrokDebuggerProvider } from './grok_debugger'; // @ts-ignore not ts yet import { UserMenuProvider } from './user_menu'; import { UptimeProvider } from './uptime'; -import { InfraSourceConfigurationFlyoutProvider } from './infra_source_configuration_flyout'; +import { InfraSourceConfigurationFormProvider } from './infra_source_configuration_form'; import { InfraLogStreamProvider } from './infra_log_stream'; import { MachineLearningProvider } from './ml'; @@ -86,7 +86,7 @@ export const services = { spaces: SpacesServiceProvider, userMenu: UserMenuProvider, uptime: UptimeProvider, - infraSourceConfigurationFlyout: InfraSourceConfigurationFlyoutProvider, + infraSourceConfigurationForm: InfraSourceConfigurationFormProvider, infraLogStream: InfraLogStreamProvider, ml: MachineLearningProvider, }; diff --git a/x-pack/test/functional/services/infra_log_stream.ts b/x-pack/test/functional/services/infra_log_stream.ts index 265c4b8d13b3c..d41b0062dcfda 100644 --- a/x-pack/test/functional/services/infra_log_stream.ts +++ b/x-pack/test/functional/services/infra_log_stream.ts @@ -9,6 +9,7 @@ import { WebElementWrapper } from '../../../../test/functional/services/lib/web_ export function InfraLogStreamProvider({ getService }: FtrProviderContext) { const testSubjects = getService('testSubjects'); + const retry = getService('retry'); return { async getColumnHeaderLabels(): Promise { @@ -18,7 +19,14 @@ export function InfraLogStreamProvider({ getService }: FtrProviderContext) { return await Promise.all(columnHeaderElements.map(element => element.getVisibleText())); }, - async getStreamEntries(): Promise { + async getStreamEntries(minimumItems = 1): Promise { + await retry.try(async () => { + const elements = await testSubjects.findAll('streamEntry'); + if (!elements || elements.length < minimumItems) { + throw new Error(); + } + }); + return await testSubjects.findAll('streamEntry'); }, diff --git a/x-pack/test/functional/services/infra_source_configuration_flyout.ts b/x-pack/test/functional/services/infra_source_configuration_form.ts similarity index 66% rename from x-pack/test/functional/services/infra_source_configuration_flyout.ts rename to x-pack/test/functional/services/infra_source_configuration_form.ts index fb77e2dced045..fb4415ed74118 100644 --- a/x-pack/test/functional/services/infra_source_configuration_flyout.ts +++ b/x-pack/test/functional/services/infra_source_configuration_form.ts @@ -7,68 +7,56 @@ import { FtrProviderContext } from '../ftr_provider_context'; import { WebElementWrapper } from '../../../../test/functional/services/lib/web_element_wrapper'; -export function InfraSourceConfigurationFlyoutProvider({ getService }: FtrProviderContext) { - const find = getService('find'); +export function InfraSourceConfigurationFormProvider({ getService }: FtrProviderContext) { const retry = getService('retry'); const testSubjects = getService('testSubjects'); const browser = getService('browser'); return { - /** - * Tab navigation - */ - async switchToIndicesAndFieldsTab() { - await (await find.descendantDisplayedByCssSelector( - '#indicesAndFieldsTab', - await this.getFlyout() - )).click(); - await testSubjects.find('sourceConfigurationNameSectionTitle'); - }, - async switchToLogsTab() { - await (await find.descendantDisplayedByCssSelector( - '#logsTab', - await this.getFlyout() - )).click(); - await testSubjects.find('sourceConfigurationLogColumnsSectionTitle'); - }, - /** * Indices and fields */ async getNameInput(): Promise { - return await testSubjects.findDescendant('nameInput', await this.getFlyout()); + return await testSubjects.findDescendant('nameInput', await this.getForm()); }, async getLogIndicesInput(): Promise { - return await testSubjects.findDescendant('logIndicesInput', await this.getFlyout()); + return await testSubjects.findDescendant('logIndicesInput', await this.getForm()); }, async getMetricIndicesInput(): Promise { - return await testSubjects.findDescendant('metricIndicesInput', await this.getFlyout()); + return await testSubjects.findDescendant('metricIndicesInput', await this.getForm()); }, /** * Logs */ async getAddLogColumnButton(): Promise { - return await testSubjects.findDescendant('addLogColumnButton', await this.getFlyout()); + return await testSubjects.findDescendant('addLogColumnButton', await this.getForm()); }, async getAddLogColumnPopover(): Promise { return await testSubjects.find('addLogColumnPopover'); }, async addTimestampLogColumn() { await (await this.getAddLogColumnButton()).click(); - await (await testSubjects.findDescendant( - 'addTimestampLogColumn', - await this.getAddLogColumnPopover() - )).click(); + await retry.try(async () => { + await (await testSubjects.findDescendant( + 'addTimestampLogColumn', + await this.getAddLogColumnPopover() + )).click(); + }); }, async addFieldLogColumn(fieldName: string) { await (await this.getAddLogColumnButton()).click(); - const popover = await this.getAddLogColumnPopover(); - await (await testSubjects.findDescendant('fieldSearchInput', popover)).type(fieldName); - await (await testSubjects.findDescendant(`addFieldLogColumn:${fieldName}`, popover)).click(); + await retry.try(async () => { + const popover = await this.getAddLogColumnPopover(); + await (await testSubjects.findDescendant('fieldSearchInput', popover)).type(fieldName); + await (await testSubjects.findDescendant( + `addFieldLogColumn:${fieldName}`, + popover + )).click(); + }); }, async getLogColumnPanels(): Promise { - return await testSubjects.findAllDescendant('logColumnPanel', await this.getFlyout()); + return await testSubjects.findAllDescendant('logColumnPanel', await this.getForm()); }, async removeLogColumn(columnIndex: number) { const logColumnPanel = (await this.getLogColumnPanels())[columnIndex]; @@ -104,29 +92,24 @@ export function InfraSourceConfigurationFlyoutProvider({ getService }: FtrProvid }, /** - * Form and flyout + * Form */ - async getFlyout(): Promise { - return await testSubjects.find('sourceConfigurationFlyout'); + async getForm(): Promise { + return await testSubjects.find('sourceConfigurationContent'); }, async saveConfiguration() { await (await testSubjects.findDescendant( - 'updateSourceConfigurationButton', - await this.getFlyout() + 'applySettingsButton', + await this.getForm() )).click(); await retry.try(async () => { const element = await testSubjects.findDescendant( - 'updateSourceConfigurationButton', - await this.getFlyout() + 'applySettingsButton', + await this.getForm() ); return !(await element.isEnabled()); }); }, - async closeFlyout() { - const flyout = await this.getFlyout(); - await (await testSubjects.findDescendant('closeFlyoutButton', flyout)).click(); - await testSubjects.waitForDeleted(flyout); - }, }; }