diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/index.ts b/x-pack/plugins/fleet/public/applications/fleet/components/index.ts index 93bc0645c7eee9..ea6abc4bba5f56 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/index.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/components/index.ts @@ -11,3 +11,4 @@ export { PackageIcon } from './package_icon'; export { ContextMenuActions } from './context_menu_actions'; export { SearchBar } from './search_bar'; export * from './settings_flyout'; +export * from './link_and_revision'; diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/link_and_revision.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/link_and_revision.tsx new file mode 100644 index 00000000000000..a9e44b200cf698 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/components/link_and_revision.tsx @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { EuiFlexGroup, EuiFlexItem, EuiLink, EuiText } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import React, { CSSProperties, memo } from 'react'; +import { EuiLinkProps } from '@elastic/eui/src/components/link/link'; + +const MIN_WIDTH: CSSProperties = { minWidth: 0 }; +const NO_WRAP_WHITE_SPACE: CSSProperties = { whiteSpace: 'nowrap' }; + +export type LinkAndRevisionProps = EuiLinkProps & { + revision?: string | number; +}; + +/** + * Components shows a link for a given value along with a revision number to its right. The display + * value is truncated if it is longer than the width of where it is displayed, while the revision + * always remain visible + */ +export const LinkAndRevision = memo( + ({ revision, className, ...euiLinkProps }) => { + return ( + + + + + {revision && ( + + + + + + )} + + ); + } +); 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 6026a5579f65b6..5b0243f127333f 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/index.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/index.ts @@ -13,7 +13,8 @@ export { useBreadcrumbs } from './use_breadcrumbs'; export { useLink } from './use_link'; export { useKibanaLink } from './use_kibana_link'; export { usePackageIconType, UsePackageIconType } from './use_package_icon_type'; -export { usePagination, Pagination } from './use_pagination'; +export { usePagination, Pagination, PAGE_SIZE_OPTIONS } from './use_pagination'; +export { useUrlPagination } from './use_url_pagination'; export { useSorting } from './use_sorting'; export { useDebounce } from './use_debounce'; export * from './use_request'; diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_pagination.tsx b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_pagination.tsx index 699bba3c62f97a..1fdd223ef80471 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_pagination.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_pagination.tsx @@ -4,22 +4,27 @@ * you may not use this file except in compliance with the Elastic License. */ -import { useState } from 'react'; +import { useMemo, useState } from 'react'; + +export const PAGE_SIZE_OPTIONS: readonly number[] = [5, 20, 50]; export interface Pagination { currentPage: number; pageSize: number; } -export function usePagination() { - const [pagination, setPagination] = useState({ +export function usePagination( + pageInfo: Pagination = { currentPage: 1, pageSize: 20, - }); + } +) { + const [pagination, setPagination] = useState(pageInfo); + const pageSizeOptions = useMemo(() => [...PAGE_SIZE_OPTIONS], []); return { pagination, setPagination, - pageSizeOptions: [5, 20, 50], + pageSizeOptions, }; } diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_url_pagination.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_url_pagination.ts new file mode 100644 index 00000000000000..f9c351899fe0a2 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_url_pagination.ts @@ -0,0 +1,94 @@ +/* + * 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 { useCallback, useEffect, useMemo } from 'react'; +import { useHistory, useLocation } from 'react-router-dom'; +import { useUrlParams } from './use_url_params'; +import { PAGE_SIZE_OPTIONS, Pagination, usePagination } from './use_pagination'; + +type SetUrlPagination = (pagination: Pagination) => void; +interface UrlPagination { + pagination: Pagination; + setPagination: SetUrlPagination; + pageSizeOptions: number[]; +} + +type UrlPaginationParams = Partial; + +/** + * Uses URL params for pagination and also persists those to the URL as they are updated + */ +export const useUrlPagination = (): UrlPagination => { + const location = useLocation(); + const history = useHistory(); + const { urlParams, toUrlParams } = useUrlParams(); + const urlPaginationParams = useMemo(() => { + return paginationFromUrlParams(urlParams); + }, [urlParams]); + const { pagination, pageSizeOptions, setPagination } = usePagination(urlPaginationParams); + + const setUrlPagination = useCallback( + ({ pageSize, currentPage }) => { + history.push({ + ...location, + search: toUrlParams({ + ...urlParams, + currentPage, + pageSize, + }), + }); + }, + [history, location, toUrlParams, urlParams] + ); + + useEffect(() => { + setPagination((prevState) => { + return { + ...prevState, + ...paginationFromUrlParams(urlParams), + }; + }); + }, [setPagination, urlParams]); + + return { + pagination, + setPagination: setUrlPagination, + pageSizeOptions, + }; +}; + +const paginationFromUrlParams = (urlParams: UrlPaginationParams): Pagination => { + const pagination: Pagination = { + pageSize: 20, + currentPage: 1, + }; + + // Search params can appear multiple times in the URL, in which case the value for them, + // once parsed, would be an array. In these case, we take the last value defined + pagination.currentPage = Number( + (Array.isArray(urlParams.currentPage) + ? urlParams.currentPage[urlParams.currentPage.length - 1] + : urlParams.currentPage) ?? pagination.currentPage + ); + pagination.pageSize = + Number( + (Array.isArray(urlParams.pageSize) + ? urlParams.pageSize[urlParams.pageSize.length - 1] + : urlParams.pageSize) ?? pagination.pageSize + ) ?? pagination.pageSize; + + // If Current Page is not a valid positive integer, set it to 1 + if (!Number.isFinite(pagination.currentPage) || pagination.currentPage < 1) { + pagination.currentPage = 1; + } + + // if pageSize is not one of the expected page sizes, reset it to 20 (default) + if (!PAGE_SIZE_OPTIONS.includes(pagination.pageSize)) { + pagination.pageSize = 20; + } + + return pagination; +}; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_select_agent_policy.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_select_agent_policy.tsx index 4a737cf3c2d7af..53463c14b9ce67 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_select_agent_policy.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_select_agent_policy.tsx @@ -247,7 +247,7 @@ export const StepSelectAgentPolicy: React.FunctionComponent<{ id="xpack.fleet.createPackagePolicy.StepSelectPolicy.agentPolicyAgentsDescriptionText" defaultMessage="{count, plural, one {# agent} other {# agents}} are enrolled with the selected agent policy." values={{ - count: agentPoliciesById[selectedPolicyId]?.agents || 0, + count: agentPoliciesById[selectedPolicyId]?.agents ?? 0, }} /> ) : null @@ -283,7 +283,7 @@ export const StepSelectAgentPolicy: React.FunctionComponent<{ id="xpack.fleet.createPackagePolicy.StepSelectPolicy.agentPolicyAgentsCountText" defaultMessage="{count, plural, one {# agent} other {# agents}} enrolled" values={{ - count: agentPoliciesById[option.value!].agents || 0, + count: agentPoliciesById[option.value!]?.agents ?? 0, }} /> diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/index.tsx index 8c2fe838bfa435..0e8bb6b49e4abd 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/list_page/index.tsx @@ -34,7 +34,7 @@ import { useUrlParams, useBreadcrumbs, } from '../../../hooks'; -import { SearchBar } from '../../../components'; +import { LinkAndRevision, SearchBar } from '../../../components'; import { LinkedAgentCount, AgentPolicyActionMenu } from '../components'; import { CreateAgentPolicyFlyout } from './components'; @@ -129,26 +129,13 @@ export const AgentPolicyListPage: React.FunctionComponent<{}> = () => { }), width: '20%', render: (name: string, agentPolicy: AgentPolicy) => ( - - - - {name || agentPolicy.id} - - - - - - - - + + {name || agentPolicy.id} + ), }, { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/content.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/content.tsx index 40346cde7f50ff..62adad14a028cc 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/content.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/content.tsx @@ -17,7 +17,7 @@ import { SettingsPanel } from './settings_panel'; type ContentProps = PackageInfo & Pick; -const SideNavColumn = styled(LeftColumn)` +const LeftSideColumn = styled(LeftColumn)` /* 🤢🤷 https://www.styled-components.com/docs/faqs#how-can-i-override-styles-with-higher-specificity */ &&& { margin-top: 77px; @@ -30,15 +30,18 @@ const ContentFlexGroup = styled(EuiFlexGroup)` `; export function Content(props: ContentProps) { + const showRightColumn = props.panel !== 'policies'; return ( - - + + - - - + {showRightColumn && ( + + + + )} ); } 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 0e72693db9e2d0..aad8f9701923ef 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 @@ -237,8 +237,7 @@ export function Detail() { return (entries(PanelDisplayNames) .filter(([panelId]) => { return ( - panelId !== 'policies' || - (packageInfoData?.response.status === InstallStatus.installed && false) // Remove `false` when ready to implement policies tab + panelId !== 'policies' || packageInfoData?.response.status === InstallStatus.installed ); }) .map(([panelId, display]) => { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/layout.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/layout.tsx index c3295963847300..cbfab9ac9e5d24 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/layout.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/layout.tsx @@ -6,31 +6,45 @@ import { EuiFlexItem } from '@elastic/eui'; import React, { FunctionComponent, ReactNode } from 'react'; +import { FlexItemGrowSize } from '@elastic/eui/src/components/flex/flex_item'; interface ColumnProps { children?: ReactNode; className?: string; + columnGrow?: FlexItemGrowSize; } -export const LeftColumn: FunctionComponent = ({ children, ...rest }) => { +export const LeftColumn: FunctionComponent = ({ + columnGrow = 2, + children, + ...rest +}) => { return ( - + {children} ); }; -export const CenterColumn: FunctionComponent = ({ children, ...rest }) => { +export const CenterColumn: FunctionComponent = ({ + columnGrow = 9, + children, + ...rest +}) => { return ( - + {children} ); }; -export const RightColumn: FunctionComponent = ({ children, ...rest }) => { +export const RightColumn: FunctionComponent = ({ + columnGrow = 3, + children, + ...rest +}) => { return ( - + {children} ); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/package_policies_panel.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/package_policies_panel.tsx index d97d891ac5e5d7..8609b08c9a7744 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/package_policies_panel.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/package_policies_panel.tsx @@ -4,11 +4,82 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { memo, ReactNode, useCallback, useMemo } from 'react'; import { Redirect } from 'react-router-dom'; +import { + CriteriaWithPagination, + EuiBasicTable, + EuiLink, + EuiTableFieldDataColumnType, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedRelative } from '@kbn/i18n/react'; import { useGetPackageInstallStatus } from '../../hooks'; import { InstallStatus } from '../../../../types'; import { useLink } from '../../../../hooks'; +import { + AGENT_SAVED_OBJECT_TYPE, + PACKAGE_POLICY_SAVED_OBJECT_TYPE, +} from '../../../../../../../common/constants'; +import { useUrlPagination } from '../../../../hooks'; +import { + PackagePolicyAndAgentPolicy, + usePackagePoliciesWithAgentPolicy, +} from './use_package_policies_with_agent_policy'; +import { LinkAndRevision, LinkAndRevisionProps } from '../../../../components'; +import { Persona } from './persona'; + +const IntegrationDetailsLink = memo<{ + packagePolicy: PackagePolicyAndAgentPolicy['packagePolicy']; +}>(({ packagePolicy }) => { + const { getHref } = useLink(); + return ( + + {packagePolicy.name} + + ); +}); + +const AgentPolicyDetailLink = memo<{ + agentPolicyId: string; + revision: LinkAndRevisionProps['revision']; + children: ReactNode; +}>(({ agentPolicyId, revision, children }) => { + const { getHref } = useLink(); + return ( + + {children} + + ); +}); + +const PolicyAgentListLink = memo<{ agentPolicyId: string; children: ReactNode }>( + ({ agentPolicyId, children }) => { + const { getHref } = useLink(); + return ( + + {children} + + ); + } +); interface PackagePoliciesPanelProps { name: string; @@ -18,9 +89,118 @@ export const PackagePoliciesPanel = ({ name, version }: PackagePoliciesPanelProp const { getPath } = useLink(); const getPackageInstallStatus = useGetPackageInstallStatus(); const packageInstallStatus = getPackageInstallStatus(name); + const { pagination, pageSizeOptions, setPagination } = useUrlPagination(); + const { data } = usePackagePoliciesWithAgentPolicy({ + page: pagination.currentPage, + perPage: pagination.pageSize, + kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name: ${name}`, + }); + + const handleTableOnChange = useCallback( + ({ page }: CriteriaWithPagination) => { + setPagination({ + currentPage: page.index + 1, + pageSize: page.size, + }); + }, + [setPagination] + ); + + const columns: Array> = useMemo( + () => [ + { + field: 'packagePolicy.name', + name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.name', { + defaultMessage: 'Integration', + }), + render(_, { packagePolicy }) { + return ; + }, + }, + { + field: 'packagePolicy.description', + name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.description', { + defaultMessage: 'Description', + }), + truncateText: true, + }, + { + field: 'packagePolicy.policy_id', + name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.agentPolicy', { + defaultMessage: 'Agent policy', + }), + truncateText: true, + render(id, { agentPolicy }) { + return ( + + {agentPolicy.name ?? id} + + ); + }, + }, + { + field: '', + name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.agentCount', { + defaultMessage: 'Agents', + }), + truncateText: true, + align: 'right', + width: '8ch', + render({ packagePolicy, agentPolicy }: PackagePolicyAndAgentPolicy) { + return ( + + {agentPolicy?.agents ?? 0} + + ); + }, + }, + { + field: 'packagePolicy.updated_by', + name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.updatedBy', { + defaultMessage: 'Last Updated By', + }), + truncateText: true, + render(updatedBy) { + return ; + }, + }, + { + field: 'packagePolicy.updated_at', + name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.updatedAt', { + defaultMessage: 'Last Updated', + }), + truncateText: true, + render(updatedAt: PackagePolicyAndAgentPolicy['packagePolicy']['updated_at']) { + return ( + + + + ); + }, + }, + ], + [] + ); + // if they arrive at this page and the package is not installed, send them to overview // this happens if they arrive with a direct url or they uninstall while on this tab - if (packageInstallStatus.status !== InstallStatus.installed) + if (packageInstallStatus.status !== InstallStatus.installed) { return ; - return null; + } + + return ( + + ); }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/persona.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/persona.tsx new file mode 100644 index 00000000000000..06b3c7a9a4093c --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/persona.tsx @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { EuiAvatar, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; +import React, { CSSProperties, memo, useCallback } from 'react'; +import { EuiAvatarProps } from '@elastic/eui/src/components/avatar/avatar'; + +const MIN_WIDTH: CSSProperties = { minWidth: 0 }; + +/** + * Shows a user's name along with an avatar. Name is truncated if its wider than the availble space + */ +export const Persona = memo( + ({ name, className, 'data-test-subj': dataTestSubj, title, ...otherAvatarProps }) => { + const getTestId = useCallback( + (suffix) => { + if (dataTestSubj) { + return `${dataTestSubj}-${suffix}`; + } + }, + [dataTestSubj] + ); + return ( + + + + + + + {name} + + + + ); + } +); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/use_package_policies_with_agent_policy.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/use_package_policies_with_agent_policy.ts new file mode 100644 index 00000000000000..d8a9d18e8a21f0 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/epm/screens/detail/use_package_policies_with_agent_policy.ts @@ -0,0 +1,129 @@ +/* + * 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 { useEffect, useMemo, useState } from 'react'; +import { PackagePolicy } from '../../../../../../../common/types/models'; +import { + GetAgentPoliciesResponse, + GetAgentPoliciesResponseItem, +} from '../../../../../../../common/types/rest_spec'; +import { useGetPackagePolicies } from '../../../../hooks/use_request'; +import { + SendConditionalRequestConfig, + useConditionalRequest, +} from '../../../../hooks/use_request/use_request'; +import { agentPolicyRouteService } from '../../../../../../../common/services'; +import { AGENT_POLICY_SAVED_OBJECT_TYPE } from '../../../../../../../common/constants'; +import { GetPackagePoliciesResponse } from '../../../../../../../common/types/rest_spec'; + +export interface PackagePolicyEnriched extends PackagePolicy { + _agentPolicy: GetAgentPoliciesResponseItem | undefined; +} + +export interface PackagePolicyAndAgentPolicy { + packagePolicy: PackagePolicy; + agentPolicy: GetAgentPoliciesResponseItem; +} + +type GetPackagePoliciesWithAgentPolicy = Omit & { + items: PackagePolicyAndAgentPolicy[]; +}; + +/** + * Works similar to `useGetAgentPolicies()`, except that it will add an additional property to + * each package policy named `_agentPolicy` which may hold the Agent Policy associated with the + * given package policy. + * @param query + */ +export const usePackagePoliciesWithAgentPolicy = ( + query: Parameters[0] +): { + isLoading: boolean; + error: Error | null; + data?: GetPackagePoliciesWithAgentPolicy; +} => { + const { + data: packagePoliciesData, + error, + isLoading: isLoadingPackagePolicies, + } = useGetPackagePolicies(query); + + const agentPoliciesFilter = useMemo(() => { + if (!packagePoliciesData?.items.length) { + return ''; + } + + // Build a list of package_policies for which we need Agent Policies for. Since some package + // policies can exist within the same Agent Policy, we don't need to (in some cases) include + // the entire list of package_policy ids. + const includedAgentPolicies = new Set(); + + return `${AGENT_POLICY_SAVED_OBJECT_TYPE}.package_policies: (${packagePoliciesData.items + .filter((packagePolicy) => { + if (includedAgentPolicies.has(packagePolicy.policy_id)) { + return false; + } + includedAgentPolicies.add(packagePolicy.policy_id); + return true; + }) + .map((packagePolicy) => packagePolicy.id) + .join(' or ')}) `; + }, [packagePoliciesData]); + + const { + data: agentPoliciesData, + isLoading: isLoadingAgentPolicies, + } = useConditionalRequest({ + path: agentPolicyRouteService.getListPath(), + method: 'get', + query: { + perPage: 100, + kuery: agentPoliciesFilter, + }, + shouldSendRequest: !!packagePoliciesData?.items.length, + } as SendConditionalRequestConfig); + + const [enrichedData, setEnrichedData] = useState(); + + useEffect(() => { + if (isLoadingPackagePolicies || isLoadingAgentPolicies) { + return; + } + + if (!packagePoliciesData?.items) { + setEnrichedData(undefined); + return; + } + + const agentPoliciesById: Record = {}; + + if (agentPoliciesData?.items) { + for (const agentPolicy of agentPoliciesData.items) { + agentPoliciesById[agentPolicy.id] = agentPolicy; + } + } + + const updatedPackageData: PackagePolicyAndAgentPolicy[] = packagePoliciesData.items.map( + (packagePolicy) => { + return { + packagePolicy, + agentPolicy: agentPoliciesById[packagePolicy.policy_id], + }; + } + ); + + setEnrichedData({ + ...packagePoliciesData, + items: updatedPackageData, + }); + }, [isLoadingAgentPolicies, isLoadingPackagePolicies, packagePoliciesData, agentPoliciesData]); + + return { + data: enrichedData, + error, + isLoading: isLoadingPackagePolicies || isLoadingAgentPolicies, + }; +}; diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index ffb79f10e235c6..9e973a0d4324d3 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -7280,7 +7280,6 @@ "xpack.fleet.agentPolicyList.pageSubtitle": "エージェントポリシーを使用すると、エージェントとエージェントが収集するデータを管理できます。", "xpack.fleet.agentPolicyList.pageTitle": "エージェントポリシー", "xpack.fleet.agentPolicyList.reloadAgentPoliciesButtonText": "再読み込み", - "xpack.fleet.agentPolicyList.revisionNumber": "rev. {revNumber}", "xpack.fleet.agentPolicyList.updatedOnColumnTitle": "最終更新日", "xpack.fleet.agentReassignPolicy.cancelButtonLabel": "キャンセル", "xpack.fleet.agentReassignPolicy.continueButtonLabel": "ポリシーの割り当て", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 08461fba1083ab..c9ca26f145102c 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -7287,7 +7287,6 @@ "xpack.fleet.agentPolicyList.pageSubtitle": "使用代理策略管理代理及其收集的数据。", "xpack.fleet.agentPolicyList.pageTitle": "代理策略", "xpack.fleet.agentPolicyList.reloadAgentPoliciesButtonText": "重新加载", - "xpack.fleet.agentPolicyList.revisionNumber": "修订版 {revNumber}", "xpack.fleet.agentPolicyList.updatedOnColumnTitle": "上次更新时间", "xpack.fleet.agentReassignPolicy.cancelButtonLabel": "取消", "xpack.fleet.agentReassignPolicy.continueButtonLabel": "分配策略",