From 8f98077138d061f863c11327c14ac5abe73052ba Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Tue, 8 Jun 2021 17:11:05 +0200 Subject: [PATCH 01/19] Initial commit, very WIP - added link to the integrations UI instead of add integration in fleet - added a new piece of route state that gets passed to integration from fleet when browsing integrations for a policy - when the integration is being added the page will send the user back to the policy overview instead of back to integrations UI --- .../package_policies_table.tsx | 12 ++++- .../public/applications/integrations/app.tsx | 9 ++-- .../applications/integrations/hooks/index.ts | 1 + .../hooks/use_agent_policy_context.tsx | 42 +++++++++++++++ .../sections/epm/screens/detail/index.tsx | 51 ++++++++++++++----- .../public/types/intra_app_route_state.ts | 5 ++ 6 files changed, 101 insertions(+), 19 deletions(-) create mode 100644 x-pack/plugins/fleet/public/applications/integrations/hooks/use_agent_policy_context.tsx diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx index 9e23fc775a213..7088b7cf1e858 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx @@ -19,10 +19,12 @@ import { EuiText, } from '@elastic/eui'; +import { INTEGRATIONS_PLUGIN_ID } from '../../../../../../../../common'; +import { pagePathGetters } from '../../../../../../../constants'; import type { AgentPolicy, PackagePolicy } from '../../../../../types'; import { PackageIcon, ContextMenuActions } from '../../../../../components'; import { PackagePolicyDeleteProvider, DangerEuiContextMenuItem } from '../../../components'; -import { useCapabilities, useLink } from '../../../../../hooks'; +import { useCapabilities, useLink, useStartServices } from '../../../../../hooks'; import { useAgentPolicyRefresh } from '../../hooks'; interface InMemoryPackagePolicy extends PackagePolicy { @@ -53,6 +55,7 @@ export const PackagePoliciesTable: React.FunctionComponent = ({ ...rest }) => { const { getHref } = useLink(); + const { application } = useStartServices(); const hasWriteCapabilities = useCapabilities().write; const refreshAgentPolicy = useAgentPolicyRefresh(); @@ -255,7 +258,12 @@ export const PackagePoliciesTable: React.FunctionComponent = ({ key="addPackagePolicyButton" isDisabled={!hasWriteCapabilities} iconType="plusInCircle" - href={getHref('add_integration_from_policy', { policyId: agentPolicy.id })} + onClick={() => { + application.navigateToApp(INTEGRATIONS_PLUGIN_ID, { + path: `#${pagePathGetters.integrations_all()[1]}`, + state: { forAgentPolicyId: agentPolicy.id }, + }); + }} > - - {children} - + + + {children} + + diff --git a/x-pack/plugins/fleet/public/applications/integrations/hooks/index.ts b/x-pack/plugins/fleet/public/applications/integrations/hooks/index.ts index 7f758e3c472c1..9e4cdde064e70 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/hooks/index.ts +++ b/x-pack/plugins/fleet/public/applications/integrations/hooks/index.ts @@ -10,3 +10,4 @@ export { useBreadcrumbs } from './use_breadcrumbs'; export { useLinks } from './use_links'; export * from './use_local_search'; export * from './use_package_install'; +export * from './use_agent_policy_context'; diff --git a/x-pack/plugins/fleet/public/applications/integrations/hooks/use_agent_policy_context.tsx b/x-pack/plugins/fleet/public/applications/integrations/hooks/use_agent_policy_context.tsx new file mode 100644 index 0000000000000..52242bc176844 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/integrations/hooks/use_agent_policy_context.tsx @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FunctionComponent } from 'react'; +import React, { createContext, useContext, useRef, useCallback } from 'react'; + +import type { IntegrationsAppBrowseRouteState } from '../../../types'; +import { useIntraAppState } from '../../../hooks'; + +interface AgentPolicyContextValue { + getId(): string | undefined; + clear(): void; +} + +const AgentPolicyContext = createContext({}); + +export const AgentPolicyContextProvider: FunctionComponent = ({ children }) => { + const maybeState = useIntraAppState(); + const ref = useRef(maybeState?.forAgentPolicyId); + + const getId = useCallback(() => { + return ref.current; + }, []); + const clear = useCallback(() => { + ref.current = undefined; + }, []); + return ( + {children} + ); +}; + +export const useAgentPolicyContext = () => { + const ctx = useContext(AgentPolicyContext); + if (!ctx) { + throw new Error('useAgentPolicyContext can only be used inside of AgentPolicyContextProvider'); + } + return ctx; +}; diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx index 68736455b818f..d533579de0d68 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx @@ -37,7 +37,12 @@ import { INTEGRATIONS_ROUTING_PATHS, pagePathGetters, } from '../../../../constants'; -import { useCapabilities, useGetPackageInfoByKey, useLink } from '../../../../hooks'; +import { + useCapabilities, + useGetPackageInfoByKey, + useLink, + useAgentPolicyContext, +} from '../../../../hooks'; import { pkgKeyFromPackageInfo } from '../../../../services'; import type { CreatePackagePolicyRouteState, @@ -79,6 +84,7 @@ function Breadcrumbs({ packageTitle }: { packageTitle: string }) { } export function Detail() { + const { getId: getAgentPolicyId } = useAgentPolicyContext(); const { pkgkey, panel } = useParams(); const { getHref } = useLink(); const hasWriteCapabilites = useCapabilities().write; @@ -204,6 +210,8 @@ export function Detail() { (ev) => { ev.preventDefault(); + const agentPolicyId = getAgentPolicyId(); + // The object below, given to `createHref` is explicitly accessing keys of `location` in order // to ensure that dependencies to this `useCallback` is set correctly (because `location` is mutable) const currentPath = history.createHref({ @@ -211,24 +219,39 @@ export function Detail() { search, hash, }); - const redirectToPath: CreatePackagePolicyRouteState['onSaveNavigateTo'] & - CreatePackagePolicyRouteState['onCancelNavigateTo'] = [ - INTEGRATIONS_PLUGIN_ID, - { - path: currentPath, - }, - ]; - const redirectBackRouteState: CreatePackagePolicyRouteState = { - onSaveNavigateTo: redirectToPath, - onCancelNavigateTo: redirectToPath, - onCancelUrl: currentPath, - }; const path = pagePathGetters.add_integration_to_policy({ pkgkey, ...(integration ? { integration } : {}), })[1]; + let redirectToPath: CreatePackagePolicyRouteState['onSaveNavigateTo'] & + CreatePackagePolicyRouteState['onCancelNavigateTo']; + + if (agentPolicyId) { + redirectToPath = [ + PLUGIN_ID, + { + path: pagePathGetters.policy_details({ + policyId: agentPolicyId, + })[1], + }, + ]; + } else { + redirectToPath = [ + INTEGRATIONS_PLUGIN_ID, + { + path: currentPath, + }, + ]; + } + + const redirectBackRouteState: CreatePackagePolicyRouteState = { + onSaveNavigateTo: redirectToPath, + onCancelNavigateTo: redirectToPath, + onCancelUrl: currentPath, + }; + services.application.navigateToApp(PLUGIN_ID, { // Necessary because of Fleet's HashRouter. Can be changed when // https://github.com/elastic/kibana/issues/96134 is resolved @@ -236,7 +259,7 @@ export function Detail() { state: redirectBackRouteState, }); }, - [history, hash, pathname, search, pkgkey, integration, services.application] + [history, hash, pathname, search, pkgkey, integration, services.application, getAgentPolicyId] ); const headerRightContent = useMemo( diff --git a/x-pack/plugins/fleet/public/types/intra_app_route_state.ts b/x-pack/plugins/fleet/public/types/intra_app_route_state.ts index 74921daa0d2a1..36fd32c2a6584 100644 --- a/x-pack/plugins/fleet/public/types/intra_app_route_state.ts +++ b/x-pack/plugins/fleet/public/types/intra_app_route_state.ts @@ -39,6 +39,11 @@ export interface AgentDetailsReassignPolicyAction { onDoneNavigateTo?: Parameters; } +export interface IntegrationsAppBrowseRouteState { + /** The agent policy that we are browsing integrations for */ + forAgentPolicyId: string; +} + /** * All possible Route states. */ From 03fe7b1b07d31142df6228a1c4bd684d91cbd182 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Wed, 9 Jun 2021 11:26:42 +0200 Subject: [PATCH 02/19] remove unnecessary agent policy clear function --- .../integrations/hooks/use_agent_policy_context.tsx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/integrations/hooks/use_agent_policy_context.tsx b/x-pack/plugins/fleet/public/applications/integrations/hooks/use_agent_policy_context.tsx index 52242bc176844..bfca3a20df329 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/hooks/use_agent_policy_context.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/hooks/use_agent_policy_context.tsx @@ -13,7 +13,6 @@ import { useIntraAppState } from '../../../hooks'; interface AgentPolicyContextValue { getId(): string | undefined; - clear(): void; } const AgentPolicyContext = createContext({}); @@ -25,12 +24,7 @@ export const AgentPolicyContextProvider: FunctionComponent = ({ children }) => { const getId = useCallback(() => { return ref.current; }, []); - const clear = useCallback(() => { - ref.current = undefined; - }, []); - return ( - {children} - ); + return {children}; }; export const useAgentPolicyContext = () => { From af3172d2999ba91d9e4bd24d42d27c408e353777 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Wed, 9 Jun 2021 11:52:13 +0200 Subject: [PATCH 03/19] added # to path so that navigation is correctly handled --- .../integrations/sections/epm/screens/detail/index.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx index d533579de0d68..74c8e648aaafc 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx @@ -232,9 +232,11 @@ export function Detail() { redirectToPath = [ PLUGIN_ID, { - path: pagePathGetters.policy_details({ - policyId: agentPolicyId, - })[1], + path: `#${ + pagePathGetters.policy_details({ + policyId: agentPolicyId, + })[1] + }`, }, ]; } else { From 8edb789e10474c0e1de945491cebc95de11556f7 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Wed, 9 Jun 2021 12:14:29 +0200 Subject: [PATCH 04/19] added logic to read the forward agent policy id --- .../create_package_policy_page/index.tsx | 4 +++- .../step_select_agent_policy.tsx | 12 ++++++++++-- .../sections/epm/screens/detail/index.tsx | 1 + .../fleet/public/types/intra_app_route_state.ts | 2 ++ 4 files changed, 16 insertions(+), 3 deletions(-) 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 6563918a5efb2..ae751f5d92ae7 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 @@ -73,6 +73,7 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { const handleNavigateTo = useNavigateToCallback(); const routeState = useIntraAppState(); const from: CreatePackagePolicyFrom = policyId ? 'policy' : 'package'; + const forwardedAgentPolicyId = from === 'package' ? routeState?.agentPolicyId : undefined; // Agent policy and package info states const [agentPolicy, setAgentPolicy] = useState(); @@ -297,12 +298,13 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { ), - [pkgkey, updatePackageInfo, agentPolicy, updateAgentPolicy] + [pkgkey, updatePackageInfo, agentPolicy, updateAgentPolicy, forwardedAgentPolicyId] ); const ExtensionView = useUIExtension(packagePolicy.package?.name ?? '', 'package-policy-create'); 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 26d47cbff5b86..29f68b34ee645 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 @@ -55,15 +55,23 @@ const AgentPolicyDescriptionColumn = styled(EuiFlexItem)` export const StepSelectAgentPolicy: React.FunctionComponent<{ pkgkey: string; updatePackageInfo: (packageInfo: PackageInfo | undefined) => void; + defaultAgentPolicyId?: string; agentPolicy: AgentPolicy | undefined; updateAgentPolicy: (agentPolicy: AgentPolicy | undefined) => void; setIsLoadingSecondStep: (isLoading: boolean) => void; -}> = ({ pkgkey, updatePackageInfo, agentPolicy, updateAgentPolicy, setIsLoadingSecondStep }) => { +}> = ({ + pkgkey, + updatePackageInfo, + agentPolicy, + updateAgentPolicy, + setIsLoadingSecondStep, + defaultAgentPolicyId, +}) => { const { isReady: isFleetReady } = useFleetStatus(); // Selected agent policy state const [selectedPolicyId, setSelectedPolicyId] = useState( - agentPolicy ? agentPolicy.id : undefined + agentPolicy?.id ?? defaultAgentPolicyId ); const [selectedAgentPolicyError, setSelectedAgentPolicyError] = useState(); diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx index 74c8e648aaafc..f4cde8bef9073 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx @@ -249,6 +249,7 @@ export function Detail() { } const redirectBackRouteState: CreatePackagePolicyRouteState = { + agentPolicyId, onSaveNavigateTo: redirectToPath, onCancelNavigateTo: redirectToPath, onCancelUrl: currentPath, diff --git a/x-pack/plugins/fleet/public/types/intra_app_route_state.ts b/x-pack/plugins/fleet/public/types/intra_app_route_state.ts index 36fd32c2a6584..fd3f4189faf85 100644 --- a/x-pack/plugins/fleet/public/types/intra_app_route_state.ts +++ b/x-pack/plugins/fleet/public/types/intra_app_route_state.ts @@ -13,6 +13,8 @@ import type { PackagePolicy } from './'; * Supported routing state for the create package policy page routes */ export interface CreatePackagePolicyRouteState { + /** Optionally specify which agent policy we should default to */ + agentPolicyId?: string; /** On a successful save of the package policy, use navigate to the given app */ onSaveNavigateTo?: | Parameters From e1708bf516bdebb15ea2a4439d092a92090fade3 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Wed, 9 Jun 2021 14:21:36 +0200 Subject: [PATCH 05/19] remove inline select integration package from fleet add integration --- .../create_package_policy_page/index.tsx | 56 ++--- .../step_select_package.tsx | 198 ------------------ 2 files changed, 20 insertions(+), 234 deletions(-) delete mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_select_package.tsx 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 ae751f5d92ae7..284831cd12493 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 @@ -49,7 +49,6 @@ import { CreatePackagePolicyPageLayout } from './components'; import type { CreatePackagePolicyFrom, PackagePolicyFormState } from './types'; import type { PackagePolicyValidationResults } from './services'; import { validatePackagePolicy, validationHasErrors } from './services'; -import { StepSelectPackage } from './step_select_package'; import { StepSelectAgentPolicy } from './step_select_agent_policy'; import { StepConfigurePackagePolicy } from './step_configure_package'; import { StepDefinePackagePolicy } from './step_define_package_policy'; @@ -59,6 +58,10 @@ const StepsWithLessPadding = styled(EuiSteps)` padding-bottom: ${(props) => props.theme.eui.paddingSizes.m}; } `; +interface RouteParameters { + policyId: string; + pkgkey: string; +} export const CreatePackagePolicyPage: React.FunctionComponent = () => { const { notifications } = useStartServices(); @@ -66,17 +69,17 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { agents: { enabled: isFleetEnabled }, } = useConfig(); const { - params: { policyId, pkgkey }, - } = useRouteMatch<{ policyId: string; pkgkey: string }>(); + params: { policyId: routeParamsAgentPolicyId, pkgkey }, + } = useRouteMatch(); const { getHref, getPath } = useLink(); const history = useHistory(); const handleNavigateTo = useNavigateToCallback(); const routeState = useIntraAppState(); - const from: CreatePackagePolicyFrom = policyId ? 'policy' : 'package'; - const forwardedAgentPolicyId = from === 'package' ? routeState?.agentPolicyId : undefined; + const from: CreatePackagePolicyFrom = routeParamsAgentPolicyId ? 'policy' : 'package'; + const policyId = from === 'policy' ? routeParamsAgentPolicyId : routeState?.agentPolicyId; // Agent policy and package info states - const [agentPolicy, setAgentPolicy] = useState(); + const [agentPolicy, setAgentPolicy] = useState(); const [packageInfo, setPackageInfo] = useState(); const [isLoadingSecondStep, setIsLoadingSecondStep] = useState(false); @@ -216,7 +219,7 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { return routeState.onCancelUrl; } return from === 'policy' - ? getHref('policy_details', { policyId: agentPolicyId || policyId }) + ? getHref('policy_details', { policyId: agentPolicyId || policyId! }) : getHref('integration_details_overview', { pkgkey }); }, [agentPolicyId, policyId, from, getHref, pkgkey, routeState]); @@ -256,7 +259,8 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { : routeState.onSaveNavigateTo ); } else { - history.push(getPath('policy_details', { policyId: agentPolicy?.id || policyId })); + // Assume agentPolicy has been set if we get this far since the form validity depends on it + history.push(getPath('policy_details', { policyId: agentPolicy?.id! || policyId! })); } notifications.toasts.addSuccess({ @@ -298,30 +302,17 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { ), - [pkgkey, updatePackageInfo, agentPolicy, updateAgentPolicy, forwardedAgentPolicyId] + [pkgkey, updatePackageInfo, agentPolicy, updateAgentPolicy, policyId] ); const ExtensionView = useUIExtension(packagePolicy.package?.name ?? '', 'package-policy-create'); - const stepSelectPackage = useMemo( - () => ( - - ), - [policyId, updateAgentPolicy, packageInfo, updatePackageInfo] - ); - const stepConfigurePackagePolicy = useMemo( () => isLoadingSecondStep ? ( @@ -372,19 +363,6 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { ); const steps: EuiStepProps[] = [ - from === 'package' - ? { - title: i18n.translate('xpack.fleet.createPackagePolicy.stepSelectAgentPolicyTitle', { - defaultMessage: 'Select an agent policy', - }), - children: stepSelectAgentPolicy, - } - : { - title: i18n.translate('xpack.fleet.createPackagePolicy.stepSelectPackageTitle', { - defaultMessage: 'Select an integration', - }), - children: stepSelectPackage, - }, { title: i18n.translate('xpack.fleet.createPackagePolicy.stepConfigurePackagePolicyTitle', { defaultMessage: 'Configure integration', @@ -393,6 +371,12 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { 'data-test-subj': 'dataCollectionSetupStep', children: stepConfigurePackagePolicy, }, + { + title: i18n.translate('xpack.fleet.createPackagePolicy.stepSelectAgentPolicyTitle', { + defaultMessage: 'Select an agent policy', + }), + children: stepSelectAgentPolicy, + }, ]; return ( diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_select_package.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_select_package.tsx deleted file mode 100644 index 50c63274b5e85..0000000000000 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/step_select_package.tsx +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useEffect, useState, Fragment } from 'react'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiFlexGroup, EuiFlexItem, EuiSelectable, EuiSpacer } from '@elastic/eui'; - -import { Error, PackageIcon } from '../../../components'; -import type { AgentPolicy, PackageInfo, PackagePolicy, GetPackagesResponse } from '../../../types'; -import { - useGetOneAgentPolicy, - useGetPackages, - useGetLimitedPackages, - sendGetPackageInfoByKey, -} from '../../../hooks'; -import { pkgKeyFromPackageInfo } from '../../../services'; - -export const StepSelectPackage: React.FunctionComponent<{ - agentPolicyId: string; - updateAgentPolicy: (agentPolicy: AgentPolicy | undefined) => void; - packageInfo?: PackageInfo; - updatePackageInfo: (packageInfo: PackageInfo | undefined) => void; - setIsLoadingSecondStep: (isLoading: boolean) => void; -}> = ({ - agentPolicyId, - updateAgentPolicy, - packageInfo, - updatePackageInfo, - setIsLoadingSecondStep, -}) => { - // Selected package state - const [selectedPkgKey, setSelectedPkgKey] = useState( - packageInfo ? pkgKeyFromPackageInfo(packageInfo) : undefined - ); - const [selectedPkgError, setSelectedPkgError] = useState(); - - // Fetch agent policy info - const { - data: agentPolicyData, - error: agentPolicyError, - isLoading: isAgentPoliciesLoading, - } = useGetOneAgentPolicy(agentPolicyId); - - // Fetch packages info - // Filter out limited packages already part of selected agent policy - const [packages, setPackages] = useState([]); - const { - data: packagesData, - error: packagesError, - isLoading: isPackagesLoading, - } = useGetPackages(); - const { - data: limitedPackagesData, - isLoading: isLimitedPackagesLoading, - } = useGetLimitedPackages(); - useEffect(() => { - if (packagesData?.response && limitedPackagesData?.response && agentPolicyData?.item) { - const allPackages = packagesData.response; - const limitedPackages = limitedPackagesData.response; - const usedLimitedPackages = (agentPolicyData.item.package_policies as PackagePolicy[]) - .map((packagePolicy) => packagePolicy.package?.name || '') - .filter((pkgName) => limitedPackages.includes(pkgName)); - setPackages(allPackages.filter((pkg) => !usedLimitedPackages.includes(pkg.name))); - } - }, [packagesData, limitedPackagesData, agentPolicyData]); - - // Update parent agent policy state - useEffect(() => { - if (agentPolicyData && agentPolicyData.item) { - updateAgentPolicy(agentPolicyData.item); - } - }, [agentPolicyData, updateAgentPolicy]); - - // Update parent selected package state - useEffect(() => { - const fetchPackageInfo = async () => { - if (selectedPkgKey) { - setIsLoadingSecondStep(true); - const { data, error } = await sendGetPackageInfoByKey(selectedPkgKey); - if (error) { - setSelectedPkgError(error); - updatePackageInfo(undefined); - } else if (data && data.response) { - setSelectedPkgError(undefined); - updatePackageInfo(data.response); - } - setIsLoadingSecondStep(false); - } else { - setSelectedPkgError(undefined); - updatePackageInfo(undefined); - } - }; - if (!packageInfo || selectedPkgKey !== pkgKeyFromPackageInfo(packageInfo)) { - fetchPackageInfo(); - } - }, [selectedPkgKey, packageInfo, updatePackageInfo, setIsLoadingSecondStep]); - - // Display agent policy error if there is one - if (agentPolicyError) { - return ( - - } - error={agentPolicyError} - /> - ); - } - - // Display packages list error if there is one - if (packagesError) { - return ( - - } - error={packagesError} - /> - ); - } - - return ( - - - { - const pkgkey = `${name}-${version}`; - return { - label: title || name, - key: pkgkey, - prepend: , - checked: selectedPkgKey === pkgkey ? 'on' : undefined, - }; - })} - listProps={{ - bordered: true, - }} - searchProps={{ - placeholder: i18n.translate( - 'xpack.fleet.createPackagePolicy.stepSelectPackage.filterPackagesInputPlaceholder', - { - defaultMessage: 'Search for integrations', - } - ), - }} - height={240} - onChange={(options) => { - const selectedOption = options.find((option) => option.checked === 'on'); - if (selectedOption) { - if (selectedOption.key !== selectedPkgKey) { - setSelectedPkgKey(selectedOption.key); - } - } else { - setSelectedPkgKey(undefined); - } - }} - > - {(list, search) => ( - - {search} - - {list} - - )} - - - {/* Display selected package error if there is one */} - {selectedPkgError ? ( - - - } - error={selectedPkgError} - /> - - ) : null} - - ); -}; From 3a058996d86e846710b3b1a6b438320c66f31334 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Wed, 9 Jun 2021 14:57:41 +0200 Subject: [PATCH 06/19] updated toast notification --- .../agent_policy/create_package_policy_page/index.tsx | 7 +++++++ 1 file changed, 7 insertions(+) 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 284831cd12493..4444ca2c5904f 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 @@ -278,6 +278,13 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { agentPolicyName: agentPolicy.name, }, }) + : routeState?.agentPolicyId && agentPolicy && agentCount === 0 + ? i18n.translate('xpack.fleet.createPackagePolicy.addAgentNextNotification', { + defaultMessage: `The policy has been updated. Add an agent to the '{agentPolicyName}' policy to deploy this policy.`, + values: { + agentPolicyName: agentPolicy.name, + }, + }) : undefined, 'data-test-subj': 'packagePolicyCreateSuccessToast', }); From bc88a5ff433e11dbce202b30b9860a0c5913564b Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 10 Jun 2021 14:49:18 +0200 Subject: [PATCH 07/19] using query parameter to pass policy id back to create policy package page --- .../create_package_policy_page/index.tsx | 13 ++++++---- .../sections/epm/screens/detail/index.tsx | 24 ++++++++++++++----- .../fleet/public/constants/page_paths.ts | 7 +++--- .../public/types/intra_app_route_state.ts | 2 -- 4 files changed, 31 insertions(+), 15 deletions(-) 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 be0dc81746109..083c14c90b03b 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 @@ -7,7 +7,7 @@ import type { ReactEventHandler } from 'react'; import React, { useState, useEffect, useMemo, useCallback } from 'react'; -import { useRouteMatch, useHistory } from 'react-router-dom'; +import { useRouteMatch, useHistory, useLocation } from 'react-router-dom'; import styled from 'styled-components'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -62,6 +62,7 @@ const StepsWithLessPadding = styled(EuiSteps)` interface AddToPolicyParams { pkgkey: string; integration?: string; + policyId?: string; } interface AddFromPolicyParams { @@ -80,6 +81,10 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { const routeState = useIntraAppState(); const from: CreatePackagePolicyFrom = 'policyId' in params ? 'policy' : 'package'; + const { search } = useLocation(); + const queryParams = useMemo(() => new URLSearchParams(search), [search]); + const policyId = useMemo(() => queryParams.get('policyId'), [queryParams]); + // Agent policy and package info states const [agentPolicy, setAgentPolicy] = useState(); const [packageInfo, setPackageInfo] = useState(); @@ -285,7 +290,7 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { agentPolicyName: agentPolicy.name, }, }) - : routeState?.agentPolicyId && agentPolicy && agentCount === 0 + : (params as AddToPolicyParams)?.policyId && agentPolicy && agentCount === 0 ? i18n.translate('xpack.fleet.createPackagePolicy.addAgentNextNotification', { defaultMessage: `The policy has been updated. Add an agent to the '{agentPolicyName}' policy to deploy this policy.`, values: { @@ -343,13 +348,13 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { ), - [params, updatePackageInfo, agentPolicy, updateAgentPolicy] + [params, updatePackageInfo, agentPolicy, updateAgentPolicy, policyId] ); const ExtensionView = useUIExtension(packagePolicy.package?.name ?? '', 'package-policy-create'); diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx index f4cde8bef9073..99a29a8194f9b 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx @@ -93,6 +93,7 @@ export function Detail() { const queryParams = useMemo(() => new URLSearchParams(search), [search]); const integration = useMemo(() => queryParams.get('integration'), [queryParams]); const services = useStartServices(); + const agentPolicyIdFromContext = getAgentPolicyId(); // Package info state const [packageInfo, setPackageInfo] = useState(null); @@ -210,8 +211,6 @@ export function Detail() { (ev) => { ev.preventDefault(); - const agentPolicyId = getAgentPolicyId(); - // The object below, given to `createHref` is explicitly accessing keys of `location` in order // to ensure that dependencies to this `useCallback` is set correctly (because `location` is mutable) const currentPath = history.createHref({ @@ -223,18 +222,19 @@ export function Detail() { const path = pagePathGetters.add_integration_to_policy({ pkgkey, ...(integration ? { integration } : {}), + ...(agentPolicyIdFromContext ? { agentPolicyId: agentPolicyIdFromContext } : {}), })[1]; let redirectToPath: CreatePackagePolicyRouteState['onSaveNavigateTo'] & CreatePackagePolicyRouteState['onCancelNavigateTo']; - if (agentPolicyId) { + if (agentPolicyIdFromContext) { redirectToPath = [ PLUGIN_ID, { path: `#${ pagePathGetters.policy_details({ - policyId: agentPolicyId, + policyId: agentPolicyIdFromContext, })[1] }`, }, @@ -249,7 +249,6 @@ export function Detail() { } const redirectBackRouteState: CreatePackagePolicyRouteState = { - agentPolicyId, onSaveNavigateTo: redirectToPath, onCancelNavigateTo: redirectToPath, onCancelUrl: currentPath, @@ -262,7 +261,16 @@ export function Detail() { state: redirectBackRouteState, }); }, - [history, hash, pathname, search, pkgkey, integration, services.application, getAgentPolicyId] + [ + history, + hash, + pathname, + search, + pkgkey, + integration, + services.application, + agentPolicyIdFromContext, + ] ); const headerRightContent = useMemo( @@ -310,6 +318,9 @@ export function Detail() { href={getHref('add_integration_to_policy', { pkgkey, ...(integration ? { integration } : {}), + ...(agentPolicyIdFromContext + ? { agentPolicyId: agentPolicyIdFromContext } + : {}), })} onClick={handleAddIntegrationPolicyClick} data-test-subj="addIntegrationPolicyButton" @@ -351,6 +362,7 @@ export function Detail() { packageInstallStatus, pkgkey, updateAvailable, + agentPolicyIdFromContext, ] ); diff --git a/x-pack/plugins/fleet/public/constants/page_paths.ts b/x-pack/plugins/fleet/public/constants/page_paths.ts index 4ff71cf162e22..a8f356de47dc6 100644 --- a/x-pack/plugins/fleet/public/constants/page_paths.ts +++ b/x-pack/plugins/fleet/public/constants/page_paths.ts @@ -48,7 +48,7 @@ export const FLEET_ROUTING_PATHS = { policy_details: '/policies/:policyId/:tabId?', policy_details_settings: '/policies/:policyId/settings', add_integration_from_policy: '/policies/:policyId/add-integration', - add_integration_to_policy: '/integrations/:pkgkey/add-integration/:integration?', + add_integration_to_policy: '/integrations/:pkgkey/add-integration/:integration?/:policyId?', edit_integration: '/policies/:policyId/edit-integration/:packagePolicyId', fleet: '/fleet', fleet_agent_list: '/fleet/agents', @@ -111,9 +111,10 @@ export const pagePathGetters: { FLEET_BASE_PATH, `/policies/${policyId}/add-integration`, ], - add_integration_to_policy: ({ pkgkey, integration }) => [ + add_integration_to_policy: ({ pkgkey, integration, agentPolicyId }) => [ FLEET_BASE_PATH, - `/integrations/${pkgkey}/add-integration${integration ? `/${integration}` : ''}`, + // prettier-ignore + `/integrations/${pkgkey}/add-integration${integration ? `/${integration}` : ''}${agentPolicyId ? `?policyId=${agentPolicyId}` : ''}`, ], edit_integration: ({ policyId, packagePolicyId }) => [ FLEET_BASE_PATH, diff --git a/x-pack/plugins/fleet/public/types/intra_app_route_state.ts b/x-pack/plugins/fleet/public/types/intra_app_route_state.ts index fd3f4189faf85..36fd32c2a6584 100644 --- a/x-pack/plugins/fleet/public/types/intra_app_route_state.ts +++ b/x-pack/plugins/fleet/public/types/intra_app_route_state.ts @@ -13,8 +13,6 @@ import type { PackagePolicy } from './'; * Supported routing state for the create package policy page routes */ export interface CreatePackagePolicyRouteState { - /** Optionally specify which agent policy we should default to */ - agentPolicyId?: string; /** On a successful save of the package policy, use navigate to the given app */ onSaveNavigateTo?: | Parameters From b08fdd990b41edafc314decd814c745190bf5489 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 10 Jun 2021 14:52:24 +0200 Subject: [PATCH 08/19] removed policyId from route path --- x-pack/plugins/fleet/public/constants/page_paths.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/fleet/public/constants/page_paths.ts b/x-pack/plugins/fleet/public/constants/page_paths.ts index a8f356de47dc6..3c9c0e5759615 100644 --- a/x-pack/plugins/fleet/public/constants/page_paths.ts +++ b/x-pack/plugins/fleet/public/constants/page_paths.ts @@ -48,7 +48,7 @@ export const FLEET_ROUTING_PATHS = { policy_details: '/policies/:policyId/:tabId?', policy_details_settings: '/policies/:policyId/settings', add_integration_from_policy: '/policies/:policyId/add-integration', - add_integration_to_policy: '/integrations/:pkgkey/add-integration/:integration?/:policyId?', + add_integration_to_policy: '/integrations/:pkgkey/add-integration/:integration?', edit_integration: '/policies/:policyId/edit-integration/:packagePolicyId', fleet: '/fleet', fleet_agent_list: '/fleet/agents', From 67edafe70d51eafda7f1cdb35aa5d27d75f081ec Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 10 Jun 2021 14:53:50 +0200 Subject: [PATCH 09/19] fix type issue --- .../sections/agent_policy/create_package_policy_page/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 083c14c90b03b..7e17e58493257 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 @@ -83,7 +83,7 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { const { search } = useLocation(); const queryParams = useMemo(() => new URLSearchParams(search), [search]); - const policyId = useMemo(() => queryParams.get('policyId'), [queryParams]); + const policyId = useMemo(() => queryParams.get('policyId') ?? undefined, [queryParams]); // Agent policy and package info states const [agentPolicy, setAgentPolicy] = useState(); From bdbce4dac3c7a8e93eadc72859256d40bafaa905 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 10 Jun 2021 16:02:52 +0200 Subject: [PATCH 10/19] updated the select agent field layout per the designs --- .../create_package_policy_page/index.tsx | 2 +- .../step_select_agent_policy.tsx | 188 ++++++++++-------- 2 files changed, 108 insertions(+), 82 deletions(-) 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 7e17e58493257..2b3a2d7bda95e 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 @@ -422,7 +422,7 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { }, { title: i18n.translate('xpack.fleet.createPackagePolicy.stepSelectAgentPolicyTitle', { - defaultMessage: 'Select an agent policy', + defaultMessage: 'Apply to agent policy', }), children: stepSelectAgentPolicy, }, 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 29f68b34ee645..912fef6d588fa 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 @@ -17,6 +17,9 @@ import { EuiTextColor, EuiPortal, EuiFormRow, + EuiDescribedFormGroup, + EuiTitle, + EuiText, EuiLink, } from '@elastic/eui'; @@ -32,7 +35,7 @@ import { } from '../../../hooks'; import { CreateAgentPolicyFlyout } from '../list_page/components'; -const AgentPolicyWrapper = styled(EuiFormRow)` +const AgentPolicyFormRow = styled(EuiFormRow)` .euiFormRow__label { width: 100%; } @@ -231,95 +234,118 @@ export const StepSelectAgentPolicy: React.FunctionComponent<{ ) : null} - - + +

- - -
- setIsCreateAgentPolicyFlyoutOpen(true)} - > - - -
-
- +

+ } - helpText={ - isFleetReady && selectedPolicyId ? ( - - ) : null + description={ + +

+ +

+
} > - ) => { - return ( - - - {option.label} - - - - {agentPoliciesById[option.value!].description} - - - {isFleetReady ? ( - - - + label={ + + + + + +
+ setIsCreateAgentPolicyFlyoutOpen(true)} + > + + +
+
+
+ } + helpText={ + isFleetReady && selectedPolicyId ? ( + + ) : null + } + > + ) => { + return ( + + + {option.label} + + + + {agentPoliciesById[option.value!].description} -
- ) : null} -
- ); - }} - selectedOptions={selectedAgentPolicyOption ? [selectedAgentPolicyOption] : []} - onChange={(options) => { - const selectedOption = options[0] || undefined; - if (selectedOption) { - if (selectedOption.value !== selectedPolicyId) { - setSelectedPolicyId(selectedOption.value); + + {isFleetReady ? ( + + + + + + ) : null} +
+ ); + }} + selectedOptions={selectedAgentPolicyOption ? [selectedAgentPolicyOption] : []} + onChange={(options) => { + const selectedOption = options[0] || undefined; + if (selectedOption) { + if (selectedOption.value !== selectedPolicyId) { + setSelectedPolicyId(selectedOption.value); + } + } else { + setSelectedPolicyId(undefined); } - } else { - setSelectedPolicyId(undefined); - } - }} - /> - + }} + /> + + {/* Display selected agent policy error if there is one */} {selectedAgentPolicyError ? ( From 1c22dfd49088b8d09e0d43b5ded8c4782ae136ab Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 10 Jun 2021 17:55:44 +0200 Subject: [PATCH 11/19] simpified item rendering in combobox and fixed combobox z-index issue --- .../create_package_policy_page/index.tsx | 2 +- .../step_select_agent_policy.tsx | 44 +------------------ 2 files changed, 2 insertions(+), 44 deletions(-) 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 2b3a2d7bda95e..3dedb7f66bd37 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 @@ -451,7 +451,7 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { )} - + {!isLoadingSecondStep && agentPolicy && packageInfo && formState === 'INVALID' ? ( 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 912fef6d588fa..e2f5a7249ff0a 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 @@ -14,7 +14,6 @@ import { EuiFlexGroup, EuiFlexItem, EuiComboBox, - EuiTextColor, EuiPortal, EuiFormRow, EuiDescribedFormGroup, @@ -41,20 +40,6 @@ const AgentPolicyFormRow = styled(EuiFormRow)` } `; -// Custom styling for drop down list items due to: -// 1) the max-width and overflow properties is added to prevent long agent policy -// names/descriptions from overflowing the flex items -// 2) max-width is built from the grow property on the flex items because the value -// changes based on if Fleet is enabled/setup or not -const AgentPolicyNameColumn = styled(EuiFlexItem)` - max-width: ${(props) => `${((props.grow as number) / 9) * 100}%`}; - overflow: hidden; -`; -const AgentPolicyDescriptionColumn = styled(EuiFlexItem)` - max-width: ${(props) => `${((props.grow as number) / 9) * 100}%`}; - overflow: hidden; -`; - export const StepSelectAgentPolicy: React.FunctionComponent<{ pkgkey: string; updatePackageInfo: (packageInfo: PackageInfo | undefined) => void; @@ -285,7 +270,7 @@ export const StepSelectAgentPolicy: React.FunctionComponent<{ isFleetReady && selectedPolicyId ? ( ) => { - return ( - - - {option.label} - - - - {agentPoliciesById[option.value!].description} - - - {isFleetReady ? ( - - - - - - ) : null} - - ); - }} selectedOptions={selectedAgentPolicyOption ? [selectedAgentPolicyOption] : []} onChange={(options) => { const selectedOption = options[0] || undefined; From 7021bfb050075adbac428f2e8ddc7cbe0b4a47e9 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 10 Jun 2021 17:57:19 +0200 Subject: [PATCH 12/19] added comment --- .../sections/agent_policy/create_package_policy_page/index.tsx | 1 + 1 file changed, 1 insertion(+) 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 3dedb7f66bd37..67387afbc7696 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 @@ -451,6 +451,7 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { )} + {/* Note: we set a relatively _low_ zIndex value here to account for EuiComboBox popover that might appear under the bottom bar */} From 6e64190a8b1c105a5e286fee98a161a6951779ad Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 10 Jun 2021 18:03:04 +0200 Subject: [PATCH 13/19] fix types and i18n --- .../integrations/hooks/use_agent_policy_context.tsx | 2 +- x-pack/plugins/translations/translations/ja-JP.json | 5 ----- x-pack/plugins/translations/translations/zh-CN.json | 5 ----- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/integrations/hooks/use_agent_policy_context.tsx b/x-pack/plugins/fleet/public/applications/integrations/hooks/use_agent_policy_context.tsx index bfca3a20df329..859db79ad159b 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/hooks/use_agent_policy_context.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/hooks/use_agent_policy_context.tsx @@ -15,7 +15,7 @@ interface AgentPolicyContextValue { getId(): string | undefined; } -const AgentPolicyContext = createContext({}); +const AgentPolicyContext = createContext({ getId: () => undefined }); export const AgentPolicyContextProvider: FunctionComponent = ({ children }) => { const maybeState = useIntraAppState(); diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 8066ca178d34f..417f2a18e8a3f 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -8998,11 +8998,6 @@ "xpack.fleet.createPackagePolicy.stepConfigure.toggleAdvancedOptionsButtonText": "高度なオプション", "xpack.fleet.createPackagePolicy.stepConfigurePackagePolicyTitle": "統合の構成", "xpack.fleet.createPackagePolicy.stepSelectAgentPolicyTitle": "エージェントポリシーを選択", - "xpack.fleet.createPackagePolicy.stepSelectPackage.errorLoadingPackagesTitle": "統合の読み込みエラー", - "xpack.fleet.createPackagePolicy.stepSelectPackage.errorLoadingPolicyTitle": "エージェントポリシー情報の読み込みエラー", - "xpack.fleet.createPackagePolicy.stepSelectPackage.errorLoadingSelectedPackageTitle": "選択した統合の読み込みエラー", - "xpack.fleet.createPackagePolicy.stepSelectPackage.filterPackagesInputPlaceholder": "統合を検索", - "xpack.fleet.createPackagePolicy.stepSelectPackageTitle": "統合を選択", "xpack.fleet.createPackagePolicy.StepSelectPolicy.addButton": "エージェントポリシーを作成", "xpack.fleet.createPackagePolicy.StepSelectPolicy.agentPolicyLabel": "エージェントポリシー", "xpack.fleet.createPackagePolicy.StepSelectPolicy.agentPolicyPlaceholderText": "この統合を追加するエージェントポリシーを選択", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 33f5d4aceb51c..6d2ca079dfb27 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -9079,11 +9079,6 @@ "xpack.fleet.createPackagePolicy.stepConfigure.toggleAdvancedOptionsButtonText": "高级选项", "xpack.fleet.createPackagePolicy.stepConfigurePackagePolicyTitle": "配置集成", "xpack.fleet.createPackagePolicy.stepSelectAgentPolicyTitle": "选择代理策略", - "xpack.fleet.createPackagePolicy.stepSelectPackage.errorLoadingPackagesTitle": "加载集成时出错", - "xpack.fleet.createPackagePolicy.stepSelectPackage.errorLoadingPolicyTitle": "加载代理策略信息时出错", - "xpack.fleet.createPackagePolicy.stepSelectPackage.errorLoadingSelectedPackageTitle": "加载选定集成时出错", - "xpack.fleet.createPackagePolicy.stepSelectPackage.filterPackagesInputPlaceholder": "搜索集成", - "xpack.fleet.createPackagePolicy.stepSelectPackageTitle": "选择集成", "xpack.fleet.createPackagePolicy.StepSelectPolicy.addButton": "创建代理策略", "xpack.fleet.createPackagePolicy.StepSelectPolicy.agentPolicyAgentsCountText": "{count, plural, other {# 个代理}}已注册", "xpack.fleet.createPackagePolicy.StepSelectPolicy.agentPolicyAgentsDescriptionText": "{count, plural, other {# 个代理}}已注册到选定代理策略。", From 91878bd77d8272178ce6c9ec8aaaebc6a8bc5fd5 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 10 Jun 2021 18:14:30 +0200 Subject: [PATCH 14/19] updated icon and removed unused i18n --- .../components/package_policies/package_policies_table.tsx | 2 +- x-pack/plugins/translations/translations/zh-CN.json | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx index ef8499ca4b416..49af14b7234fa 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx @@ -196,7 +196,7 @@ export const PackagePoliciesTable: React.FunctionComponent = ({ { application.navigateToApp(INTEGRATIONS_PLUGIN_ID, { path: `#${pagePathGetters.integrations_all()[1]}`, diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 6d2ca079dfb27..6af2cdd4c4e07 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -9080,7 +9080,6 @@ "xpack.fleet.createPackagePolicy.stepConfigurePackagePolicyTitle": "配置集成", "xpack.fleet.createPackagePolicy.stepSelectAgentPolicyTitle": "选择代理策略", "xpack.fleet.createPackagePolicy.StepSelectPolicy.addButton": "创建代理策略", - "xpack.fleet.createPackagePolicy.StepSelectPolicy.agentPolicyAgentsCountText": "{count, plural, other {# 个代理}}已注册", "xpack.fleet.createPackagePolicy.StepSelectPolicy.agentPolicyAgentsDescriptionText": "{count, plural, other {# 个代理}}已注册到选定代理策略。", "xpack.fleet.createPackagePolicy.StepSelectPolicy.agentPolicyLabel": "代理策略", "xpack.fleet.createPackagePolicy.StepSelectPolicy.agentPolicyPlaceholderText": "选择要将此集成添加到的代理策略", From 546a0fa99ace8d23f00401db0dbd35beace5a546 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Mon, 14 Jun 2021 11:11:40 +0200 Subject: [PATCH 15/19] refactor to using styled components for cusomt z-index styling --- .../agent_policy/create_package_policy_page/index.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) 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 67387afbc7696..41a69f62de04e 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 @@ -59,6 +59,11 @@ const StepsWithLessPadding = styled(EuiSteps)` } `; +const CustomEuiBottomBar = styled(EuiBottomBar)` + // Set a relatively _low_ z-index value here to account for EuiComboBox popover that might appear under the bottom bar + z-index: 50; +`; + interface AddToPolicyParams { pkgkey: string; integration?: string; @@ -451,8 +456,7 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { )} - {/* Note: we set a relatively _low_ zIndex value here to account for EuiComboBox popover that might appear under the bottom bar */} - + {!isLoadingSecondStep && agentPolicy && packageInfo && formState === 'INVALID' ? ( @@ -497,7 +501,7 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { - + ); }; From 5001d92566a32b980fc7f2483369b399582567f4 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Mon, 14 Jun 2021 11:35:56 +0200 Subject: [PATCH 16/19] attempt to fix integration test --- .../test/functional/page_objects/synthetics_integration_page.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/test/functional/page_objects/synthetics_integration_page.ts b/x-pack/test/functional/page_objects/synthetics_integration_page.ts index 69ae3f43d26f2..818ae0a493508 100644 --- a/x-pack/test/functional/page_objects/synthetics_integration_page.ts +++ b/x-pack/test/functional/page_objects/synthetics_integration_page.ts @@ -85,6 +85,7 @@ export function SyntheticsIntegrationPageProvider({ */ async fillTextInputByTestSubj(testSubj: string, value: string) { const field = await testSubjects.find(testSubj, 5000); + await field.scrollIntoViewIfNecessary(); await field.click(); await field.clearValue(); await field.type(value); From 5d49fd45ecace4b88e1f7c3ca3655f1dddb23102 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Mon, 14 Jun 2021 14:40:11 +0200 Subject: [PATCH 17/19] added scroll functionality for dealing with fixed footers that might be obstructing content --- .../scroll_into_view_if_necessary.js | 9 ++++++++- .../web_element_wrapper/web_element_wrapper.ts | 15 +++++++++++++-- .../create_package_policy_page/index.tsx | 14 +++++++------- .../page_objects/synthetics_integration_page.ts | 3 ++- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/test/functional/services/lib/web_element_wrapper/scroll_into_view_if_necessary.js b/test/functional/services/lib/web_element_wrapper/scroll_into_view_if_necessary.js index 88a6ad0e3ab15..ac5e64696b7fd 100644 --- a/test/functional/services/lib/web_element_wrapper/scroll_into_view_if_necessary.js +++ b/test/functional/services/lib/web_element_wrapper/scroll_into_view_if_necessary.js @@ -27,7 +27,7 @@ * SOFTWARE. */ -export function scrollIntoViewIfNecessary(target, fixedHeaderHeight) { +export function scrollIntoViewIfNecessary(target, fixedHeaderHeight, fixedFooterHeight) { var rootScroller = document.scrollingElement || document.documentElement; if (!rootScroller) { throw new Error('Unable to find document.scrollingElement or document.documentElement'); @@ -63,4 +63,11 @@ export function scrollIntoViewIfNecessary(target, fixedHeaderHeight) { if (additionalScrollNecessary > 0) { rootScroller.scrollTop = rootScroller.scrollTop - additionalScrollNecessary; } + + if (fixedFooterHeight) { + var bottomOfVisibility = viewportHeight - fixedFooterHeight; + if (bottomOfVisibility < boundingRect.top) { + rootScroller.scrollTop = rootScroller.scrollTop - boundingRect.height; + } + } } diff --git a/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts b/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts index 148c21ffac191..4b164402bfb70 100644 --- a/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts +++ b/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts @@ -692,11 +692,22 @@ export class WebElementWrapper { * @nonstandard * @return {Promise} */ - public async scrollIntoViewIfNecessary(topOffset?: number): Promise { + public async scrollIntoViewIfNecessary( + topOffsetOrOptions?: number | { topOffset?: number; bottomOffset?: number } + ): Promise { + let topOffset: undefined | number; + let bottomOffset: undefined | number; + if (typeof topOffsetOrOptions === 'number') { + topOffset = topOffsetOrOptions; + } else { + topOffset = topOffsetOrOptions?.topOffset; + bottomOffset = topOffsetOrOptions?.bottomOffset; + } await this.driver.executeScript( scrollIntoViewIfNecessary, this._webElement, - topOffset || this.fixedHeaderHeight + topOffset || this.fixedHeaderHeight, + bottomOffset ); } 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 41a69f62de04e..75fc06c1a4494 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 @@ -93,7 +93,7 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { // Agent policy and package info states const [agentPolicy, setAgentPolicy] = useState(); const [packageInfo, setPackageInfo] = useState(); - const [isLoadingSecondStep, setIsLoadingSecondStep] = useState(false); + const [isLoadingAgentPolicyStep, setIsLoadingAgentPolicyStep] = useState(false); // Retrieve agent count const agentPolicyId = agentPolicy?.id; @@ -356,7 +356,7 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { defaultAgentPolicyId={policyId} agentPolicy={agentPolicy} updateAgentPolicy={updateAgentPolicy} - setIsLoadingSecondStep={setIsLoadingSecondStep} + setIsLoadingSecondStep={setIsLoadingAgentPolicyStep} /> ), [params, updatePackageInfo, agentPolicy, updateAgentPolicy, policyId] @@ -366,7 +366,7 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { const stepConfigurePackagePolicy = useMemo( () => - isLoadingSecondStep ? ( + isLoadingAgentPolicyStep ? ( ) : agentPolicy && packageInfo ? ( <> @@ -403,7 +403,7 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => {
), [ - isLoadingSecondStep, + isLoadingAgentPolicyStep, agentPolicy, packageInfo, packagePolicy, @@ -421,7 +421,7 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { title: i18n.translate('xpack.fleet.createPackagePolicy.stepConfigurePackagePolicyTitle', { defaultMessage: 'Configure integration', }), - status: !packageInfo || !agentPolicy || isLoadingSecondStep ? 'disabled' : undefined, + status: !packageInfo || !agentPolicy || isLoadingAgentPolicyStep ? 'disabled' : undefined, 'data-test-subj': 'dataCollectionSetupStep', children: stepConfigurePackagePolicy, }, @@ -456,10 +456,10 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => { )} - + - {!isLoadingSecondStep && agentPolicy && packageInfo && formState === 'INVALID' ? ( + {!isLoadingAgentPolicyStep && agentPolicy && packageInfo && formState === 'INVALID' ? ( Date: Mon, 14 Jun 2021 14:42:30 +0200 Subject: [PATCH 18/19] fix scroll direction! --- .../lib/web_element_wrapper/scroll_into_view_if_necessary.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/services/lib/web_element_wrapper/scroll_into_view_if_necessary.js b/test/functional/services/lib/web_element_wrapper/scroll_into_view_if_necessary.js index ac5e64696b7fd..5df88461fc312 100644 --- a/test/functional/services/lib/web_element_wrapper/scroll_into_view_if_necessary.js +++ b/test/functional/services/lib/web_element_wrapper/scroll_into_view_if_necessary.js @@ -67,7 +67,7 @@ export function scrollIntoViewIfNecessary(target, fixedHeaderHeight, fixedFooter if (fixedFooterHeight) { var bottomOfVisibility = viewportHeight - fixedFooterHeight; if (bottomOfVisibility < boundingRect.top) { - rootScroller.scrollTop = rootScroller.scrollTop - boundingRect.height; + rootScroller.scrollTop = rootScroller.scrollTop + boundingRect.height; } } } From 28f1f2ad6b5958fee2f827ea5ff8624d050b9fb3 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Mon, 14 Jun 2021 17:24:44 +0200 Subject: [PATCH 19/19] attempting another scroll algorithm --- .../web_element_wrapper/scroll_into_view_if_necessary.js | 4 ++-- .../functional/page_objects/synthetics_integration_page.ts | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/test/functional/services/lib/web_element_wrapper/scroll_into_view_if_necessary.js b/test/functional/services/lib/web_element_wrapper/scroll_into_view_if_necessary.js index 5df88461fc312..514d1bb1d9d7b 100644 --- a/test/functional/services/lib/web_element_wrapper/scroll_into_view_if_necessary.js +++ b/test/functional/services/lib/web_element_wrapper/scroll_into_view_if_necessary.js @@ -66,8 +66,8 @@ export function scrollIntoViewIfNecessary(target, fixedHeaderHeight, fixedFooter if (fixedFooterHeight) { var bottomOfVisibility = viewportHeight - fixedFooterHeight; - if (bottomOfVisibility < boundingRect.top) { - rootScroller.scrollTop = rootScroller.scrollTop + boundingRect.height; + if (bottomOfVisibility < boundingRect.bottom) { + rootScroller.scrollTop = rootScroller.scrollTop + fixedFooterHeight; } } } diff --git a/x-pack/test/functional/page_objects/synthetics_integration_page.ts b/x-pack/test/functional/page_objects/synthetics_integration_page.ts index 72e81e8813231..56a67d9e6fbd4 100644 --- a/x-pack/test/functional/page_objects/synthetics_integration_page.ts +++ b/x-pack/test/functional/page_objects/synthetics_integration_page.ts @@ -16,6 +16,8 @@ export function SyntheticsIntegrationPageProvider({ const testSubjects = getService('testSubjects'); const comboBox = getService('comboBox'); + const fixedFooterHeight = 72; // Size of EuiBottomBar more or less + return { /** * Navigates to the Synthetics Integration page @@ -85,7 +87,7 @@ export function SyntheticsIntegrationPageProvider({ */ async fillTextInputByTestSubj(testSubj: string, value: string) { const field = await testSubjects.find(testSubj, 5000); - await field.scrollIntoViewIfNecessary({ bottomOffset: 56 }); + await field.scrollIntoViewIfNecessary({ bottomOffset: fixedFooterHeight }); await field.click(); await field.clearValue(); await field.type(value); @@ -97,7 +99,7 @@ export function SyntheticsIntegrationPageProvider({ * @params {value} the value of the input */ async fillTextInput(field: WebElementWrapper, value: string) { - await field.scrollIntoViewIfNecessary({ bottomOffset: 56 }); + await field.scrollIntoViewIfNecessary({ bottomOffset: fixedFooterHeight }); await field.click(); await field.clearValue(); await field.type(value);