From cf91dc3d4b44cb9777d3070d004778fb030a9840 Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Fri, 20 Nov 2020 10:49:02 -0800 Subject: [PATCH] [Fleet] Agent logs UI (#83356) * Initial agent log table * Add data and storage services to Kibana context, rename useCore to useStartServices and replace usage of useStartDeps * Initial attempt at adding query bar for log stream * Adjust app layout to allow page content to be full height * Dataset and log level filters, split into smaller files * Use data plugin's `QueryStringInput` component for query bar * Add open in Logs UI link * Clean up unused storage dependency * Remove agent activity log and related dead code * Clean up i18n * Clean up plugin deps, fix routing * Add back storage dependency that data plugin components need * Remove dependency on infra for logs UI link * Change default date range to last one day * Adjust panel padding * Add comment * Move module declarations to top-level x-pack/typings * Fix missed renaming * Remove unused path * Move building of log stream query into separate service with unit tests * Adjust test conditions --- x-pack/plugins/fleet/kibana.json | 2 +- .../fleet/components/search_bar.tsx | 6 +- .../fleet/components/settings_flyout.tsx | 10 +- .../fleet/constants/page_paths.ts | 3 +- .../public/applications/fleet/hooks/index.ts | 3 +- .../fleet/hooks/use_breadcrumbs.tsx | 4 +- .../fleet/hooks/use_capabilities.ts | 4 +- .../applications/fleet/hooks/use_core.ts | 6 +- .../applications/fleet/hooks/use_deps.ts | 29 --- .../fleet/hooks/use_kibana_link.ts | 4 +- .../applications/fleet/hooks/use_link.ts | 4 +- .../fleet/public/applications/fleet/index.tsx | 51 ++-- .../applications/fleet/layouts/default.tsx | 10 +- .../applications/fleet/layouts/index.tsx | 2 +- .../fleet/layouts/with_header.tsx | 14 +- .../fleet/layouts/without_header.tsx | 17 +- .../components/agent_policy_copy_provider.tsx | 4 +- .../agent_policy_delete_provider.tsx | 4 +- .../components/agent_policy_yaml_flyout.tsx | 4 +- .../package_policy_delete_provider.tsx | 4 +- .../create_package_policy_page/index.tsx | 4 +- .../components/settings/index.tsx | 4 +- .../agent_policy/details_page/index.tsx | 4 +- .../edit_package_policy_page/index.tsx | 4 +- .../components/create_agent_policy.tsx | 4 +- .../components/agent_events_table.tsx | 232 ------------------ .../components/agent_logs/build_query.test.ts | 80 ++++++ .../components/agent_logs/build_query.ts | 46 ++++ .../components/agent_logs/constants.tsx | 26 ++ .../components/agent_logs/filter_dataset.tsx | 74 ++++++ .../agent_logs/filter_log_level.tsx | 74 ++++++ .../components/agent_logs/index.tsx | 218 ++++++++++++++++ .../components/agent_logs/query_bar.tsx | 77 ++++++ .../agent_details_page/components/helper.ts | 47 ---- .../agent_details_page/components/index.ts | 2 +- .../components/metadata_flyout.tsx | 78 ------ .../components/metadata_form.tsx | 160 ------------ .../components/type_labels.tsx | 120 --------- .../agents/agent_details_page/index.tsx | 32 +-- .../agent_policy_selection.tsx | 4 +- .../managed_instructions.tsx | 4 +- .../standalone_instructions.tsx | 4 +- .../agent_reassign_policy_flyout/index.tsx | 4 +- .../components/agent_unenroll_modal/index.tsx | 8 +- .../components/agent_upgrade_modal/index.tsx | 8 +- .../components/new_enrollment_key_flyout.tsx | 4 +- .../enrollment_token_list_page/index.tsx | 6 +- .../sections/agents/setup_page/index.tsx | 4 +- .../sections/data_stream/list_page/index.tsx | 4 +- .../sections/epm/components/icon_panel.tsx | 3 +- .../fleet/sections/epm/hooks/use_links.tsx | 4 +- .../sections/epm/screens/detail/index.scss | 5 + .../sections/epm/screens/detail/index.tsx | 64 ++--- .../sections/epm/screens/home/header.tsx | 4 +- .../components/datastream_section.tsx | 4 +- x-pack/plugins/fleet/public/plugin.ts | 29 ++- .../translations/translations/ja-JP.json | 34 --- .../translations/translations/zh-CN.json | 34 --- .../apm => }/typings/cytoscape_dagre.d.ts | 0 .../{plugins/apm => }/typings/react_vis.d.ts | 0 60 files changed, 788 insertions(+), 914 deletions(-) delete mode 100644 x-pack/plugins/fleet/public/applications/fleet/hooks/use_deps.ts delete mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_events_table.tsx create mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/build_query.test.ts create mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/build_query.ts create mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/constants.tsx create mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/filter_dataset.tsx create mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/filter_log_level.tsx create mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/index.tsx create mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/query_bar.tsx delete mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/helper.ts delete mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/metadata_flyout.tsx delete mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/metadata_form.tsx delete mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/type_labels.tsx create mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/index.scss rename x-pack/{plugins/apm => }/typings/cytoscape_dagre.d.ts (100%) rename x-pack/{plugins/apm => }/typings/react_vis.d.ts (100%) diff --git a/x-pack/plugins/fleet/kibana.json b/x-pack/plugins/fleet/kibana.json index 81b56682b47e1..2fcbef75b9832 100644 --- a/x-pack/plugins/fleet/kibana.json +++ b/x-pack/plugins/fleet/kibana.json @@ -7,5 +7,5 @@ "requiredPlugins": ["licensing", "data", "encryptedSavedObjects"], "optionalPlugins": ["security", "features", "cloud", "usageCollection", "home"], "extraPublicDirs": ["common"], - "requiredBundles": ["kibanaReact", "esUiShared", "home"] + "requiredBundles": ["kibanaReact", "esUiShared", "home", "infra", "kibanaUtils"] } diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx index a22e4e14055e3..9ebc8ea9380a9 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx @@ -9,7 +9,7 @@ import { IFieldType } from 'src/plugins/data/public'; // @ts-ignore import { EuiSuggest, EuiSuggestItemProps } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { useDebounce, useStartDeps } from '../hooks'; +import { useDebounce, useStartServices } from '../hooks'; import { INDEX_NAME, AGENT_SAVED_OBJECT_TYPE } from '../constants'; const DEBOUNCE_SEARCH_MS = 150; @@ -80,7 +80,7 @@ export const SearchBar: React.FunctionComponent = ({ ); }; -function transformSuggestionType(type: string): { iconType: string; color: string } { +export function transformSuggestionType(type: string): { iconType: string; color: string } { switch (type) { case 'field': return { iconType: 'kqlField', color: 'tint4' }; @@ -96,7 +96,7 @@ function transformSuggestionType(type: string): { iconType: string; color: strin } function useSuggestions(fieldPrefix: string, search: string) { - const { data } = useStartDeps(); + const { data } = useStartServices(); const debouncedSearch = useDebounce(search, DEBOUNCE_SEARCH_MS); const [suggestions, setSuggestions] = useState([]); diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout.tsx index 80ecaa2493278..639a3e41b39fa 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/components/settings_flyout.tsx @@ -25,7 +25,13 @@ import { import { FormattedMessage } from '@kbn/i18n/react'; import { EuiText } from '@elastic/eui'; import { safeLoad } from 'js-yaml'; -import { useComboInput, useCore, useGetSettings, useInput, sendPutSettings } from '../hooks'; +import { + useComboInput, + useStartServices, + useGetSettings, + useInput, + sendPutSettings, +} from '../hooks'; import { useGetOutputs, sendPutOutput } from '../hooks/use_request/outputs'; import { isDiffPathProtocol } from '../../../../common/'; @@ -37,7 +43,7 @@ interface Props { function useSettingsForm(outputId: string | undefined, onSuccess: () => void) { const [isLoading, setIsloading] = React.useState(false); - const { notifications } = useCore(); + const { notifications } = useStartServices(); const kibanaUrlsInput = useComboInput([], (value) => { if (value.length === 0) { return [ diff --git a/x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts b/x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts index 9963753651671..ecd4227a54b65 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/constants/page_paths.ts @@ -51,8 +51,7 @@ export const PAGE_ROUTING_PATHS = { fleet: '/fleet', fleet_agent_list: '/fleet/agents', fleet_agent_details: '/fleet/agents/:agentId/:tabId?', - fleet_agent_details_events: '/fleet/agents/:agentId', - fleet_agent_details_details: '/fleet/agents/:agentId/details', + fleet_agent_details_logs: '/fleet/agents/:agentId/logs', fleet_enrollment_tokens: '/fleet/enrollment-tokens', data_streams: '/data-streams', }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/index.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/index.ts index 29843f6a3e5b1..6026a5579f65b 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/index.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/index.ts @@ -5,10 +5,9 @@ */ export { useCapabilities } from './use_capabilities'; -export { useCore } from './use_core'; +export { useStartServices } from './use_core'; export { useConfig, ConfigContext } from './use_config'; export { useKibanaVersion, KibanaVersionContext } from './use_kibana_version'; -export { useSetupDeps, useStartDeps, DepsContext } from './use_deps'; export { licenseService, useLicense } from './use_license'; export { useBreadcrumbs } from './use_breadcrumbs'; export { useLink } from './use_link'; diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_breadcrumbs.tsx b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_breadcrumbs.tsx index ed38e1a5ce4a1..40654645ecd3f 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_breadcrumbs.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_breadcrumbs.tsx @@ -6,7 +6,7 @@ import { i18n } from '@kbn/i18n'; import { ChromeBreadcrumb } from 'src/core/public'; import { BASE_PATH, Page, DynamicPagePathValues, pagePathGetters } from '../constants'; -import { useCore } from './use_core'; +import { useStartServices } from './use_core'; const BASE_BREADCRUMB: ChromeBreadcrumb = { href: pagePathGetters.overview(), @@ -204,7 +204,7 @@ const breadcrumbGetters: { }; export function useBreadcrumbs(page: Page, values: DynamicPagePathValues = {}) { - const { chrome, http } = useCore(); + const { chrome, http } = useStartServices(); const breadcrumbs: ChromeBreadcrumb[] = breadcrumbGetters[page](values).map((breadcrumb) => ({ ...breadcrumb, href: breadcrumb.href ? http.basePath.prepend(`${BASE_PATH}#${breadcrumb.href}`) : undefined, diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_capabilities.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_capabilities.ts index d8535183bb84e..da5be82049c8e 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_capabilities.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_capabilities.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { useCore } from './'; +import { useStartServices } from './'; export function useCapabilities() { - const core = useCore(); + const core = useStartServices(); return core.application.capabilities.fleet; } diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_core.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_core.ts index dad2eaa1d8e0f..f425831f6d6bc 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_core.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_core.ts @@ -4,11 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { CoreStart } from 'kibana/public'; +import { FleetStartServices } from '../../../plugin'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; -export function useCore(): CoreStart { - const { services } = useKibana(); +export function useStartServices(): FleetStartServices { + const { services } = useKibana(); if (services === null) { throw new Error('KibanaContextProvider not initialized'); } diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_deps.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_deps.ts deleted file mode 100644 index bf8f33297882e..0000000000000 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_deps.ts +++ /dev/null @@ -1,29 +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, { useContext } from 'react'; -import { FleetSetupDeps, FleetStartDeps } from '../../../plugin'; - -export const DepsContext = React.createContext<{ - setup: FleetSetupDeps; - start: FleetStartDeps; -} | null>(null); - -export function useSetupDeps() { - const deps = useContext(DepsContext); - if (deps === null) { - throw new Error('DepsContext not initialized'); - } - return deps.setup; -} - -export function useStartDeps() { - const deps = useContext(DepsContext); - if (deps === null) { - throw new Error('StartDepsContext not initialized'); - } - return deps.start; -} diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_kibana_link.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_kibana_link.ts index 58537b2075c16..5faa3bfcab4af 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_kibana_link.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_kibana_link.ts @@ -4,11 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { useCore } from './'; +import { useStartServices } from './'; const KIBANA_BASE_PATH = '/app/kibana'; export function useKibanaLink(path: string = '/') { - const core = useCore(); + const core = useStartServices(); return core.http.basePath.prepend(`${KIBANA_BASE_PATH}#${path}`); } diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_link.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_link.ts index 1b17c5cb0b1f3..40c0689905932 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_link.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_link.ts @@ -11,14 +11,14 @@ import { DynamicPagePathValues, pagePathGetters, } from '../constants'; -import { useCore } from './'; +import { useStartServices } from './'; const getPath = (page: StaticPage | DynamicPage, values: DynamicPagePathValues = {}): string => { return values ? pagePathGetters[page](values) : pagePathGetters[page as StaticPage](); }; export const useLink = () => { - const core = useCore(); + const core = useStartServices(); return { getPath, getHref: (page: StaticPage | DynamicPage, values?: DynamicPagePathValues) => { diff --git a/x-pack/plugins/fleet/public/applications/fleet/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/index.tsx index 51c897b3661cc..61a5f1eabc2af 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/index.tsx @@ -14,16 +14,15 @@ import { EuiErrorBoundary, EuiPanel, EuiEmptyPrompt, EuiCode } from '@elastic/eu import { CoreStart, AppMountParameters } from 'src/core/public'; import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; import { EuiThemeProvider } from '../../../../xpack_legacy/common'; -import { FleetSetupDeps, FleetConfigType, FleetStartDeps } from '../../plugin'; +import { FleetConfigType, FleetStartServices } from '../../plugin'; import { PAGE_ROUTING_PATHS } from './constants'; import { DefaultLayout, WithoutHeaderLayout } from './layouts'; import { Loading, Error } from './components'; import { IngestManagerOverview, EPMApp, AgentPolicyApp, FleetApp, DataStreamApp } from './sections'; import { - DepsContext, ConfigContext, useConfig, - useCore, + useStartServices, sendSetup, sendGetPermissionsCheck, licenseService, @@ -67,7 +66,7 @@ const IngestManagerRoutes = memo<{ history: AppMountParameters['history']; basep useBreadcrumbs('base'); const { agents } = useConfig(); - const { notifications } = useCore(); + const { notifications } = useStartServices(); const [isPermissionsLoading, setIsPermissionsLoading] = useState(false); const [permissionsError, setPermissionsError] = useState(); @@ -227,48 +226,40 @@ const IngestManagerRoutes = memo<{ history: AppMountParameters['history']; basep const IngestManagerApp = ({ basepath, - coreStart, - setupDeps, - startDeps, + startServices, config, history, kibanaVersion, extensions, }: { basepath: string; - coreStart: CoreStart; - setupDeps: FleetSetupDeps; - startDeps: FleetStartDeps; + startServices: FleetStartServices; config: FleetConfigType; history: AppMountParameters['history']; kibanaVersion: string; extensions: UIExtensionsStorage; }) => { - const isDarkMode = useObservable(coreStart.uiSettings.get$('theme:darkMode')); + const isDarkMode = useObservable(startServices.uiSettings.get$('theme:darkMode')); return ( - - - - - - - - - - - - - + + + + + + + + + + + - + ); }; export function renderApp( - coreStart: CoreStart, + startServices: FleetStartServices, { element, appBasePath, history }: AppMountParameters, - setupDeps: FleetSetupDeps, - startDeps: FleetStartDeps, config: FleetConfigType, kibanaVersion: string, extensions: UIExtensionsStorage @@ -276,9 +267,7 @@ export function renderApp( ReactDOM.render( props.theme.eui.euiColorEmptyShade}; border-bottom: ${(props) => props.theme.eui.euiBorderThin}; @@ -56,7 +62,7 @@ export const DefaultLayout: React.FunctionComponent = ({ /> )} -
+ {children} -
+
diff --git a/x-pack/plugins/fleet/public/applications/fleet/layouts/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/layouts/index.tsx index 03efe20f96a51..e49ef152f8306 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/layouts/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/layouts/index.tsx @@ -4,5 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ export { DefaultLayout } from './default'; -export { WithHeaderLayout } from './with_header'; +export { WithHeaderLayout, WithHeaderLayoutProps } from './with_header'; export { WithoutHeaderLayout } from './without_header'; diff --git a/x-pack/plugins/fleet/public/applications/fleet/layouts/with_header.tsx b/x-pack/plugins/fleet/public/applications/fleet/layouts/with_header.tsx index 4b21a15a73645..bca0e2889483f 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/layouts/with_header.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/layouts/with_header.tsx @@ -4,13 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ import React, { Fragment } from 'react'; -import styled from 'styled-components'; -import { EuiPage, EuiPageBody, EuiSpacer } from '@elastic/eui'; +import { EuiPageBody, EuiSpacer } from '@elastic/eui'; import { Header, HeaderProps } from '../components'; - -const Page = styled(EuiPage)` - background: ${(props) => props.theme.eui.euiColorEmptyShade}; -`; +import { Page, ContentWrapper } from './without_header'; export interface WithHeaderLayoutProps extends HeaderProps { restrictWidth?: number; @@ -37,8 +33,10 @@ export const WithHeaderLayout: React.FC = ({ data-test-subj={dataTestSubj ? `${dataTestSubj}_page` : undefined} > - - {children} + + + {children} + diff --git a/x-pack/plugins/fleet/public/applications/fleet/layouts/without_header.tsx b/x-pack/plugins/fleet/public/applications/fleet/layouts/without_header.tsx index 08f6244242a3d..93ad997780015 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/layouts/without_header.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/layouts/without_header.tsx @@ -7,8 +7,17 @@ import React, { Fragment } from 'react'; import styled from 'styled-components'; import { EuiPage, EuiPageBody, EuiSpacer } from '@elastic/eui'; -const Page = styled(EuiPage)` +export const Page = styled(EuiPage)` background: ${(props) => props.theme.eui.euiColorEmptyShade}; + width: 100%; + align-self: center; + margin-left: 0; + margin-right: 0; + flex: 1; +`; + +export const ContentWrapper = styled.div` + height: 100%; `; interface Props { @@ -20,8 +29,10 @@ export const WithoutHeaderLayout: React.FC = ({ restrictWidth, children } - - {children} + + + {children} + diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_copy_provider.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_copy_provider.tsx index 41201f9612f13..9e2a7ae8f8f47 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_copy_provider.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_copy_provider.tsx @@ -9,7 +9,7 @@ import { EuiConfirmModal, EuiOverlayMask, EuiFormRow, EuiFieldText } from '@elas import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { AgentPolicy } from '../../../types'; -import { sendCopyAgentPolicy, useCore } from '../../../hooks'; +import { sendCopyAgentPolicy, useStartServices } from '../../../hooks'; interface Props { children: (copyAgentPolicy: CopyAgentPolicy) => React.ReactElement; @@ -20,7 +20,7 @@ export type CopyAgentPolicy = (agentPolicy: AgentPolicy, onSuccess?: OnSuccessCa type OnSuccessCallback = (newAgentPolicy: AgentPolicy) => void; export const AgentPolicyCopyProvider: React.FunctionComponent = ({ children }) => { - const { notifications } = useCore(); + const { notifications } = useStartServices(); const [agentPolicy, setAgentPolicy] = useState(); const [newAgentPolicy, setNewAgentPolicy] = useState>(); const [isModalOpen, setIsModalOpen] = useState(false); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx index 41704f69958a0..7afb028dded2a 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_delete_provider.tsx @@ -9,7 +9,7 @@ import { EuiConfirmModal, EuiOverlayMask, EuiCallOut } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { AGENT_SAVED_OBJECT_TYPE } from '../../../constants'; -import { sendDeleteAgentPolicy, useCore, useConfig, sendRequest } from '../../../hooks'; +import { sendDeleteAgentPolicy, useStartServices, useConfig, sendRequest } from '../../../hooks'; interface Props { children: (deleteAgentPolicy: DeleteAgentPolicy) => React.ReactElement; @@ -20,7 +20,7 @@ export type DeleteAgentPolicy = (agentPolicy: string, onSuccess?: OnSuccessCallb type OnSuccessCallback = (agentPolicyDeleted: string) => void; export const AgentPolicyDeleteProvider: React.FunctionComponent = ({ children }) => { - const { notifications } = useCore(); + const { notifications } = useStartServices(); const { agents: { enabled: isFleetEnabled }, } = useConfig(); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_yaml_flyout.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_yaml_flyout.tsx index 773d53484147a..7b0075e160c47 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_yaml_flyout.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_yaml_flyout.tsx @@ -20,7 +20,7 @@ import { EuiButton, EuiCallOut, } from '@elastic/eui'; -import { useGetOneAgentPolicyFull, useGetOneAgentPolicy, useCore } from '../../../hooks'; +import { useGetOneAgentPolicyFull, useGetOneAgentPolicy, useStartServices } from '../../../hooks'; import { Loading } from '../../../components'; import { fullAgentPolicyToYaml, agentPolicyRouteService } from '../../../services'; @@ -32,7 +32,7 @@ const FlyoutBody = styled(EuiFlyoutBody)` export const AgentPolicyYamlFlyout = memo<{ policyId: string; onClose: () => void }>( ({ policyId, onClose }) => { - const core = useCore(); + const core = useStartServices(); const { isLoading: isLoadingYaml, data: yamlData, error } = useGetOneAgentPolicyFull(policyId); const { data: agentPolicyData } = useGetOneAgentPolicy(policyId); const body = isLoadingYaml ? ( diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/package_policy_delete_provider.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/package_policy_delete_provider.tsx index 8de40edc40331..e86ac9e3bd03c 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/package_policy_delete_provider.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/package_policy_delete_provider.tsx @@ -8,7 +8,7 @@ import React, { Fragment, useMemo, useRef, useState } from 'react'; import { EuiCallOut, EuiConfirmModal, EuiOverlayMask, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { useCore, sendRequest, sendDeletePackagePolicy, useConfig } from '../../../hooks'; +import { useStartServices, sendRequest, sendDeletePackagePolicy, useConfig } from '../../../hooks'; import { AGENT_API_ROUTES, AGENT_SAVED_OBJECT_TYPE } from '../../../constants'; import { AgentPolicy } from '../../../types'; @@ -28,7 +28,7 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent = ({ agentPolicy, children, }) => { - const { notifications } = useCore(); + const { notifications } = useStartServices(); const { agents: { enabled: isFleetEnabled }, } = useConfig(); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/index.tsx index a837ed33e4110..62792b84105ab 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/index.tsx @@ -28,7 +28,7 @@ import { useLink, useBreadcrumbs, sendCreatePackagePolicy, - useCore, + useStartServices, useConfig, sendGetAgentStatus, } from '../../../hooks'; @@ -60,7 +60,7 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { const { notifications, application: { navigateToApp }, - } = useCore(); + } = useStartServices(); const { agents: { enabled: isFleetEnabled }, } = useConfig(); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/settings/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/settings/index.tsx index fe3955c84dec3..b33976d53fe95 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/settings/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/settings/index.tsx @@ -12,7 +12,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { AgentPolicy } from '../../../../../types'; import { useLink, - useCore, + useStartServices, useCapabilities, sendUpdateAgentPolicy, useConfig, @@ -33,7 +33,7 @@ const FormWrapper = styled.div` export const SettingsView = memo<{ agentPolicy: AgentPolicy }>( ({ agentPolicy: originalAgentPolicy }) => { - const { notifications } = useCore(); + const { notifications } = useStartServices(); const { agents: { enabled: isFleetEnabled }, } = useConfig(); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/index.tsx index 7528c923f0abd..0099fb3c84d12 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/index.tsx @@ -26,7 +26,7 @@ import { useGetOneAgentPolicy, useLink, useBreadcrumbs, - useCore, + useStartServices, useFleetStatus, } from '../../../hooks'; import { Loading, Error } from '../../../components'; @@ -56,7 +56,7 @@ export const AgentPolicyDetailsPage: React.FunctionComponent = () => { const { refreshAgentStatus } = agentStatusRequest; const { application: { navigateToApp }, - } = useCore(); + } = useStartServices(); const routeState = useIntraAppState(); const agentStatus = agentStatusRequest.data?.results; const queryParams = new URLSearchParams(useLocation().search); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx index bfc10848d378f..c0db51873e52e 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx @@ -19,7 +19,7 @@ import { AgentPolicy, PackageInfo, UpdatePackagePolicy } from '../../../types'; import { useLink, useBreadcrumbs, - useCore, + useStartServices, useConfig, sendUpdatePackagePolicy, sendGetAgentStatus, @@ -47,7 +47,7 @@ import { GetOnePackagePolicyResponse } from '../../../../../../common/types/rest import { PackagePolicyEditExtensionComponentProps } from '../../../types'; export const EditPackagePolicyPage: React.FunctionComponent = () => { - const { notifications } = useCore(); + const { notifications } = useStartServices(); const { agents: { enabled: isFleetEnabled }, } = useConfig(); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/components/create_agent_policy.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/components/create_agent_policy.tsx index f10f36174fe82..364df44a59e18 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/components/create_agent_policy.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/components/create_agent_policy.tsx @@ -23,7 +23,7 @@ import { } from '@elastic/eui'; import { dataTypes } from '../../../../../../../common'; import { NewAgentPolicy, AgentPolicy } from '../../../../types'; -import { useCapabilities, useCore, sendCreateAgentPolicy } from '../../../../hooks'; +import { useCapabilities, useStartServices, sendCreateAgentPolicy } from '../../../../hooks'; import { AgentPolicyForm, agentPolicyFormValidation } from '../../components'; const FlyoutWithHigherZIndex = styled(EuiFlyout)` @@ -38,7 +38,7 @@ export const CreateAgentPolicyFlyout: React.FunctionComponent = ({ onClose, ...restOfProps }) => { - const { notifications } = useCore(); + const { notifications } = useStartServices(); const hasWriteCapabilites = useCapabilities().write; const [agentPolicy, setAgentPolicy] = useState({ name: '', diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_events_table.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_events_table.tsx deleted file mode 100644 index c1a1b3862728d..0000000000000 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_events_table.tsx +++ /dev/null @@ -1,232 +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, { useState } from 'react'; -import { - EuiBasicTable, - // @ts-ignore - EuiSuggest, - EuiFlexGroup, - EuiButton, - EuiSpacer, - EuiFlexItem, - EuiBadge, - EuiText, - EuiButtonIcon, - EuiCodeBlock, -} from '@elastic/eui'; -import { RIGHT_ALIGNMENT } from '@elastic/eui/lib/services'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage, FormattedTime } from '@kbn/i18n/react'; -import { AGENT_EVENT_SAVED_OBJECT_TYPE } from '../../../../constants'; -import { Agent, AgentEvent } from '../../../../types'; -import { usePagination, useGetOneAgentEvents } from '../../../../hooks'; -import { SearchBar } from '../../../../components/search_bar'; -import { TYPE_LABEL, SUBTYPE_LABEL } from './type_labels'; - -function useSearch() { - const [state, setState] = useState<{ search: string }>({ - search: '', - }); - - const setSearch = (s: string) => - setState({ - search: s, - }); - - return { - ...state, - setSearch, - }; -} - -export const AgentEventsTable: React.FunctionComponent<{ agent: Agent }> = ({ agent }) => { - const { pageSizeOptions, pagination, setPagination } = usePagination(); - const { search, setSearch } = useSearch(); - const [itemIdToExpandedRowMap, setItemIdToExpandedRowMap] = useState<{ - [key: string]: JSX.Element; - }>({}); - - const { isLoading, data, resendRequest } = useGetOneAgentEvents(agent.id, { - page: pagination.currentPage, - perPage: pagination.pageSize, - kuery: search && search.trim() !== '' ? search.trim() : undefined, - }); - - const refresh = () => resendRequest(); - - const total = data ? data.total : 0; - const list = data ? data.list : []; - const paginationOptions = { - pageIndex: pagination.currentPage - 1, - pageSize: pagination.pageSize, - totalItemCount: total, - pageSizeOptions, - }; - - const toggleDetails = (agentEvent: AgentEvent) => { - const itemIdToExpandedRowMapValues = { ...itemIdToExpandedRowMap }; - if (itemIdToExpandedRowMapValues[agentEvent.id]) { - delete itemIdToExpandedRowMapValues[agentEvent.id]; - } else { - const details = ( -
-
- - - - - -

{agentEvent.message}

-
-
- {agentEvent.payload ? ( -
- - - - - - - - - {JSON.stringify(agentEvent.payload, null, 2)} - -
- ) : null} -
- ); - itemIdToExpandedRowMapValues[agentEvent.id] = details; - } - setItemIdToExpandedRowMap(itemIdToExpandedRowMapValues); - }; - - const columns = [ - { - field: 'timestamp', - name: i18n.translate('xpack.fleet.agentEventsList.timestampColumnTitle', { - defaultMessage: 'Timestamp', - }), - render: (timestamp: string) => ( - - ), - sortable: true, - width: '18%', - }, - { - field: 'type', - name: i18n.translate('xpack.fleet.agentEventsList.typeColumnTitle', { - defaultMessage: 'Type', - }), - width: '10%', - render: (type: AgentEvent['type']) => - TYPE_LABEL[type] || {type}, - }, - { - field: 'subtype', - name: i18n.translate('xpack.fleet.agentEventsList.subtypeColumnTitle', { - defaultMessage: 'Subtype', - }), - width: '13%', - render: (subtype: AgentEvent['subtype']) => - SUBTYPE_LABEL[subtype] || {subtype}, - }, - { - field: 'message', - name: i18n.translate('xpack.fleet.agentEventsList.messageColumnTitle', { - defaultMessage: 'Message', - }), - render: (value: string) => ( - - {value} - - ), - }, - { - align: RIGHT_ALIGNMENT, - width: '40px', - isExpander: true, - render: (agentEvent: AgentEvent) => ( - toggleDetails(agentEvent)} - aria-label={ - itemIdToExpandedRowMap[agentEvent.id] - ? i18n.translate('xpack.fleet.agentEventsList.collapseDetailsAriaLabel', { - defaultMessage: 'Hide details', - }) - : i18n.translate('xpack.fleet.agentEventsList.expandDetailsAriaLabel', { - defaultMessage: 'Show details', - }) - } - iconType={itemIdToExpandedRowMap[agentEvent.id] ? 'arrowUp' : 'arrowDown'} - /> - ), - }, - ]; - - const onClickRefresh = () => { - refresh(); - }; - - const onChange = ({ page }: { page: { index: number; size: number } }) => { - const newPagination = { - ...pagination, - currentPage: page.index + 1, - pageSize: page.size, - }; - - setPagination(newPagination); - }; - - return ( - <> - - - - - - - - - - - - - onChange={onChange} - items={list} - itemId="id" - columns={columns} - pagination={paginationOptions} - loading={isLoading} - itemIdToExpandedRowMap={itemIdToExpandedRowMap} - /> - - ); -}; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/build_query.test.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/build_query.test.ts new file mode 100644 index 0000000000000..610c2feacf99e --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/build_query.test.ts @@ -0,0 +1,80 @@ +/* + * 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 { buildQuery } from './build_query'; + +describe('Fleet - buildQuery', () => { + it('should work', () => { + expect( + buildQuery({ agentId: 'some-agent-id', datasets: [], logLevels: [], userQuery: '' }) + ).toEqual( + 'elastic_agent.id:some-agent-id and (data_stream.dataset:elastic_agent or data_stream.dataset:elastic_agent.*)' + ); + + expect( + buildQuery({ + agentId: 'some-agent-id', + datasets: ['elastic_agent'], + logLevels: [], + userQuery: '', + }) + ).toEqual('elastic_agent.id:some-agent-id and (data_stream.dataset:elastic_agent)'); + + expect( + buildQuery({ + agentId: 'some-agent-id', + datasets: ['elastic_agent', 'elastic_agent.filebeat'], + logLevels: ['error'], + userQuery: '', + }) + ).toEqual( + 'elastic_agent.id:some-agent-id and (data_stream.dataset:elastic_agent or data_stream.dataset:elastic_agent.filebeat) and (log.level:error)' + ); + + expect( + buildQuery({ + agentId: 'some-agent-id', + datasets: [], + logLevels: ['error', 'info', 'warn'], + userQuery: '', + }) + ).toEqual( + 'elastic_agent.id:some-agent-id and (data_stream.dataset:elastic_agent or data_stream.dataset:elastic_agent.*) and (log.level:error or log.level:info or log.level:warn)' + ); + + expect( + buildQuery({ + agentId: 'some-agent-id', + datasets: ['elastic_agent'], + logLevels: ['error', 'info', 'warn'], + userQuery: 'FLEET_GATEWAY and input.type:*', + }) + ).toEqual( + '(elastic_agent.id:some-agent-id and (data_stream.dataset:elastic_agent) and (log.level:error or log.level:info or log.level:warn)) and (FLEET_GATEWAY and input.type:*)' + ); + + expect( + buildQuery({ + agentId: 'some-agent-id', + datasets: [], + logLevels: [], + userQuery: 'FLEET_GATEWAY and input.type:*', + }) + ).toEqual( + '(elastic_agent.id:some-agent-id and (data_stream.dataset:elastic_agent or data_stream.dataset:elastic_agent.*)) and (FLEET_GATEWAY and input.type:*)' + ); + + expect( + buildQuery({ + agentId: 'some-agent-id', + datasets: [], + logLevels: ['error'], + userQuery: 'FLEET_GATEWAY and input.type:*', + }) + ).toEqual( + '(elastic_agent.id:some-agent-id and (data_stream.dataset:elastic_agent or data_stream.dataset:elastic_agent.*) and (log.level:error)) and (FLEET_GATEWAY and input.type:*)' + ); + }); +}); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/build_query.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/build_query.ts new file mode 100644 index 0000000000000..39d383cad503d --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/build_query.ts @@ -0,0 +1,46 @@ +/* + * 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 { + DATASET_FIELD, + AGENT_DATASET, + AGENT_DATASET_PATTERN, + LOG_LEVEL_FIELD, + AGENT_ID_FIELD, +} from './constants'; + +export const buildQuery = ({ + agentId, + datasets, + logLevels, + userQuery, +}: { + agentId: string; + datasets: string[]; + logLevels: string[]; + userQuery: string; +}): string => { + // Filter on agent ID + const agentIdQuery = `${AGENT_ID_FIELD.name}:${agentId}`; + + // Filter on selected datasets if given, fall back to filtering on dataset: elastic_agent|elastic_agent.* + const datasetQuery = datasets.length + ? datasets.map((dataset) => `${DATASET_FIELD.name}:${dataset}`).join(' or ') + : `${DATASET_FIELD.name}:${AGENT_DATASET} or ${DATASET_FIELD.name}:${AGENT_DATASET_PATTERN}`; + + // Filter on log levels + const logLevelQuery = logLevels.map((level) => `${LOG_LEVEL_FIELD.name}:${level}`).join(' or '); + + // Agent ID + datasets query + const agentQuery = `${agentIdQuery} and (${datasetQuery})`; + + // Agent ID + datasets + log levels query + const baseQuery = logLevelQuery ? `${agentQuery} and (${logLevelQuery})` : agentQuery; + + // Agent ID + datasets + log levels + user input query + const finalQuery = userQuery ? `(${baseQuery}) and (${userQuery})` : baseQuery; + + return finalQuery; +}; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/constants.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/constants.tsx new file mode 100644 index 0000000000000..b56e27356ef34 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/constants.tsx @@ -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; + * you may not use this file except in compliance with the Elastic License. + */ +export const AGENT_LOG_INDEX_PATTERN = 'logs-elastic_agent-*,logs-elastic_agent.*-*'; +export const AGENT_DATASET = 'elastic_agent'; +export const AGENT_DATASET_PATTERN = 'elastic_agent.*'; +export const AGENT_ID_FIELD = { + name: 'elastic_agent.id', + type: 'string', +}; +export const DATASET_FIELD = { + name: 'data_stream.dataset', + type: 'string', + aggregatable: true, +}; +export const LOG_LEVEL_FIELD = { + name: 'log.level', + type: 'string', + aggregatable: true, +}; +export const DEFAULT_DATE_RANGE = { + start: 'now-1d', + end: 'now', +}; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/filter_dataset.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/filter_dataset.tsx new file mode 100644 index 0000000000000..bc3cfd84d2379 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/filter_dataset.tsx @@ -0,0 +1,74 @@ +/* + * 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, { memo, useState, useEffect } from 'react'; +import { EuiPopover, EuiFilterButton, EuiFilterSelectItem } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { useStartServices } from '../../../../../hooks'; +import { AGENT_LOG_INDEX_PATTERN, DATASET_FIELD, AGENT_DATASET } from './constants'; + +export const DatasetFilter: React.FunctionComponent<{ + selectedDatasets: string[]; + onToggleDataset: (dataset: string) => void; +}> = memo(({ selectedDatasets, onToggleDataset }) => { + const { data } = useStartServices(); + const [isOpen, setIsOpen] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const [datasetValues, setDatasetValues] = useState([AGENT_DATASET]); + + useEffect(() => { + const fetchValues = async () => { + setIsLoading(true); + try { + const values = await data.autocomplete.getValueSuggestions({ + indexPattern: { + title: AGENT_LOG_INDEX_PATTERN, + fields: [DATASET_FIELD], + }, + field: DATASET_FIELD, + query: '', + }); + setDatasetValues(values.sort()); + } catch (e) { + setDatasetValues([AGENT_DATASET]); + } + setIsLoading(false); + }; + fetchValues(); + }, [data.autocomplete]); + + return ( + setIsOpen(true)} + isSelected={isOpen} + isLoading={isLoading} + numFilters={datasetValues.length} + hasActiveFilters={selectedDatasets.length > 0} + numActiveFilters={selectedDatasets.length} + > + {i18n.translate('xpack.fleet.agentLogs.datasetSelectText', { + defaultMessage: 'Dataset', + })} + + } + isOpen={isOpen} + closePopover={() => setIsOpen(false)} + panelPaddingSize="none" + > + {datasetValues.map((dataset) => ( + onToggleDataset(dataset)} + > + {dataset} + + ))} + + ); +}); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/filter_log_level.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/filter_log_level.tsx new file mode 100644 index 0000000000000..b034168dc8a15 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/filter_log_level.tsx @@ -0,0 +1,74 @@ +/* + * 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, { memo, useState, useEffect } from 'react'; +import { EuiPopover, EuiFilterButton, EuiFilterSelectItem } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { useStartServices } from '../../../../../hooks'; +import { AGENT_LOG_INDEX_PATTERN, LOG_LEVEL_FIELD } from './constants'; + +export const LogLevelFilter: React.FunctionComponent<{ + selectedLevels: string[]; + onToggleLevel: (level: string) => void; +}> = memo(({ selectedLevels, onToggleLevel }) => { + const { data } = useStartServices(); + const [isOpen, setIsOpen] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const [levelValues, setLevelValues] = useState([]); + + useEffect(() => { + const fetchValues = async () => { + setIsLoading(true); + try { + const values = await data.autocomplete.getValueSuggestions({ + indexPattern: { + title: AGENT_LOG_INDEX_PATTERN, + fields: [LOG_LEVEL_FIELD], + }, + field: LOG_LEVEL_FIELD, + query: '', + }); + setLevelValues(values.sort()); + } catch (e) { + setLevelValues([]); + } + setIsLoading(false); + }; + fetchValues(); + }, [data.autocomplete]); + + return ( + setIsOpen(true)} + isSelected={isOpen} + isLoading={isLoading} + numFilters={levelValues.length} + hasActiveFilters={selectedLevels.length > 0} + numActiveFilters={selectedLevels.length} + > + {i18n.translate('xpack.fleet.agentLogs.logLevelSelectText', { + defaultMessage: 'Log level', + })} + + } + isOpen={isOpen} + closePopover={() => setIsOpen(false)} + panelPaddingSize="none" + > + {levelValues.map((level) => ( + onToggleLevel(level)} + > + {level} + + ))} + + ); +}); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/index.tsx new file mode 100644 index 0000000000000..e033781a850a0 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/index.tsx @@ -0,0 +1,218 @@ +/* + * 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, { memo, useMemo, useState, useCallback } from 'react'; +import styled from 'styled-components'; +import url from 'url'; +import { encode } from 'rison-node'; +import { stringify } from 'query-string'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiSuperDatePicker, + EuiFilterGroup, + EuiPanel, + EuiButtonEmpty, +} from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { RedirectAppLinks } from '../../../../../../../../../../../src/plugins/kibana_react/public'; +import { TimeRange, esKuery } from '../../../../../../../../../../../src/plugins/data/public'; +import { LogStream } from '../../../../../../../../../infra/public'; +import { Agent } from '../../../../../types'; +import { useStartServices } from '../../../../../hooks'; +import { AGENT_DATASET, DEFAULT_DATE_RANGE } from './constants'; +import { DatasetFilter } from './filter_dataset'; +import { LogLevelFilter } from './filter_log_level'; +import { LogQueryBar } from './query_bar'; +import { buildQuery } from './build_query'; + +const WrapperFlexGroup = styled(EuiFlexGroup)` + height: 100%; +`; + +const DatePickerFlexItem = styled(EuiFlexItem)` + max-width: 312px; +`; + +export const AgentLogs: React.FunctionComponent<{ agent: Agent }> = memo(({ agent }) => { + const { data, application, http } = useStartServices(); + + // Util to convert date expressions (returned by datepicker) to timestamps (used by LogStream) + const getDateRangeTimestamps = useCallback( + (timeRange: TimeRange) => { + const { min, max } = data.query.timefilter.timefilter.calculateBounds(timeRange); + return min && max + ? { + startTimestamp: min.valueOf(), + endTimestamp: max.valueOf(), + } + : undefined; + }, + [data.query.timefilter.timefilter] + ); + + // Initial time range filter + const [dateRange, setDateRange] = useState<{ + startExpression: string; + endExpression: string; + startTimestamp: number; + endTimestamp: number; + }>({ + startExpression: DEFAULT_DATE_RANGE.start, + endExpression: DEFAULT_DATE_RANGE.end, + ...getDateRangeTimestamps({ from: DEFAULT_DATE_RANGE.start, to: DEFAULT_DATE_RANGE.end })!, + }); + + const tryUpdateDateRange = useCallback( + (timeRange: TimeRange) => { + const timestamps = getDateRangeTimestamps(timeRange); + if (timestamps) { + setDateRange({ + startExpression: timeRange.from, + endExpression: timeRange.to, + ...timestamps, + }); + } + }, + [getDateRangeTimestamps] + ); + + // Filters + const [selectedLogLevels, setSelectedLogLevels] = useState([]); + const [selectedDatasets, setSelectedDatasets] = useState([AGENT_DATASET]); + + // User query state + const [query, setQuery] = useState(''); + const [draftQuery, setDraftQuery] = useState(''); + const [isDraftQueryValid, setIsDraftQueryValid] = useState(true); + const onUpdateDraftQuery = useCallback((newDraftQuery: string, runQuery?: boolean) => { + setDraftQuery(newDraftQuery); + try { + esKuery.fromKueryExpression(newDraftQuery); + setIsDraftQueryValid(true); + if (runQuery) { + setQuery(newDraftQuery); + } + } catch (err) { + setIsDraftQueryValid(false); + } + }, []); + + // Build final log stream query from agent id, datasets, log levels, and user input + const logStreamQuery = useMemo( + () => + buildQuery({ + agentId: agent.id, + datasets: selectedDatasets, + logLevels: selectedLogLevels, + userQuery: query, + }), + [agent.id, query, selectedDatasets, selectedLogLevels] + ); + + // Generate URL to pass page state to Logs UI + const viewInLogsUrl = useMemo( + () => + http.basePath.prepend( + url.format({ + pathname: '/app/logs/stream', + search: stringify( + { + logPosition: encode({ + start: dateRange.startExpression, + end: dateRange.endExpression, + streamLive: false, + }), + logFilter: encode({ + expression: logStreamQuery, + kind: 'kuery', + }), + }, + { sort: false, encode: false } + ), + }) + ), + [logStreamQuery, dateRange.endExpression, dateRange.startExpression, http.basePath] + ); + + return ( + + + + + + + + + { + const currentLevels = [...selectedDatasets]; + const levelPosition = currentLevels.indexOf(level); + if (levelPosition >= 0) { + currentLevels.splice(levelPosition, 1); + setSelectedDatasets(currentLevels); + } else { + setSelectedDatasets([...selectedDatasets, level]); + } + }} + /> + { + const currentLevels = [...selectedLogLevels]; + const levelPosition = currentLevels.indexOf(level); + if (levelPosition >= 0) { + currentLevels.splice(levelPosition, 1); + setSelectedLogLevels(currentLevels); + } else { + setSelectedLogLevels([...selectedLogLevels, level]); + } + }} + /> + + + + { + tryUpdateDateRange({ + from: start, + to: end, + }); + }} + /> + + + + + + + + + + + + + + + + + ); +}); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/query_bar.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/query_bar.tsx new file mode 100644 index 0000000000000..ae2385d714219 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/query_bar.tsx @@ -0,0 +1,77 @@ +/* + * 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, { memo, useState, useEffect } from 'react'; +import { i18n } from '@kbn/i18n'; +import { + QueryStringInput, + IFieldType, +} from '../../../../../../../../../../../src/plugins/data/public'; +import { useStartServices } from '../../../../../hooks'; +import { + AGENT_LOG_INDEX_PATTERN, + AGENT_ID_FIELD, + DATASET_FIELD, + LOG_LEVEL_FIELD, +} from './constants'; + +const EXCLUDED_FIELDS = [AGENT_ID_FIELD.name, DATASET_FIELD.name, LOG_LEVEL_FIELD.name]; + +export const LogQueryBar: React.FunctionComponent<{ + query: string; + isQueryValid: boolean; + onUpdateQuery: (query: string, runQuery?: boolean) => void; +}> = memo(({ query, isQueryValid, onUpdateQuery }) => { + const { data } = useStartServices(); + const [indexPatternFields, setIndexPatternFields] = useState(); + + useEffect(() => { + const fetchFields = async () => { + try { + const fields = ( + ((await data.indexPatterns.getFieldsForWildcard({ + pattern: AGENT_LOG_INDEX_PATTERN, + })) as IFieldType[]) || [] + ).filter((field) => { + return !EXCLUDED_FIELDS.includes(field.name); + }); + setIndexPatternFields(fields); + } catch (err) { + setIndexPatternFields(undefined); + } + }; + fetchFields(); + }, [data.indexPatterns]); + + return ( + { + onUpdateQuery(newQuery.query as string); + }} + onSubmit={(newQuery) => { + onUpdateQuery(newQuery.query as string, true); + }} + /> + ); +}); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/helper.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/helper.ts deleted file mode 100644 index b512ca230080d..0000000000000 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/helper.ts +++ /dev/null @@ -1,47 +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 { AgentMetadata } from '../../../../types'; - -export function flattenMetadata(metadata: AgentMetadata) { - return Object.entries(metadata).reduce((acc, [key, value]) => { - if (typeof value === 'string') { - acc[key] = value; - - return acc; - } - - Object.entries(flattenMetadata(value)).forEach(([flattenedKey, flattenedValue]) => { - acc[`${key}.${flattenedKey}`] = flattenedValue; - }); - - return acc; - }, {} as { [k: string]: string }); -} -export function unflattenMetadata(flattened: { [k: string]: string }) { - const metadata: AgentMetadata = {}; - - Object.entries(flattened).forEach(([flattenedKey, flattenedValue]) => { - const keyParts = flattenedKey.split('.'); - const lastKey = keyParts.pop(); - - if (!lastKey) { - throw new Error('Invalid metadata'); - } - - let metadataPart = metadata; - keyParts.forEach((keyPart) => { - if (!metadataPart[keyPart]) { - metadataPart[keyPart] = {}; - } - - metadataPart = metadataPart[keyPart] as AgentMetadata; - }); - metadataPart[lastKey] = flattenedValue; - }); - - return metadata; -} diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/index.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/index.ts index 8e6ddd0959358..128f803bb2f2e 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/index.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/index.ts @@ -3,6 +3,6 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -export { AgentEventsTable } from './agent_events_table'; +export { AgentLogs } from './agent_logs'; export { AgentDetailsActionMenu } from './actions_menu'; export { AgentDetailsContent } from './agent_details'; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/metadata_flyout.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/metadata_flyout.tsx deleted file mode 100644 index f808f4ade107b..0000000000000 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/metadata_flyout.tsx +++ /dev/null @@ -1,78 +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 { FormattedMessage } from '@kbn/i18n/react'; -import { - EuiTitle, - EuiSpacer, - EuiDescriptionList, - EuiFlyout, - EuiFlyoutHeader, - EuiFlyoutBody, - EuiHorizontalRule, -} from '@elastic/eui'; -import { MetadataForm } from './metadata_form'; -import { Agent } from '../../../../types'; -import { flattenMetadata } from './helper'; - -interface Props { - agent: Agent; - flyout: { hide: () => void }; -} - -export const AgentMetadataFlyout: React.FunctionComponent = ({ agent, flyout }) => { - const mapMetadata = (obj: { [key: string]: string } | undefined) => { - return Object.keys(obj || {}).map((key) => ({ - title: key, - description: obj ? obj[key] : '', - })); - }; - - const localItems = mapMetadata(flattenMetadata(agent.local_metadata)); - const userProvidedItems = mapMetadata(flattenMetadata(agent.user_provided_metadata)); - - return ( - flyout.hide()} size="s" aria-labelledby="flyoutTitle"> - - -

- -

-
-
- - -

- -

-
- - - - -

- -

-
- - - - - -
-
- ); -}; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/metadata_form.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/metadata_form.tsx deleted file mode 100644 index fd8de709c172a..0000000000000 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/metadata_form.tsx +++ /dev/null @@ -1,160 +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, { useState } from 'react'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { - EuiButtonEmpty, - EuiPopover, - EuiFormRow, - EuiButton, - EuiFlexItem, - EuiFieldText, - EuiFlexGroup, - EuiForm, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { AxiosError } from 'axios'; -import { useAgentRefresh } from '../hooks'; -import { useInput, sendRequest } from '../../../../hooks'; -import { Agent } from '../../../../types'; -import { agentRouteService } from '../../../../services'; -import { flattenMetadata, unflattenMetadata } from './helper'; - -function useAddMetadataForm(agent: Agent, done: () => void) { - const refreshAgent = useAgentRefresh(); - const keyInput = useInput(); - const valueInput = useInput(); - const [state, setState] = useState<{ - isLoading: boolean; - error: null | string; - }>({ - isLoading: false, - error: null, - }); - - function clearInputs() { - keyInput.clear(); - valueInput.clear(); - } - - function setError(error: AxiosError) { - setState({ - isLoading: false, - error: error.response && error.response.data ? error.response.data.message : error.message, - }); - } - - async function success() { - await refreshAgent(); - setState({ - isLoading: false, - error: null, - }); - clearInputs(); - done(); - } - - return { - state, - onSubmit: async (e: React.FormEvent | React.MouseEvent) => { - e.preventDefault(); - setState({ - ...state, - isLoading: true, - }); - - const metadata = unflattenMetadata({ - ...flattenMetadata(agent.user_provided_metadata), - [keyInput.value]: valueInput.value, - }); - - try { - const { error } = await sendRequest({ - path: agentRouteService.getUpdatePath(agent.id), - method: 'put', - body: JSON.stringify({ - user_provided_metadata: metadata, - }), - }); - - if (error) { - throw error; - } - await success(); - } catch (error) { - setError(error); - } - }, - inputs: { - keyInput, - valueInput, - }, - }; -} - -export const MetadataForm: React.FunctionComponent<{ agent: Agent }> = ({ agent }) => { - const [isOpen, setOpen] = useState(false); - - const form = useAddMetadataForm(agent, () => { - setOpen(false); - }); - const { keyInput, valueInput } = form.inputs; - - const button = ( - setOpen(true)} color={'text'}> - - - ); - return ( - <> - setOpen(false)} - initialFocus="[id=fleet-details-metadata-form]" - > -
- - - - - - - - - - - - - - - - - - - - - -
-
- - ); -}; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/type_labels.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/type_labels.tsx deleted file mode 100644 index dbe18ab333736..0000000000000 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/type_labels.tsx +++ /dev/null @@ -1,120 +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 { EuiBadge } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { AgentEvent } from '../../../../types'; - -export const TYPE_LABEL: { [key in AgentEvent['type']]: JSX.Element } = { - STATE: ( - - - - ), - ERROR: ( - - - - ), - ACTION_RESULT: ( - - - - ), - ACTION: ( - - - - ), -}; - -export const SUBTYPE_LABEL: { [key in AgentEvent['subtype']]: JSX.Element } = { - RUNNING: ( - - - - ), - STARTING: ( - - - - ), - IN_PROGRESS: ( - - - - ), - CONFIG: ( - - - - ), - FAILED: ( - - - - ), - STOPPING: ( - - - - ), - STOPPED: ( - - - - ), - DEGRADED: ( - - - - ), - DATA_DUMP: ( - - - - ), - ACKNOWLEDGED: ( - - - - ), - UPDATING: ( - - - - ), - UNKNOWN: ( - - - - ), -}; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/index.tsx index 7d60ae23deac6..f3714bbb53223 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/index.tsx @@ -28,13 +28,13 @@ import { useGetOneAgentPolicy, useLink, useBreadcrumbs, - useCore, + useStartServices, useKibanaVersion, } from '../../../hooks'; import { WithHeaderLayout } from '../../../layouts'; import { AgentHealth } from '../components'; import { AgentRefreshContext } from './hooks'; -import { AgentEventsTable, AgentDetailsActionMenu, AgentDetailsContent } from './components'; +import { AgentLogs, AgentDetailsActionMenu, AgentDetailsContent } from './components'; import { useIntraAppState } from '../../../hooks/use_intra_app_state'; import { isAgentUpgradeable } from '../../../services'; @@ -67,7 +67,7 @@ export const AgentDetailsPage: React.FunctionComponent = () => { const { application: { navigateToApp }, - } = useCore(); + } = useStartServices(); const routeState = useIntraAppState(); const queryParams = new URLSearchParams(useLocation().search); const openReassignFlyoutOpenByDefault = queryParams.get('openReassignFlyout') === 'true'; @@ -223,21 +223,21 @@ export const AgentDetailsPage: React.FunctionComponent = () => { const headerTabs = useMemo(() => { return [ - { - id: 'activity_log', - name: i18n.translate('xpack.fleet.agentDetails.subTabs.activityLogTab', { - defaultMessage: 'Activity log', - }), - href: getHref('fleet_agent_details', { agentId, tabId: 'activity' }), - isSelected: !tabId || tabId === 'activity', - }, { id: 'details', name: i18n.translate('xpack.fleet.agentDetails.subTabs.detailsTab', { defaultMessage: 'Agent details', }), href: getHref('fleet_agent_details', { agentId, tabId: 'details' }), - isSelected: tabId === 'details', + isSelected: !tabId || tabId === 'details', + }, + { + id: 'logs', + name: i18n.translate('xpack.fleet.agentDetails.subTabs.logsTab', { + defaultMessage: 'Logs', + }), + href: getHref('fleet_agent_details', { agentId, tabId: 'logs' }), + isSelected: tabId === 'logs', }, ]; }, [getHref, agentId, tabId]); @@ -305,15 +305,15 @@ const AgentDetailsPageContent: React.FunctionComponent<{ return ( { - return ; + return ; }} /> { - return ; + return ; }} /> diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_enrollment_flyout/agent_policy_selection.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_enrollment_flyout/agent_policy_selection.tsx index 758497607c057..b90758335dc75 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_enrollment_flyout/agent_policy_selection.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_enrollment_flyout/agent_policy_selection.tsx @@ -10,7 +10,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { EuiSelect, EuiSpacer, EuiText, EuiButtonEmpty } from '@elastic/eui'; import { SO_SEARCH_LIMIT } from '../../../../constants'; import { AgentPolicy, GetEnrollmentAPIKeysResponse } from '../../../../types'; -import { sendGetEnrollmentAPIKeys, useCore } from '../../../../hooks'; +import { sendGetEnrollmentAPIKeys, useStartServices } from '../../../../hooks'; import { AgentPolicyPackageBadges } from '../agent_policy_package_badges'; type Props = { @@ -27,7 +27,7 @@ type Props = { ); export const EnrollmentStepAgentPolicy: React.FC = (props) => { - const { notifications } = useCore(); + const { notifications } = useStartServices(); const { withKeySelection, agentPolicies, onAgentPolicyChange } = props; const onKeyChange = props.withKeySelection && props.onKeyChange; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_enrollment_flyout/managed_instructions.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_enrollment_flyout/managed_instructions.tsx index 656493e31e5f5..840e47c5cd1f7 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_enrollment_flyout/managed_instructions.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_enrollment_flyout/managed_instructions.tsx @@ -12,7 +12,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { AgentPolicy } from '../../../../types'; import { useGetOneEnrollmentAPIKey, - useCore, + useStartServices, useGetSettings, useLink, useFleetStatus, @@ -26,7 +26,7 @@ interface Props { export const ManagedInstructions = React.memo(({ agentPolicies }) => { const { getHref } = useLink(); - const core = useCore(); + const core = useStartServices(); const fleetStatus = useFleetStatus(); const [selectedAPIKeyId, setSelectedAPIKeyId] = useState(); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_enrollment_flyout/standalone_instructions.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_enrollment_flyout/standalone_instructions.tsx index a2daf2d10c271..da2bb8adf1b35 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_enrollment_flyout/standalone_instructions.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_enrollment_flyout/standalone_instructions.tsx @@ -21,7 +21,7 @@ import { EuiContainedStepProps } from '@elastic/eui/src/components/steps/steps'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { AgentPolicy } from '../../../../types'; -import { useCore, useLink, sendGetOneAgentPolicyFull } from '../../../../hooks'; +import { useStartServices, useLink, sendGetOneAgentPolicyFull } from '../../../../hooks'; import { DownloadStep, AgentPolicySelectionStep } from './steps'; import { fullAgentPolicyToYaml, agentPolicyRouteService } from '../../../../services'; @@ -33,7 +33,7 @@ const RUN_INSTRUCTIONS = './elastic-agent install'; export const StandaloneInstructions = React.memo(({ agentPolicies }) => { const { getHref } = useLink(); - const core = useCore(); + const core = useStartServices(); const { notifications } = core; const [selectedPolicyId, setSelectedPolicyId] = useState(); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_reassign_policy_flyout/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_reassign_policy_flyout/index.tsx index 46e291e73fa78..90726b54d283a 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_reassign_policy_flyout/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_reassign_policy_flyout/index.tsx @@ -25,7 +25,7 @@ import { Agent } from '../../../../types'; import { sendPutAgentReassign, sendPostBulkAgentReassign, - useCore, + useStartServices, useGetAgentPolicies, } from '../../../../hooks'; import { AgentPolicyPackageBadges } from '../agent_policy_package_badges'; @@ -39,7 +39,7 @@ export const AgentReassignAgentPolicyFlyout: React.FunctionComponent = ({ onClose, agents, }) => { - const { notifications } = useCore(); + const { notifications } = useStartServices(); const isSingleAgent = Array.isArray(agents) && agents.length === 1; const [selectedAgentPolicyId, setSelectedAgentPolicyId] = useState( diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_unenroll_modal/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_unenroll_modal/index.tsx index 1b3935a86f65c..180ad5e4953b8 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_unenroll_modal/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_unenroll_modal/index.tsx @@ -8,7 +8,11 @@ import { i18n } from '@kbn/i18n'; import { EuiConfirmModal, EuiOverlayMask, EuiFormFieldset, EuiCheckbox } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { Agent } from '../../../../types'; -import { sendPostAgentUnenroll, sendPostBulkAgentUnenroll, useCore } from '../../../../hooks'; +import { + sendPostAgentUnenroll, + sendPostBulkAgentUnenroll, + useStartServices, +} from '../../../../hooks'; interface Props { onClose: () => void; @@ -23,7 +27,7 @@ export const AgentUnenrollAgentModal: React.FunctionComponent = ({ agentCount, useForceUnenroll, }) => { - const { notifications } = useCore(); + const { notifications } = useStartServices(); const [forceUnenroll, setForceUnenroll] = useState(useForceUnenroll || false); const [isSubmitting, setIsSubmitting] = useState(false); const isSingleAgent = Array.isArray(agents) && agents.length === 1; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.tsx index 43ad7208c3d81..6b7fca9e086aa 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.tsx @@ -14,7 +14,11 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { Agent } from '../../../../types'; -import { sendPostAgentUpgrade, sendPostBulkAgentUpgrade, useCore } from '../../../../hooks'; +import { + sendPostAgentUpgrade, + sendPostBulkAgentUpgrade, + useStartServices, +} from '../../../../hooks'; interface Props { onClose: () => void; @@ -29,7 +33,7 @@ export const AgentUpgradeAgentModal: React.FunctionComponent = ({ agentCount, version, }) => { - const { notifications } = useCore(); + const { notifications } = useStartServices(); const [isSubmitting, setIsSubmitting] = useState(false); const isSingleAgent = Array.isArray(agents) && agents.length === 1; async function onSubmit() { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/enrollment_token_list_page/components/new_enrollment_key_flyout.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/enrollment_token_list_page/components/new_enrollment_key_flyout.tsx index 78e8be4679dc3..ed607e361bd6e 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/enrollment_token_list_page/components/new_enrollment_key_flyout.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/enrollment_token_list_page/components/new_enrollment_key_flyout.tsx @@ -22,14 +22,14 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { AgentPolicy } from '../../../../types'; -import { useInput, useCore, sendRequest } from '../../../../hooks'; +import { useInput, useStartServices, sendRequest } from '../../../../hooks'; import { enrollmentAPIKeyRouteService } from '../../../../services'; function useCreateApiKeyForm( policyIdDefaultValue: string | undefined, onSuccess: (keyId: string) => void ) { - const { notifications } = useCore(); + const { notifications } = useStartServices(); const [isLoading, setIsLoading] = useState(false); const apiKeyNameInput = useInput(''); const policyIdInput = useInput(policyIdDefaultValue); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/enrollment_token_list_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/enrollment_token_list_page/index.tsx index 7e5d07b2319d3..71cd417a256c3 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/enrollment_token_list_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/enrollment_token_list_page/index.tsx @@ -26,7 +26,7 @@ import { useGetEnrollmentAPIKeys, useGetAgentPolicies, sendGetOneEnrollmentAPIKey, - useCore, + useStartServices, sendDeleteOneEnrollmentAPIKey, } from '../../../hooks'; import { EnrollmentAPIKey } from '../../../types'; @@ -35,7 +35,7 @@ import { NewEnrollmentTokenFlyout } from './components/new_enrollment_key_flyout import { ConfirmEnrollmentTokenDelete } from './components/confirm_delete_modal'; const ApiKeyField: React.FunctionComponent<{ apiKeyId: string }> = ({ apiKeyId }) => { - const { notifications } = useCore(); + const { notifications } = useStartServices(); const [state, setState] = useState<'VISIBLE' | 'HIDDEN' | 'LOADING'>('HIDDEN'); const [key, setKey] = useState(); @@ -106,7 +106,7 @@ const DeleteButton: React.FunctionComponent<{ apiKey: EnrollmentAPIKey; refresh: apiKey, refresh, }) => { - const { notifications } = useCore(); + const { notifications } = useStartServices(); const [state, setState] = useState<'CONFIRM_VISIBLE' | 'CONFIRM_HIDDEN'>('CONFIRM_HIDDEN'); const onCancel = () => setState('CONFIRM_HIDDEN'); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/setup_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/setup_page/index.tsx index 60ee791ace5eb..8fee44018f0a0 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/setup_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/setup_page/index.tsx @@ -22,7 +22,7 @@ import { EuiCodeBlock, EuiLink, } from '@elastic/eui'; -import { useCore, sendPostFleetSetup } from '../../../hooks'; +import { useStartServices, sendPostFleetSetup } from '../../../hooks'; import { WithoutHeaderLayout } from '../../../layouts'; import { GetFleetStatusResponse } from '../../../types'; @@ -53,7 +53,7 @@ export const SetupPage: React.FunctionComponent<{ missingRequirements: GetFleetStatusResponse['missing_requirements']; }> = ({ refresh, missingRequirements }) => { const [isFormLoading, setIsFormLoading] = useState(false); - const core = useCore(); + const core = useStartServices(); const onSubmit = async () => { setIsFormLoading(true); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/data_stream/list_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/data_stream/list_page/index.tsx index 533c273681122..c614518c1930b 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/data_stream/list_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/data_stream/list_page/index.tsx @@ -19,7 +19,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage, FormattedDate } from '@kbn/i18n/react'; import { DataStream } from '../../../types'; import { WithHeaderLayout } from '../../../layouts'; -import { useGetDataStreams, useStartDeps, usePagination, useBreadcrumbs } from '../../../hooks'; +import { useGetDataStreams, useStartServices, usePagination, useBreadcrumbs } from '../../../hooks'; import { PackageIcon } from '../../../components/package_icon'; import { DataStreamRowActions } from './components/data_stream_row_actions'; @@ -59,7 +59,7 @@ export const DataStreamListPage: React.FunctionComponent<{}> = () => { const { data: { fieldFormats }, - } = useStartDeps(); + } = useStartServices(); const { pagination, pageSizeOptions } = usePagination(); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/components/icon_panel.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/components/icon_panel.tsx index 7004a602627c1..8ced0734a3967 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/components/icon_panel.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/components/icon_panel.tsx @@ -12,8 +12,9 @@ import { Loading } from '../../../components'; const PanelWrapper = styled.div` // NOTE: changes to the width here will impact navigation tabs page layout under integration package details width: ${(props) => - parseFloat(props.theme.eui.euiSize) * 6 + parseFloat(props.theme.eui.spacerSizes.xl) * 2}px; + parseFloat(props.theme.eui.euiSize) * 6 + parseFloat(props.theme.eui.euiSizeXL) * 2}px; height: 1px; + z-index: 1; `; const Panel = styled(EuiPanel)` diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/hooks/use_links.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/hooks/use_links.tsx index a453a7f2e28cb..3d2babae8eb2e 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/hooks/use_links.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/hooks/use_links.tsx @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { useCore } from '../../../hooks/use_core'; +import { useStartServices } from '../../../hooks/use_core'; import { PLUGIN_ID } from '../../../constants'; import { epmRouteService } from '../../../services'; @@ -11,7 +11,7 @@ const removeRelativePath = (relativePath: string): string => new URL(relativePath, 'http://example.com').pathname; export function useLinks() { - const { http } = useCore(); + const { http } = useStartServices(); return { toAssets: (path: string) => http.basePath.prepend(`/plugins/${PLUGIN_ID}/assets/${path}`), toImage: (path: string) => http.basePath.prepend(epmRouteService.getFilePath(path)), diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/index.scss b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/index.scss new file mode 100644 index 0000000000000..e8366d99b6391 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/index.scss @@ -0,0 +1,5 @@ +@import '@elastic/eui/src/global_styling/variables/_size.scss'; + +.fleet__epm__shiftNavTabs { + margin-left: $euiSize * 6 + $euiSizeXL * 2 + $euiSizeL; +} diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/index.tsx index 2535a53589bd9..0e72693db9e2d 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/index.tsx @@ -28,13 +28,13 @@ import { useLink, useCapabilities, } from '../../../../hooks'; -import { WithHeaderLayout } from '../../../../layouts'; +import { WithHeaderLayout, WithHeaderLayoutProps } from '../../../../layouts'; import { useSetPackageInstallStatus } from '../../hooks'; import { IconPanel, LoadingIconPanel } from '../../components/icon_panel'; import { RELEASE_BADGE_LABEL, RELEASE_BADGE_DESCRIPTION } from '../../components/release_badge'; import { UpdateIcon } from '../../components/icons'; import { Content } from './content'; -import { WithHeaderLayoutProps } from '../../../../layouts/with_header'; +import './index.scss'; export const DEFAULT_PANEL: DetailViewPanelName = 'overview'; @@ -55,16 +55,6 @@ const PanelDisplayNames: Record = { }), }; -const DetailWrapper = styled.div` - // Class name here is in sync with 'PanelWrapper' in 'IconPanel' component - .shiftNavTabs { - margin-left: ${(props) => - parseFloat(props.theme.eui.euiSize) * 6 + - parseFloat(props.theme.eui.spacerSizes.xl) * 2 + - parseFloat(props.theme.eui.spacerSizes.l)}px; - } -`; - const Divider = styled.div` width: 0; height: 100%; @@ -265,31 +255,29 @@ export function Detail() { }, [getHref, packageInfo, packageInfoData?.response?.status, panel]); return ( - - - {packageInfo ? : null} - {packageInfoError ? ( - - } - error={packageInfoError} - /> - ) : isLoading || !packageInfo ? ( - - ) : ( - - )} - - + + {packageInfo ? : null} + {packageInfoError ? ( + + } + error={packageInfoError} + /> + ) : isLoading || !packageInfo ? ( + + ) : ( + + )} + ); } diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/home/header.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/home/header.tsx index e9704cd16b219..b5fef901d123d 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/home/header.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/home/header.tsx @@ -10,7 +10,7 @@ import styled from 'styled-components'; import { EuiFlexGroup, EuiFlexItem, EuiImage, EuiText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { useLinks } from '../../hooks'; -import { useCore } from '../../../../hooks'; +import { useStartServices } from '../../../../hooks'; export const HeroCopy = memo(() => { return ( @@ -43,7 +43,7 @@ const Illustration = styled(EuiImage)` export const HeroImage = memo(() => { const { toAssets } = useLinks(); - const { uiSettings } = useCore(); + const { uiSettings } = useStartServices(); const IS_DARK_THEME = uiSettings.get('theme:darkMode'); return ( diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/overview/components/datastream_section.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/overview/components/datastream_section.tsx index 58f84e8671385..10f538b3112c6 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/overview/components/datastream_section.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/overview/components/datastream_section.tsx @@ -15,7 +15,7 @@ import { } from '@elastic/eui'; import { OverviewPanel } from './overview_panel'; import { OverviewStats } from './overview_stats'; -import { useLink, useGetDataStreams, useStartDeps } from '../../../hooks'; +import { useLink, useGetDataStreams, useStartServices } from '../../../hooks'; import { Loading } from '../../agents/components'; export const OverviewDatastreamSection: React.FC = () => { @@ -23,7 +23,7 @@ export const OverviewDatastreamSection: React.FC = () => { const datastreamRequest = useGetDataStreams(); const { data: { fieldFormats }, - } = useStartDeps(); + } = useStartServices(); const total = datastreamRequest.data?.data_streams?.length ?? 0; let sizeBytes = 0; diff --git a/x-pack/plugins/fleet/public/plugin.ts b/x-pack/plugins/fleet/public/plugin.ts index 7e523b3fa594a..31b53f41b3a91 100644 --- a/x-pack/plugins/fleet/public/plugin.ts +++ b/x-pack/plugins/fleet/public/plugin.ts @@ -17,6 +17,7 @@ import { HomePublicPluginSetup, FeatureCatalogueCategory, } from '../../../../src/plugins/home/public'; +import { Storage } from '../../../../src/plugins/kibana_utils/public'; import { LicensingPluginSetup } from '../../licensing/public'; import { PLUGIN_ID, CheckPermissionsResponse, PostIngestSetupResponse } from '../common'; import { BASE_PATH } from './applications/fleet/constants'; @@ -58,10 +59,15 @@ export interface FleetStartDeps { data: DataPublicPluginStart; } +export interface FleetStartServices extends CoreStart, FleetStartDeps { + storage: Storage; +} + export class FleetPlugin implements Plugin { private config: FleetConfigType; private kibanaVersion: string; private extensions: UIExtensionsStorage = {}; + private storage = new Storage(localStorage); constructor(private readonly initializerContext: PluginInitializerContext) { this.config = this.initializerContext.config.get(); @@ -86,26 +92,23 @@ export class FleetPlugin implements Plugin { + const [coreStartServices, startDepsServices] = (await core.getStartServices()) as [ CoreStart, FleetStartDeps, FleetStart ]; - const { renderApp, teardownFleet } = await import('./applications/fleet/'); - const unmount = renderApp( - coreStart, - params, - deps, - startDeps, - config, - kibanaVersion, - extensions - ); + const startServices: FleetStartServices = { + ...coreStartServices, + ...startDepsServices, + storage: this.storage, + }; + const { renderApp, teardownFleet } = await import('./applications/fleet'); + const unmount = renderApp(startServices, params, config, kibanaVersion, extensions); return () => { unmount(); - teardownFleet(coreStart); + teardownFleet(startServices); }; }, }); diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 5277944afa907..b5c6a4e3fd03f 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -7181,17 +7181,13 @@ "xpack.fleet.agentDetails.agentVersionLabel": "エージェントバージョン", "xpack.fleet.agentDetails.hostIdLabel": "エージェントID", "xpack.fleet.agentDetails.hostNameLabel": "ホスト名", - "xpack.fleet.agentDetails.localMetadataSectionSubtitle": "メタデータを読み込み中", - "xpack.fleet.agentDetails.metadataSectionTitle": "メタデータ", "xpack.fleet.agentDetails.platformLabel": "プラットフォーム", "xpack.fleet.agentDetails.policyLabel": "ポリシー", "xpack.fleet.agentDetails.releaseLabel": "エージェントリリース", "xpack.fleet.agentDetails.statusLabel": "ステータス", - "xpack.fleet.agentDetails.subTabs.activityLogTab": "アクティビティログ", "xpack.fleet.agentDetails.subTabs.detailsTab": "エージェントの詳細", "xpack.fleet.agentDetails.unexceptedErrorTitle": "エージェントの読み込み中にエラーが発生しました", "xpack.fleet.agentDetails.upgradeAvailableTooltip": "アップグレードが利用可能です", - "xpack.fleet.agentDetails.userProvidedMetadataSectionSubtitle": "ユーザー提供メタデータ", "xpack.fleet.agentDetails.versionLabel": "エージェントバージョン", "xpack.fleet.agentDetails.viewAgentListTitle": "すべてのエージェントを表示", "xpack.fleet.agentEnrollment.agentDescription": "Elasticエージェントをホストに追加し、データを収集して、Elastic Stackに送信します。", @@ -7219,32 +7215,6 @@ "xpack.fleet.agentEnrollment.stepEnrollAndRunAgentTitle": "Elasticエージェントを登録して実行", "xpack.fleet.agentEnrollment.stepRunAgentDescription": "エージェントのディレクトリから、このコマンドを実行し、Elasticエージェントを、インストール、登録、起動します。このコマンドを再利用すると、複数のホストでエージェントを設定できます。管理者権限が必要です。", "xpack.fleet.agentEnrollment.stepRunAgentTitle": "エージェントの起動", - "xpack.fleet.agentEventsList.collapseDetailsAriaLabel": "詳細を非表示", - "xpack.fleet.agentEventsList.expandDetailsAriaLabel": "詳細を表示", - "xpack.fleet.agentEventsList.messageColumnTitle": "メッセージ", - "xpack.fleet.agentEventsList.messageDetailsTitle": "メッセージ", - "xpack.fleet.agentEventsList.payloadDetailsTitle": "ペイロード", - "xpack.fleet.agentEventsList.refreshButton": "更新", - "xpack.fleet.agentEventsList.searchPlaceholderText": "アクティビティログを検索", - "xpack.fleet.agentEventsList.subtypeColumnTitle": "サブタイプ", - "xpack.fleet.agentEventsList.timestampColumnTitle": "タイムスタンプ", - "xpack.fleet.agentEventsList.typeColumnTitle": "タイプ", - "xpack.fleet.agentEventSubtype.acknowledgedLabel": "認識", - "xpack.fleet.agentEventSubtype.dataDumpLabel": "データダンプ", - "xpack.fleet.agentEventSubtype.degradedLabel": "劣化", - "xpack.fleet.agentEventSubtype.failedLabel": "失敗", - "xpack.fleet.agentEventSubtype.inProgressLabel": "進行中", - "xpack.fleet.agentEventSubtype.policyLabel": "ポリシー", - "xpack.fleet.agentEventSubtype.runningLabel": "実行中", - "xpack.fleet.agentEventSubtype.startingLabel": "開始中", - "xpack.fleet.agentEventSubtype.stoppedLabel": "停止", - "xpack.fleet.agentEventSubtype.stoppingLabel": "停止中", - "xpack.fleet.agentEventSubtype.unknownLabel": "不明", - "xpack.fleet.agentEventSubtype.updatingLabel": "更新中", - "xpack.fleet.agentEventType.actionLabel": "アクション", - "xpack.fleet.agentEventType.actionResultLabel": "アクション結果", - "xpack.fleet.agentEventType.errorLabel": "エラー", - "xpack.fleet.agentEventType.stateLabel": "ステータス", "xpack.fleet.agentHealth.checkInTooltipText": "前回のチェックイン {lastCheckIn}", "xpack.fleet.agentHealth.degradedStatusText": "劣化", "xpack.fleet.agentHealth.enrollingStatusText": "登録中", @@ -7590,10 +7560,6 @@ "xpack.fleet.invalidLicenseTitle": "ライセンスの期限切れ", "xpack.fleet.listTabs.agentTitle": "エージェント", "xpack.fleet.listTabs.enrollmentTokensTitle": "登録トークン", - "xpack.fleet.metadataForm.addButton": "+ メタデータを追加", - "xpack.fleet.metadataForm.keyLabel": "キー", - "xpack.fleet.metadataForm.submitButtonText": "追加", - "xpack.fleet.metadataForm.valueLabel": "値", "xpack.fleet.namespaceValidation.invalidCharactersErrorMessage": "名前空間に無効な文字が含まれています", "xpack.fleet.namespaceValidation.lowercaseErrorMessage": "名前空間は小文字で指定する必要があります", "xpack.fleet.namespaceValidation.requiredErrorMessage": "名前空間は必須です", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 0ac240ddfa13f..a2d42dcfcdc52 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -7187,17 +7187,13 @@ "xpack.fleet.agentDetails.agentVersionLabel": "代理版本", "xpack.fleet.agentDetails.hostIdLabel": "代理 ID", "xpack.fleet.agentDetails.hostNameLabel": "主机名", - "xpack.fleet.agentDetails.localMetadataSectionSubtitle": "本地元数据", - "xpack.fleet.agentDetails.metadataSectionTitle": "元数据", "xpack.fleet.agentDetails.platformLabel": "平台", "xpack.fleet.agentDetails.policyLabel": "策略", "xpack.fleet.agentDetails.releaseLabel": "代理发行版", "xpack.fleet.agentDetails.statusLabel": "状态", - "xpack.fleet.agentDetails.subTabs.activityLogTab": "活动日志", "xpack.fleet.agentDetails.subTabs.detailsTab": "代理详情", "xpack.fleet.agentDetails.unexceptedErrorTitle": "加载代理时出错", "xpack.fleet.agentDetails.upgradeAvailableTooltip": "升级可用", - "xpack.fleet.agentDetails.userProvidedMetadataSectionSubtitle": "用户提供的元数据", "xpack.fleet.agentDetails.versionLabel": "代理版本", "xpack.fleet.agentDetails.viewAgentListTitle": "查看所有代理", "xpack.fleet.agentEnrollment.agentDescription": "将 Elastic 代理添加到您的主机,以收集数据并将其发送到 Elastic Stack。", @@ -7225,32 +7221,6 @@ "xpack.fleet.agentEnrollment.stepEnrollAndRunAgentTitle": "注册并启动 Elastic 代理", "xpack.fleet.agentEnrollment.stepRunAgentDescription": "从代理目录运行此命令,以安装、注册并启动 Elastic 代理。您可以重复使用此命令在多个主机上设置代理。需要管理员权限。", "xpack.fleet.agentEnrollment.stepRunAgentTitle": "启动代理", - "xpack.fleet.agentEventsList.collapseDetailsAriaLabel": "隐藏详情", - "xpack.fleet.agentEventsList.expandDetailsAriaLabel": "显示详情", - "xpack.fleet.agentEventsList.messageColumnTitle": "消息", - "xpack.fleet.agentEventsList.messageDetailsTitle": "消息", - "xpack.fleet.agentEventsList.payloadDetailsTitle": "负载", - "xpack.fleet.agentEventsList.refreshButton": "刷新", - "xpack.fleet.agentEventsList.searchPlaceholderText": "搜索活动日志", - "xpack.fleet.agentEventsList.subtypeColumnTitle": "子类型", - "xpack.fleet.agentEventsList.timestampColumnTitle": "时间戳", - "xpack.fleet.agentEventsList.typeColumnTitle": "类型", - "xpack.fleet.agentEventSubtype.acknowledgedLabel": "已确认", - "xpack.fleet.agentEventSubtype.dataDumpLabel": "数据转储", - "xpack.fleet.agentEventSubtype.degradedLabel": "已降级", - "xpack.fleet.agentEventSubtype.failedLabel": "失败", - "xpack.fleet.agentEventSubtype.inProgressLabel": "进行中", - "xpack.fleet.agentEventSubtype.policyLabel": "策略", - "xpack.fleet.agentEventSubtype.runningLabel": "正在运行", - "xpack.fleet.agentEventSubtype.startingLabel": "正在启动", - "xpack.fleet.agentEventSubtype.stoppedLabel": "已停止", - "xpack.fleet.agentEventSubtype.stoppingLabel": "正在停止", - "xpack.fleet.agentEventSubtype.unknownLabel": "未知", - "xpack.fleet.agentEventSubtype.updatingLabel": "正在更新", - "xpack.fleet.agentEventType.actionLabel": "操作", - "xpack.fleet.agentEventType.actionResultLabel": "操作结果", - "xpack.fleet.agentEventType.errorLabel": "错误", - "xpack.fleet.agentEventType.stateLabel": "状态", "xpack.fleet.agentHealth.checkInTooltipText": "上次签入时间 {lastCheckIn}", "xpack.fleet.agentHealth.degradedStatusText": "已降级", "xpack.fleet.agentHealth.enrollingStatusText": "正在注册", @@ -7598,10 +7568,6 @@ "xpack.fleet.invalidLicenseTitle": "已过期许可证", "xpack.fleet.listTabs.agentTitle": "代理", "xpack.fleet.listTabs.enrollmentTokensTitle": "注册令牌", - "xpack.fleet.metadataForm.addButton": "+ 添加元数据", - "xpack.fleet.metadataForm.keyLabel": "键", - "xpack.fleet.metadataForm.submitButtonText": "添加", - "xpack.fleet.metadataForm.valueLabel": "值", "xpack.fleet.namespaceValidation.invalidCharactersErrorMessage": "命名空间包含无效字符", "xpack.fleet.namespaceValidation.lowercaseErrorMessage": "命名空间必须小写", "xpack.fleet.namespaceValidation.requiredErrorMessage": "“命名空间”必填", diff --git a/x-pack/plugins/apm/typings/cytoscape_dagre.d.ts b/x-pack/typings/cytoscape_dagre.d.ts similarity index 100% rename from x-pack/plugins/apm/typings/cytoscape_dagre.d.ts rename to x-pack/typings/cytoscape_dagre.d.ts diff --git a/x-pack/plugins/apm/typings/react_vis.d.ts b/x-pack/typings/react_vis.d.ts similarity index 100% rename from x-pack/plugins/apm/typings/react_vis.d.ts rename to x-pack/typings/react_vis.d.ts