diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/advanced_tab.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/advanced_tab.tsx index 2eacab9bbaa49..5e88e69682d79 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/advanced_tab.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/advanced_tab.tsx @@ -22,11 +22,13 @@ import { interface AdvancedTabProps { onClose: () => void; selectedPolicyId?: string; + handleContinueAddingAgentClick?: () => void; } export const AdvancedTab: React.FunctionComponent = ({ selectedPolicyId, onClose, + handleContinueAddingAgentClick, }) => { const { isSelectFleetServerPolicyLoading, @@ -81,6 +83,7 @@ export const AdvancedTab: React.FunctionComponent = ({ getConfirmFleetServerConnectionStep({ hasRecentlyEnrolledFleetServers, disabled: !Boolean(serviceToken), + handleContinueAddingAgentClick, }), ]; diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/index.tsx index b46d4f2060669..e8acf2597df6b 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/index.tsx @@ -39,20 +39,33 @@ interface Props { onClose: () => void; } -const useFleetServerTabs = (onClose: () => void) => { +export const useFleetServerTabs = ( + onClose: () => void, + handleContinueAddingAgentClick?: () => void +) => { const [currentTab, setCurrentTab] = useState('quickStart'); const quickStartTab = { id: 'quickStart', label: 'Quick Start', - content: , + content: ( + + ), 'data-test-subj': 'fleetServerFlyoutTab-quickStart', }; const advancedTab = { id: 'advanced', label: 'Advanced', - content: , + content: ( + + ), 'data-test-subj': 'fleetServerFlyoutTab-advanced', }; @@ -62,7 +75,7 @@ const useFleetServerTabs = (onClose: () => void) => { return { tabs: [quickStartTab, advancedTab], currentTab, setCurrentTab, currentTabContent }; }; -const Header: React.FunctionComponent<{ +export const Header: React.FunctionComponent<{ isFlyout?: boolean; currentTab: string; tabs: Array<{ id: string; label: string; content: React.ReactNode }>; diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/quick_start_tab.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/quick_start_tab.tsx index 959b1d08d7863..c3334ce28cc2a 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/quick_start_tab.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/quick_start_tab.tsx @@ -19,9 +19,13 @@ import { useLatestFleetServers } from './hooks/use_latest_fleet_servers'; interface Props { onClose: () => void; + handleContinueAddingAgentClick?: () => void; } -export const QuickStartTab: React.FunctionComponent = ({ onClose }) => { +export const QuickStartTab: React.FunctionComponent = ({ + onClose, + handleContinueAddingAgentClick, +}) => { const { fleetServerHost, setFleetServerHost, @@ -62,6 +66,7 @@ export const QuickStartTab: React.FunctionComponent = ({ onClose }) => { getConfirmFleetServerConnectionStep({ hasRecentlyEnrolledFleetServers, disabled: status !== 'success', + handleContinueAddingAgentClick, }), ]; diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/steps/confirm_fleet_server_connection.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/steps/confirm_fleet_server_connection.tsx index de6ff3f95fbf9..ae0b36738a77b 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/steps/confirm_fleet_server_connection.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/steps/confirm_fleet_server_connection.tsx @@ -18,9 +18,11 @@ import { useFleetStatus, useFlyoutContext } from '../../../hooks'; export function getConfirmFleetServerConnectionStep({ disabled, hasRecentlyEnrolledFleetServers, + handleContinueAddingAgentClick, }: { disabled: boolean; hasRecentlyEnrolledFleetServers: boolean; + handleContinueAddingAgentClick?: () => void; }): EuiStepProps { return { title: hasRecentlyEnrolledFleetServers @@ -34,6 +36,7 @@ export function getConfirmFleetServerConnectionStep({ children: !disabled && ( ), }; @@ -41,7 +44,8 @@ export function getConfirmFleetServerConnectionStep({ const ConfirmFleetServerConnectionStepContent: React.FunctionComponent<{ hasRecentlyEnrolledFleetServers: boolean; -}> = ({ hasRecentlyEnrolledFleetServers }) => { + handleContinueAddingAgentClick?: () => void; +}> = ({ handleContinueAddingAgentClick, hasRecentlyEnrolledFleetServers }) => { const flyoutContext = useFlyoutContext(); const fleetStatus = useFleetStatus(); @@ -64,7 +68,7 @@ const ConfirmFleetServerConnectionStepContent: React.FunctionComponent<{ = (props) => { + const { steps, currentStep, error } = props; + + if (error) { + return ( + + } + error={error} + /> + ); + } + + const StepComponent = steps[currentStep].component; + + return ; +}; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/embedded_integration_flow/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/embedded_integration_flow/index.tsx new file mode 100644 index 0000000000000..5cc12169f2369 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/embedded_integration_flow/index.tsx @@ -0,0 +1,149 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { i18n } from '@kbn/i18n'; + +import { splitPkgKey } from '../../../../../../../common/services'; + +import { + useGetPackageInfoByKeyQuery, + useFleetServerHostsForPolicy, + useStartServices, +} from '../../../../hooks'; + +import { useIntegrationsStateContext } from '../../../../../integrations/hooks'; + +import type { AgentPolicy } from '../../../../types'; +import { useGetAgentPolicyOrDefault } from '../multi_page_layout/hooks'; +import { Loading } from '../../../../components'; + +import { onboardingManagedSteps } from './onboarding_steps'; + +import { EmbeddedIntegrationStepsLayout } from './embedded_integration_steps_layout'; +import type { EmbeddedIntegrationFlowProps } from './types'; + +export const EmbeddedIntegrationFlow: React.FC = ({ + prerelease, + integrationName: integration, + onStepNext, + onCancel, + handleViewAssets, + from, +}) => { + const { notifications } = useStartServices(); + + const { pkgkey: pkgKeyContext } = useIntegrationsStateContext(); + const pkgkey = pkgKeyContext || ''; + const { pkgName, pkgVersion } = splitPkgKey(pkgkey); + const [currentStep, setCurrentStep] = useState(0); + const [isManaged, setIsManaged] = useState(true); + const [enrolledAgentIds, setEnrolledAgentIds] = useState([]); + const [selectedAgentPolicies, setSelectedAgentPolicies] = useState(); + const toggleIsManaged = (newIsManaged: boolean) => { + setIsManaged(newIsManaged); + setCurrentStep(0); + }; + + const agentPolicyId = useMemo(() => selectedAgentPolicies?.[0]?.id, [selectedAgentPolicies]); + const { + data: packageInfoData, + error: packageInfoError, + isLoading: isPackageInfoLoading, + } = useGetPackageInfoByKeyQuery(pkgName, pkgVersion, { prerelease, full: true }); + + const { + agentPolicy, + enrollmentAPIKey, + error: agentPolicyError, + isLoading: isAgentPolicyLoading, + } = useGetAgentPolicyOrDefault(agentPolicyId); + + const packageInfo = useMemo(() => packageInfoData?.item, [packageInfoData]); + + const integrationInfo = useMemo(() => { + if (!integration) return; + return packageInfo?.policy_templates?.find( + (policyTemplate) => policyTemplate.name === integration + ); + }, [packageInfo?.policy_templates, integration]); + + const { fleetServerHost, fleetProxy, downloadSource } = useFleetServerHostsForPolicy(agentPolicy); + + const stepsNext = useCallback( + (props?: { selectedAgentPolicies?: AgentPolicy[]; toStep?: number }) => { + if (currentStep === onboardingManagedSteps.length - 1) { + return; + } + + setCurrentStep(props?.toStep ?? currentStep + 1); + onStepNext?.(props?.toStep ?? currentStep + 1); + + // selected agent policy is set after integration is configured + if (props?.selectedAgentPolicies) { + setSelectedAgentPolicies(props?.selectedAgentPolicies); + } + }, + [currentStep, onStepNext] + ); + + const stepsBack = () => { + if (currentStep === 0) { + return; + } + + setCurrentStep(currentStep - 1); + }; + + useEffect(() => { + if (!isPackageInfoLoading && packageInfoError) { + notifications.toasts.addError(packageInfoError, { + title: i18n.translate('xpack.fleet.createPackagePolicy.errorLoadingPackageTitle', { + defaultMessage: 'Error loading package information', + }), + toastMessage: packageInfoError.message, + }); + } + }, [isPackageInfoLoading, notifications.toasts, packageInfoError]); + + useEffect(() => { + if (!isAgentPolicyLoading && agentPolicyError) { + notifications.toasts.addError(agentPolicyError, { + title: i18n.translate('xpack.fleet.createPackagePolicy.errorLoadingAgentPolicyTitle', { + defaultMessage: 'Error loading agent policy information', + }), + toastMessage: agentPolicyError.message, + }); + } + }, [isAgentPolicyLoading, notifications.toasts, agentPolicyError]); + + return !isPackageInfoLoading && packageInfo ? ( + + ) : ( + + ); +}; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/embedded_integration_flow/onboarding_steps/add_fleet_server.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/embedded_integration_flow/onboarding_steps/add_fleet_server.tsx new file mode 100644 index 0000000000000..c62f04e5efd8e --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/embedded_integration_flow/onboarding_steps/add_fleet_server.tsx @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { EuiSpacer } from '@elastic/eui'; + +import { useCheckPermissions } from '../../../../../hooks'; + +import { useFleetServerTabs } from '../../../../../components'; +import { Header } from '../../../../../components/fleet_server_instructions'; +import { FleetServerMissingESPrivileges } from '../../../../agents/components'; +import type { EmbeddedIntegrationStepsLayoutProps } from '../types'; + +export const AddFleetServerStepFromOnboardingHub: React.FC = ({ + onCancel, + onNext, +}) => { + const { tabs, currentTab, setCurrentTab, currentTabContent } = useFleetServerTabs( + onCancel, + onNext + ); + + const { permissionsError, isPermissionsLoading } = useCheckPermissions(); + + return ( + <> +
setCurrentTab(id)} /> + {!isPermissionsLoading && permissionsError === 'MISSING_FLEET_SERVER_SETUP_PRIVILEGES' ? ( + + ) : ( + <> + + {currentTabContent} + + )} + + ); +}; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/embedded_integration_flow/onboarding_steps/agent_enrollment.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/embedded_integration_flow/onboarding_steps/agent_enrollment.tsx new file mode 100644 index 0000000000000..4536d13fdea7a --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/embedded_integration_flow/onboarding_steps/agent_enrollment.tsx @@ -0,0 +1,122 @@ +/* + * 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 { useCallback, useEffect, useState } from 'react'; + +import React from 'react'; + +import type { + FlyoutMode, + SelectionType, +} from '../../../../../../../components/agent_enrollment_flyout/types'; +import { useAgentEnrollmentFlyoutData, useFleetServerHostsForPolicy } from '../../../../../hooks'; +import { + useAgentPolicyWithPackagePolicies, + useCloudSecurityIntegration, + useIsK8sPolicy, +} from '../../../../../../../components/agent_enrollment_flyout/hooks'; +import { usePollingAgentCount } from '../../../../../../../components/agent_enrollment_flyout/confirm_agent_enrollment'; +import type { PackagePolicy } from '../../../../../types'; +import { FLEET_SERVER_PACKAGE } from '../../../../../constants'; +import { Instructions, Loading } from '../../../../../components'; +import type { EmbeddedIntegrationStepsLayoutProps } from '../types'; + +export const AgentEnrollmentFromOnboardingHub = ({ + agentPolicy, + selectedAgentPolicies, + isManaged, + from, + onNext, + setEnrolledAgentIds, + steps, +}: EmbeddedIntegrationStepsLayoutProps) => { + const [selectedPolicyId, setSelectedPolicyId] = useState(agentPolicy?.id); + const [isFleetServerPolicySelected, setIsFleetServerPolicySelected] = useState(false); + const [selectedApiKeyId, setSelectedAPIKeyId] = useState(); + const [mode, setMode] = useState(isManaged ? 'managed' : 'standalone'); + const [selectionType, setSelectionType] = useState(); + + const { + agentPolicies: fetchedAgentPolicies, + isLoadingInitialAgentPolicies, + isLoadingAgentPolicies, + refreshAgentPolicies, + } = useAgentEnrollmentFlyoutData(); + + // Have the option to pass agentPolicies from props, otherwise use the fetched ones + const agentPolicies = selectedAgentPolicies ? selectedAgentPolicies : fetchedAgentPolicies; + + const { agentPolicyWithPackagePolicies } = useAgentPolicyWithPackagePolicies(selectedPolicyId); + + const { fleetServerHost, fleetProxy, downloadSource, downloadSourceProxy } = + useFleetServerHostsForPolicy(agentPolicyWithPackagePolicies); + + const selectedPolicy = agentPolicyWithPackagePolicies + ? agentPolicyWithPackagePolicies + : undefined; + + const { enrolledAgentIds } = usePollingAgentCount(selectedPolicyId || '', { + noLowerTimeLimit: true, + pollImmediately: true, + }); + + const onClickViewIncomingData = useCallback(() => { + setEnrolledAgentIds(enrolledAgentIds); + onNext({ toStep: steps.length - 1 }); + }, [enrolledAgentIds, onNext, setEnrolledAgentIds, steps.length]); + + const handleAddFleetServer = useCallback(() => { + setEnrolledAgentIds(enrolledAgentIds); + onNext(); + }, [enrolledAgentIds, onNext, setEnrolledAgentIds]); + + useEffect(() => { + if (selectedPolicy) { + if ( + (selectedPolicy.package_policies as PackagePolicy[]).some( + (packagePolicy) => packagePolicy.package?.name === FLEET_SERVER_PACKAGE + ) + ) { + setIsFleetServerPolicySelected(true); + } else { + setIsFleetServerPolicySelected(false); + } + } + }, [selectedPolicy, isFleetServerPolicySelected]); + + const { isK8s } = useIsK8sPolicy(selectedPolicy ?? undefined); + const { cloudSecurityIntegration } = useCloudSecurityIntegration(selectedPolicy ?? undefined); + + return isLoadingInitialAgentPolicies || isLoadingAgentPolicies ? ( + + ) : ( + + ); +}; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/embedded_integration_flow/onboarding_steps/check_fleet_server_required.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/embedded_integration_flow/onboarding_steps/check_fleet_server_required.tsx new file mode 100644 index 0000000000000..427608f36049f --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/embedded_integration_flow/onboarding_steps/check_fleet_server_required.tsx @@ -0,0 +1,82 @@ +/* + * 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 } from 'react'; + +import { + useFleetServerStandalone, + useFleetStatus, + useGetEnrollmentSettings, +} from '../../../../../hooks'; + +import { shouldShowFleetServerEnrollment } from '../../../../../components'; +import type { EmbeddedIntegrationStepsLayoutProps } from '../types'; +import { useAgentPolicyWithPackagePolicies } from '../../../../../../../components/agent_enrollment_flyout/hooks'; +import { FleetServerRequirementPage } from '../../../../agents/agent_requirements_page'; +import type { PackagePolicy } from '../../../../../types'; +import { FLEET_SERVER_PACKAGE } from '../../../../../constants'; + +export const CheckFleetServerRequiredFromOnboardingHub: React.FC< + EmbeddedIntegrationStepsLayoutProps +> = ({ agentPolicy, isManaged, setIsManaged, onNext, currentStep }) => { + const [isFleetServerPolicySelected, setIsFleetServerPolicySelected] = useState(false); + + const fleetStatus = useFleetStatus(); + const { isFleetServerStandalone } = useFleetServerStandalone(); + const { data: enrollmentSettings } = useGetEnrollmentSettings(); + + const showFleetServerEnrollment = shouldShowFleetServerEnrollment({ + isFleetServerStandalone, + isFleetServerPolicySelected, + enrollmentSettings, + fleetStatusMissingRequirements: fleetStatus.missingRequirements, + }); + + const { agentPolicyWithPackagePolicies } = useAgentPolicyWithPackagePolicies(agentPolicy?.id); + + const selectedPolicy = agentPolicyWithPackagePolicies + ? agentPolicyWithPackagePolicies + : undefined; + + useEffect(() => { + if (selectedPolicy) { + if ( + (selectedPolicy.package_policies as PackagePolicy[]).some( + (packagePolicy) => packagePolicy.package?.name === FLEET_SERVER_PACKAGE + ) + ) { + setIsFleetServerPolicySelected(true); + } else { + setIsFleetServerPolicySelected(false); + } + } + }, [selectedPolicy, isFleetServerPolicySelected]); + + useEffect(() => { + // If the user is standalone, skip the Fleet Server enrollment step + // If the user is managed and the Fleet Server enrollment is done, skip the Fleet Server enrollment step + if ((!isManaged && showFleetServerEnrollment) || (isManaged && !showFleetServerEnrollment)) { + onNext({ toStep: currentStep + 2 }); + } + }, [currentStep, isManaged, onNext, showFleetServerEnrollment]); + + if (isManaged && showFleetServerEnrollment) { + return ( + { + setIsManaged(false); + onNext({ toStep: currentStep + 2 }); + }} + handleAddFleetServer={() => { + onNext(); + }} + /> + ); + } + + return null; +}; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/embedded_integration_flow/onboarding_steps/confirm_incoming_data.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/embedded_integration_flow/onboarding_steps/confirm_incoming_data.tsx new file mode 100644 index 0000000000000..6f630eb51d65a --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/embedded_integration_flow/onboarding_steps/confirm_incoming_data.tsx @@ -0,0 +1,150 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback, useState } from 'react'; + +import { EuiButton, EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; + +import { FormattedMessage } from '@kbn/i18n-react'; + +import { DASHBOARD_APP_ID, createDashboardEditUrl } from '@kbn/dashboard-plugin/public'; + +import { useIntraAppState, useStartServices } from '../../../../../hooks'; + +import { + ConfirmIncomingDataWithPreview, + ConfirmIncomingDataStandalone, +} from '../../multi_page_layout/components'; +import type { EmbeddedIntegrationStepsLayoutProps } from '../types'; +import { FLEET_KUBERNETES_PACKAGE } from '../../../../../../../../common'; +import type { AgentPolicyDetailsDeployAgentAction } from '../../../../../types'; + +export const FinalBottomBar: React.FC<{ + pkgkey: string; + handleAddAnotherIntegration: () => void; + handleViewAssets: () => void; + viewKubernetesMetricsDashboards: () => void; +}> = ({ + pkgkey, + handleAddAnotherIntegration, + handleViewAssets, + viewKubernetesMetricsDashboards, +}) => { + const isK8s = pkgkey.includes(FLEET_KUBERNETES_PACKAGE); + return ( + + + + + + + + + {!isK8s && ( + + + + + + )} + {isK8s && ( + + + + + + )} + + ); +}; + +export const ConfirmDataStepFromOnboardingHub: React.FC = ( + props +) => { + const { enrolledAgentIds, packageInfo, isManaged, onCancel, handleViewAssets } = props; + const core = useStartServices(); + + const [agentDataConfirmed, setAgentDataConfirmed] = useState(false); + const { + docLinks: { + links: { + fleet: { troubleshooting: troubleshootLink }, + }, + }, + application: { navigateToApp }, + } = core; + const routeState = useIntraAppState(); + + const handleAddAnotherIntegration = () => { + // Close the modal + onCancel(); + }; + + const viewKubernetesMetricsDashboards = useCallback(() => { + // Open the Kubernetes metrics dashboards in security solution + // href={getAbsolutePath( + // '/app/dashboards#/view/kubernetes-f4dc26db-1b53-4ea2-a78b-1bfab8ea267c' + // )} + if (routeState && routeState.onDoneNavigateTo) { + const [appId] = routeState.onDoneNavigateTo; + return () => { + navigateToApp(appId === 'securitySolutionUI' ? appId : DASHBOARD_APP_ID, { + path: createDashboardEditUrl(`kubernetes-f4dc26db-1b53-4ea2-a78b-1bfab8ea267c`), + }); + }; + } + }, [navigateToApp, routeState]); + + if (!isManaged) { + return ( + + + + ); + } + + return ( + + {!!agentDataConfirmed && ( + + )} + + ); +}; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/embedded_integration_flow/onboarding_steps/create_package_policy.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/embedded_integration_flow/onboarding_steps/create_package_policy.tsx new file mode 100644 index 0000000000000..a7b37f4e1a35d --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/embedded_integration_flow/onboarding_steps/create_package_policy.tsx @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import type { EmbeddedIntegrationStepsLayoutProps } from '../types'; +import { CreatePackagePolicySinglePage } from '../../single_page_layout'; + +export const CreatePackagePolicyFromOnboardingHub: React.FC = ( + props +) => { + return ( + + ); +}; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/embedded_integration_flow/onboarding_steps/index.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/embedded_integration_flow/onboarding_steps/index.ts new file mode 100644 index 0000000000000..858898797cc93 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/embedded_integration_flow/onboarding_steps/index.ts @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +import { CreatePackagePolicyFromOnboardingHub } from './create_package_policy'; +import { AgentEnrollmentFromOnboardingHub } from './agent_enrollment'; +import { AddFleetServerStepFromOnboardingHub } from './add_fleet_server'; +import { ConfirmDataStepFromOnboardingHub } from './confirm_incoming_data'; +import { CheckFleetServerRequiredFromOnboardingHub } from './check_fleet_server_required'; + +const addIntegrationFromOnboardingHub = { + title: i18n.translate('xpack.fleet.createFirstPackagePolicy.addIntegrationStepTitle', { + defaultMessage: 'Add the integration', + }), + component: CreatePackagePolicyFromOnboardingHub, +}; + +const agentEnrollmentStepFromOnboardingHub = { + title: i18n.translate('xpack.fleet.createFirstPackagePolicy.agentEnrollmentStepTitle', { + defaultMessage: 'Add agent', + }), + component: AgentEnrollmentFromOnboardingHub, +}; + +const addFleetServerStepFromOnboardingHub = { + title: i18n.translate('xpack.fleet.createFirstPackagePolicy.addFleetServerStepTitle', { + defaultMessage: 'Add Fleet Server', + }), + component: AddFleetServerStepFromOnboardingHub, +}; + +const confirmDataStepFromOnboardingHub = { + title: i18n.translate('xpack.fleet.createFirstPackagePolicy.confirmDataStepTitle', { + defaultMessage: 'Confirm incoming data', + }), + component: ConfirmDataStepFromOnboardingHub, +}; + +const checkFleetServerRequirementsStep = { + title: i18n.translate( + 'xpack.fleet.createFirstPackagePolicy.checkFleetServerRequirementsStepTitle', + { + defaultMessage: 'Check Fleet Server requirements', + } + ), + component: CheckFleetServerRequiredFromOnboardingHub, +}; + +export const onboardingManagedSteps = [ + addIntegrationFromOnboardingHub, + checkFleetServerRequirementsStep, + addFleetServerStepFromOnboardingHub, + agentEnrollmentStepFromOnboardingHub, + confirmDataStepFromOnboardingHub, +]; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/embedded_integration_flow/types.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/embedded_integration_flow/types.ts new file mode 100644 index 0000000000000..c812c1aa124b8 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/embedded_integration_flow/types.ts @@ -0,0 +1,56 @@ +/* + * 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 { + FleetProxy, + DownloadSource, + AgentPolicy, + EnrollmentAPIKey, + PackageInfo, + RegistryPolicyTemplate, +} from '../../../../types'; +import type { EditPackagePolicyFrom } from '../types'; + +export interface EmbeddedIntegrationStepsLayoutProps { + fleetServerHost: string; + fleetProxy?: FleetProxy; + downloadSource?: DownloadSource; + agentPolicy?: AgentPolicy; + error?: Error; + enrollmentAPIKey?: EnrollmentAPIKey; + packageInfo: PackageInfo; + integrationInfo?: RegistryPolicyTemplate; + cancelClickHandler?: React.ReactEventHandler; + onBack: React.ReactEventHandler; + steps: EmbeddedFlowStep[]; + currentStep: number; + onNext: (params?: { selectedAgentPolicies?: AgentPolicy[]; toStep?: number }) => void; + setIsManaged: (isManaged: boolean) => void; + isManaged: boolean; + setEnrolledAgentIds: (agentIds: string[]) => void; + enrolledAgentIds: string[]; + onCancel: () => void; + prerelease: boolean; + handleViewAssets: () => void; + from: EditPackagePolicyFrom; + selectedAgentPolicies?: AgentPolicy[]; +} + +export interface EmbeddedIntegrationFlowProps { + from: EditPackagePolicyFrom; + queryParamsPolicyId?: string; + integrationName?: string; + prerelease: boolean; + onCancel: () => void; + onStepNext?: (step: number) => void; + handleViewAssets: () => void; +} + +export interface EmbeddedFlowStep { + title: string; + component: React.FC; +} 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 3cf6b362e7376..12903adb008af 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 @@ -8,27 +8,30 @@ import React, { useEffect } from 'react'; import { useMemo } from 'react'; import { useLocation, useRouteMatch } from 'react-router-dom'; +import { noop } from 'lodash/fp'; + import { useGetSettings } from '../../../hooks'; import type { AddToPolicyParams, EditPackagePolicyFrom } from './types'; import { CreatePackagePolicySinglePage } from './single_page_layout'; import { CreatePackagePolicyMultiPage } from './multi_page_layout'; +import { EmbeddedIntegrationFlow } from './embedded_integration_flow'; export const CreatePackagePolicyPage: React.FC<{ useMultiPageLayoutProp?: boolean; originFrom?: EditPackagePolicyFrom; - propPolicyId?: string; integrationName?: string; - setIntegrationStep?: (step: number) => void; - onCanceled?: () => void; + onStepNext?: (step: number) => void; + onCancel?: () => void; + handleViewAssets?: () => void; }> = ({ useMultiPageLayoutProp, originFrom, - propPolicyId, integrationName, - setIntegrationStep, - onCanceled, + onStepNext, + onCancel = noop, + handleViewAssets = noop, }) => { const { search } = useLocation(); const { params } = useRouteMatch(); @@ -69,13 +72,21 @@ export const CreatePackagePolicyPage: React.FC<{ const pageParams = { from, queryParamsPolicyId, - propPolicyId, - integrationName, prerelease, - setIntegrationStep, - onCanceled, }; + if (from === 'onboarding-hub') { + return ( + + ); + } + if (useMultiPageLayout) { return ; } diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/bottom_bar.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/bottom_bar.tsx index 90d25a35be875..9610e54bc0849 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/bottom_bar.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/bottom_bar.tsx @@ -123,60 +123,68 @@ export const AgentStandaloneBottomBar: React.FC<{ ); }; -export const CreatePackagePolicyFinalBottomBar: React.FC<{ +const FinalBottomBar: React.FC<{ pkgkey: string; }> = ({ pkgkey }) => { const isK8s = pkgkey.includes(FLEET_KUBERNETES_PACKAGE); const { getHref } = useLink(); const { getAbsolutePath } = useLink(); return ( - - + + - - - - - + + + - {!isK8s && ( - - - - - - )} - {isK8s && ( - - - - - - )} - + + {!isK8s && ( + + + + + + )} + {isK8s && ( + + + + + + )} + + ); +}; + +export const CreatePackagePolicyFinalBottomBar: React.FC<{ + pkgkey: string; +}> = ({ pkgkey }) => { + return ( + + ); }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/confirm_incoming_data_with_preview.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/confirm_incoming_data_with_preview.tsx index d6d4c3abd63f5..485d1b5036597 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/confirm_incoming_data_with_preview.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/confirm_incoming_data_with_preview.tsx @@ -5,6 +5,7 @@ * 2.0. */ +import type { PropsWithChildren } from 'react'; import React from 'react'; import { EuiCallOut, @@ -124,12 +125,13 @@ const AgentDataPreview: React.FC<{ dataPreview: SearchHit[] }> = ({ dataPreview ); }; -export const ConfirmIncomingDataWithPreview: React.FunctionComponent = ({ +export const ConfirmIncomingDataWithPreview: React.FunctionComponent> = ({ agentIds, packageInfo, agentDataConfirmed, setAgentDataConfirmed, troubleshootLink, + children, }) => { const { incomingData, dataPreview, isLoading, hasReachedTimeout } = usePollingIncomingData({ agentIds, @@ -218,6 +220,7 @@ export const ConfirmIncomingDataWithPreview: React.FunctionComponent = ({ + {children} ); }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/confirming_incoming_data_standalone.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/confirming_incoming_data_standalone.tsx index 5ad7be6fce71a..e83d05bd82dbe 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/confirming_incoming_data_standalone.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/confirming_incoming_data_standalone.tsx @@ -5,6 +5,7 @@ * 2.0. */ +import type { PropsWithChildren } from 'react'; import React from 'react'; import { EuiCallOut, EuiText, EuiLink } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -13,8 +14,9 @@ interface Props { troubleshootLink: string; } -export const ConfirmIncomingDataStandalone: React.FunctionComponent = ({ +export const ConfirmIncomingDataStandalone: React.FunctionComponent> = ({ troubleshootLink, + children, }) => { return ( <> @@ -45,6 +47,7 @@ export const ConfirmIncomingDataStandalone: React.FunctionComponent = ({ /> + {children} ); }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/multi_page_steps_layout.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/multi_page_steps_layout.tsx index d9539e318c142..44348b704d220 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/multi_page_steps_layout.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/multi_page_steps_layout.tsx @@ -57,6 +57,7 @@ export const MultiPageStepsLayout: React.FunctionComponent = ({ packageInfoName, packageInfoVersion }) => ( + <> + + + +); + export const ConfirmDataPageStep: React.FC = (props) => { const { enrolledAgentIds, packageInfo, isManaged } = props; const core = useStartServices(); @@ -25,18 +35,11 @@ export const ConfirmDataPageStep: React.FC = (props) = const { docLinks } = core; const troubleshootLink = docLinks.links.fleet.troubleshooting; - const bottomBar = ( - <> - - - - ); - if (!isManaged) { return ( <> - {bottomBar} + ); } @@ -51,7 +54,9 @@ export const ConfirmDataPageStep: React.FC = (props) = troubleshootLink={troubleshootLink} /> - {!!agentDataConfirmed && bottomBar} + {!!agentDataConfirmed && ( + + )} ); }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/hooks/use_get_agent_policy_or_default.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/hooks/use_get_agent_policy_or_default.tsx index ead4496b0ba7a..d46594ef6bb3b 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/hooks/use_get_agent_policy_or_default.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/hooks/use_get_agent_policy_or_default.tsx @@ -5,9 +5,8 @@ * 2.0. */ -import { useEffect, useState, useMemo, useRef } from 'react'; +import { useEffect, useState, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; -import { v4 as uuidv4 } from 'uuid'; import { generateNewAgentPolicyWithDefaults } from '../../../../../../../../common/services/generate_new_agent_policy'; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/index.tsx index 1d61e8e033358..ebfba7a24297a 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/index.tsx @@ -18,12 +18,6 @@ import { import type { AddToPolicyParams, CreatePackagePolicyParams } from '../types'; -import { useIntegrationsStateContext } from '../../../../../integrations/hooks'; - -import { CreatePackagePolicySinglePage } from '../single_page_layout'; - -import type { AgentPolicy } from '../../../../types'; - import { useGetAgentPolicyOrDefault } from './hooks'; import { @@ -48,13 +42,6 @@ const addIntegrationStep = { component: AddIntegrationPageStep, }; -const addIntegrationSingleLayoutStep = { - title: i18n.translate('xpack.fleet.createFirstPackagePolicy.addIntegrationStepTitle', { - defaultMessage: 'Add the integration', - }), - component: CreatePackagePolicySinglePage, -}; - const confirmDataStep = { title: i18n.translate('xpack.fleet.createFirstPackagePolicy.confirmDataStepTitle', { defaultMessage: 'Confirm incoming data', @@ -66,35 +53,25 @@ const fleetManagedSteps = [installAgentStep, addIntegrationStep, confirmDataStep const standaloneSteps = [addIntegrationStep, installAgentStep, confirmDataStep]; -const onboardingSteps = [addIntegrationSingleLayoutStep, installAgentStep, confirmDataStep]; - -export const CreatePackagePolicyMultiPage: CreatePackagePolicyParams = ({ +export const CreatePackagePolicyMultiPage: React.FC = ({ queryParamsPolicyId, prerelease, - from, - integrationName, - setIntegrationStep, - onCanceled, }) => { const { params } = useRouteMatch(); - // fixme - const { pkgkey: pkgkeyParam, policyId, integration: integrationParam } = params; - const { pkgkey: pkgKeyContext } = useIntegrationsStateContext(); - const pkgkey = pkgkeyParam || pkgKeyContext; + const { pkgkey, policyId, integration } = params; const { pkgName, pkgVersion } = splitPkgKey(pkgkey); - const [onSplash, setOnSplash] = useState(from !== 'onboarding-integration'); + const [onSplash, setOnSplash] = useState(true); const [currentStep, setCurrentStep] = useState(0); const [isManaged, setIsManaged] = useState(true); const { getHref } = useLink(); const [enrolledAgentIds, setEnrolledAgentIds] = useState([]); - const [selectedAgentPolicies, setSelectedAgentPolicies] = useState(); + const toggleIsManaged = (newIsManaged: boolean) => { setIsManaged(newIsManaged); setCurrentStep(0); }; - const integration = integrationName || integrationParam; - const agentPolicyId = selectedAgentPolicies?.[0]?.id || policyId || queryParamsPolicyId; + const agentPolicyId = policyId || queryParamsPolicyId; const { data: packageInfoData, error: packageInfoError, @@ -131,6 +108,8 @@ export const CreatePackagePolicyMultiPage: CreatePackagePolicyParams = ({ ...(agentPolicyId ? { agentPolicyId } : {}), }); + const steps = isManaged ? fleetManagedSteps : standaloneSteps; + if (onSplash || !packageInfo) { return ( { + const stepsNext = () => { if (currentStep === steps.length - 1) { return; } setCurrentStep(currentStep + 1); - setIntegrationStep(currentStep + 1); - if (props?.selectedAgentPolicies) { - setSelectedAgentPolicies(props?.selectedAgentPolicies); - } }; const stepsBack = () => { @@ -189,7 +157,6 @@ export const CreatePackagePolicyMultiPage: CreatePackagePolicyParams = ({ setIsManaged={toggleIsManaged} setEnrolledAgentIds={setEnrolledAgentIds} enrolledAgentIds={enrolledAgentIds} - onCanceled={onCanceled} /> ); }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/components/layout.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/components/layout.tsx index c5170d33eee68..d6138fc7dc7a2 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/components/layout.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/components/layout.tsx @@ -48,6 +48,7 @@ export const CreatePackagePolicySinglePageLayout: React.FunctionComponent<{ onClick: React.ReactEventHandler; }>; children: React.ReactNode; + withHeader?: boolean; }> = memo( ({ from, @@ -59,6 +60,7 @@ export const CreatePackagePolicySinglePageLayout: React.FunctionComponent<{ children, 'data-test-subj': dataTestSubj, tabs = [], + withHeader = true, }) => { const isAdd = useMemo(() => ['package', 'policy'].includes(from), [from]); const isEdit = useMemo(() => ['edit', 'package-edit'].includes(from), [from]); @@ -252,7 +254,8 @@ export const CreatePackagePolicySinglePageLayout: React.FunctionComponent<{ ) : undefined; const maxWidth = 800; - return ( + + return withHeader ? ( {children} + ) : ( + children ); } ); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/form.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/form.tsx index 4c4c7b311cb06..181a7e51e1933 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/form.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/form.tsx @@ -133,6 +133,17 @@ const DEFAULT_PACKAGE_POLICY = { inputs: [], }; +export interface UseOnSubmitProps { + agentCount: number; + selectedPolicyTab: SelectedPolicyTab; + newAgentPolicy: NewAgentPolicy; + withSysMonitoring: boolean; + queryParamsPolicyId: string | undefined; + packageInfo?: PackageInfo; + integrationToEnable?: string; + hasFleetAddAgentsPrivileges: boolean; +} + export function useOnSubmit({ agentCount, selectedPolicyTab, @@ -142,16 +153,7 @@ export function useOnSubmit({ packageInfo, integrationToEnable, hasFleetAddAgentsPrivileges, -}: { - packageInfo?: PackageInfo; - newAgentPolicy: NewAgentPolicy; - withSysMonitoring: boolean; - selectedPolicyTab: SelectedPolicyTab; - agentCount: number; - queryParamsPolicyId: string | undefined; - integrationToEnable?: string; - hasFleetAddAgentsPrivileges: boolean; -}) { +}: UseOnSubmitProps) { const { notifications } = useStartServices(); const confirmForceInstall = useConfirmForceInstall(); const spaceSettings = useSpaceSettingsContext(); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx index b206df51de00b..c05e8d988dce8 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx @@ -103,12 +103,13 @@ const CustomEuiBottomBar = styled(EuiBottomBar)` z-index: 50; `; -export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ +export const CreatePackagePolicySinglePage: React.FC = ({ from, queryParamsPolicyId, prerelease, - onNext, - onCanceled, + onAddAgent, + onCancel, + withHeader = true, }) => { const { agents: { enabled: isFleetEnabled }, @@ -116,7 +117,7 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ const hasFleetAddAgentsPrivileges = useAuthz().fleet.addAgents; const { params } = useRouteMatch(); const { pkgkey: pkgKeyContext } = useIntegrationsStateContext(); - const pkgkey = params.pkgkey || pkgKeyContext; + const pkgkey = params.pkgkey || pkgKeyContext || ''; const fleetStatus = useFleetStatus(); const { docLinks } = useStartServices(); @@ -195,22 +196,24 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ }); const handleNavigateAddAgent = useCallback(() => { - if (onNext) { - onNext({ selectedAgentPolicies: agentPolicies }); + if (onAddAgent) { + onAddAgent({ selectedAgentPolicies: agentPolicies }); } else { if (savedPackagePolicy) { navigateAddAgent(savedPackagePolicy); } } - }, [onNext, agentPolicies, savedPackagePolicy, navigateAddAgent]); + }, [onAddAgent, agentPolicies, savedPackagePolicy, navigateAddAgent]); const handleCancellation = useCallback(() => { - if (onCanceled) { - onCanceled(); + if (onCancel) { + onCancel(); } else { - navigateAddAgentHelp(savedPackagePolicy); + if (savedPackagePolicy) { + navigateAddAgentHelp(savedPackagePolicy); + } } - }, [onCanceled, savedPackagePolicy, navigateAddAgentHelp]); + }, [onCancel, savedPackagePolicy, navigateAddAgentHelp]); const setPolicyValidation = useCallback( (selectedTab: SelectedPolicyTab, updatedAgentPolicy: NewAgentPolicy) => { @@ -307,12 +310,22 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ () => ({ from, cancelUrl, - onCancel: cancelClickHandler, + onCancel: onCancel ?? cancelClickHandler, agentPolicies, packageInfo, integrationInfo, + withHeader, }), - [agentPolicies, cancelClickHandler, cancelUrl, from, integrationInfo, packageInfo] + [ + agentPolicies, + cancelClickHandler, + cancelUrl, + from, + integrationInfo, + onCancel, + packageInfo, + withHeader, + ] ); const stepSelectAgentPolicy = useMemo( @@ -531,7 +544,7 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ onConfirm={onSubmit} onCancel={() => { setFormState('VALID'); - onCanceled?.(); + onCancel?.(); }} /> )} @@ -649,11 +662,10 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ - {/* eslint-disable-next-line @elastic/eui/href-or-on-click */} void; -}>; + onAddAgent: (param?: { selectedAgentPolicies: AgentPolicy[] }) => void; + onCancel: () => void; + withHeader?: boolean; +} diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_requirements_page/components/enrollment_recommendation.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_requirements_page/components/enrollment_recommendation.tsx index 9ad6cc482fb1a..c74b6cf542175 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_requirements_page/components/enrollment_recommendation.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_requirements_page/components/enrollment_recommendation.tsx @@ -21,7 +21,8 @@ import { useFlyoutContext, useStartServices } from '../../../../hooks'; export const EnrollmentRecommendation: React.FunctionComponent<{ showStandaloneTab: () => void; -}> = ({ showStandaloneTab }) => { + handleAddFleetServer?: () => void; +}> = ({ showStandaloneTab, handleAddFleetServer }) => { const flyoutContext = useFlyoutContext(); const { docLinks } = useStartServices(); @@ -80,7 +81,7 @@ export const EnrollmentRecommendation: React.FunctionComponent<{ - + void; } | { showEnrollmentRecommendation?: true; showStandaloneTab: () => void; + handleAddFleetServer?: () => void; } -> = ({ showStandaloneTab = () => {}, showEnrollmentRecommendation = true }) => { +> = ({ + showStandaloneTab = () => {}, + showEnrollmentRecommendation = true, + handleAddFleetServer, +}) => { const startService = useStartServices(); const deploymentUrl = startService.cloud?.deploymentUrl; const authz = useAuthz(); @@ -61,7 +67,10 @@ export const FleetServerRequirementPage: React.FunctionComponent< ) : permissionsError ? ( ) : showEnrollmentRecommendation ? ( - + ) : ( )} diff --git a/x-pack/plugins/fleet/public/applications/integrations/hooks/use_fleet_integration_context.tsx b/x-pack/plugins/fleet/public/applications/integrations/hooks/use_fleet_integration_context.tsx index d4005439a39e8..bbc0f71b123a1 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/hooks/use_fleet_integration_context.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/hooks/use_fleet_integration_context.tsx @@ -8,6 +8,7 @@ import React, { createContext } from 'react'; import { FleetStatusProvider, + FlyoutContextProvider, KibanaVersionContext, UIExtensionsContextProvider, } from '../../../hooks'; @@ -38,7 +39,9 @@ export const FleetIntegrationsStateContextProvider: React.FC<{ - {children} + + {children} + diff --git a/x-pack/plugins/fleet/public/applications/integrations/hooks/use_integrations_state.tsx b/x-pack/plugins/fleet/public/applications/integrations/hooks/use_integrations_state.tsx index 47243f2b30e30..3074b0f10ec05 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/hooks/use_integrations_state.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/hooks/use_integrations_state.tsx @@ -13,6 +13,8 @@ import { useIntraAppState } from '../../../hooks'; interface IntegrationsStateContextValue { getFromIntegrations(): string | undefined; + pkgkey?: string; + panel?: string; } const IntegrationsStateContext = createContext({ @@ -24,7 +26,6 @@ export const IntegrationsStateContextProvider: FunctionComponent<{ }> = ({ children }) => { const maybeState = useIntraAppState(); const stateRef = useRef(maybeState); - console.log('myState---', maybeState); const getFromIntegrations = useCallback(() => { return stateRef.current?.fromIntegrations; }, []); @@ -33,7 +34,6 @@ export const IntegrationsStateContextProvider: FunctionComponent<{ value={{ getFromIntegrations, pkgkey: maybeState?.pkgkey, - panel: maybeState?.panel, }} > {children} 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 3652a4cec81db..1279b287202c0 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 @@ -134,21 +134,21 @@ export function Detail({ originFrom, routesEnabled = true, onAddIntegrationPolicyClick, + onDetailsTabClick, + selectedDetailsTab = 'overview', }: { originFrom?: string; routesEnabled?: boolean; onAddIntegrationPolicyClick?: () => void; + onDetailsTabClick?: (tabId: DetailViewPanelName) => void; + selectedDetailsTab?: DetailViewPanelName; }) { const { getId: getAgentPolicyId } = useAgentPolicyContext(); - const { - getFromIntegrations, - pkgkey: pkgKeyContext, - panel: panelContext, - } = useIntegrationsStateContext(); - const [selectedPanel, setSelectedPanel] = useState(panelContext); + const { getFromIntegrations, pkgkey: pkgKeyContext } = useIntegrationsStateContext(); + const { pkgkey: pkgkeyParam, panel: panelParam } = useParams(); const pkgkey = pkgkeyParam || pkgKeyContext; - const panel = panelParam || selectedPanel; + const panel = panelParam || selectedDetailsTab; const { getHref, getPath } = useLink(); const history = useHistory(); const { pathname, search, hash } = useLocation(); @@ -656,7 +656,7 @@ export function Detail({ isSelected: panel === 'overview', 'data-test-subj': `tab-overview`, href: - originFrom !== 'onboarding-integration' + originFrom !== 'onboarding-hub' ? getHref('integration_details_overview', { pkgkey: packageInfoKey, ...(integration ? { integration } : {}), @@ -664,7 +664,7 @@ export function Detail({ : undefined, onClick: (e: React.MouseEvent) => { e.preventDefault(); - setSelectedPanel('overview'); + onDetailsTabClick?.('overview'); }, }, ]; @@ -680,7 +680,7 @@ export function Detail({ ), isSelected: panel === 'policies', 'data-test-subj': `tab-policies`, - href: routesEnabled + href: onDetailsTabClick ? getHref('integration_details_policies', { pkgkey: packageInfoKey, ...(integration ? { integration } : {}), @@ -688,7 +688,7 @@ export function Detail({ : undefined, onClick: (e: React.MouseEvent) => { e.preventDefault(); - setSelectedPanel('policies'); + onDetailsTabClick?.('policies'); }, }); } @@ -710,7 +710,7 @@ export function Detail({ ), isSelected: panel === 'assets', 'data-test-subj': `tab-assets`, - href: routesEnabled + href: onDetailsTabClick ? getHref('integration_details_assets', { pkgkey: packageInfoKey, ...(integration ? { integration } : {}), @@ -718,7 +718,7 @@ export function Detail({ : undefined, onClick: (e: React.MouseEvent) => { e.preventDefault(); - setSelectedPanel('assets'); + onDetailsTabClick?.('assets'); }, }); } @@ -734,7 +734,7 @@ export function Detail({ ), isSelected: panel === 'settings', 'data-test-subj': `tab-settings`, - href: routesEnabled + href: onDetailsTabClick ? getHref('integration_details_settings', { pkgkey: packageInfoKey, ...(integration ? { integration } : {}), @@ -742,7 +742,7 @@ export function Detail({ : undefined, onClick: (e: React.MouseEvent) => { e.preventDefault(); - setSelectedPanel('settings'); + onDetailsTabClick?.('settings'); }, }); } @@ -758,7 +758,7 @@ export function Detail({ ), isSelected: panel === 'configs', 'data-test-subj': `tab-configs`, - href: routesEnabled + href: onDetailsTabClick ? getHref('integration_details_configs', { pkgkey: packageInfoKey, ...(integration ? { integration } : {}), @@ -766,7 +766,7 @@ export function Detail({ : undefined, onClick: (e: React.MouseEvent) => { e.preventDefault(); - setSelectedPanel('configs'); + onDetailsTabClick?.('configs'); }, }); } @@ -782,7 +782,7 @@ export function Detail({ ), isSelected: panel === 'custom', 'data-test-subj': `tab-custom`, - href: routesEnabled + href: onDetailsTabClick ? getHref('integration_details_custom', { pkgkey: packageInfoKey, ...(integration ? { integration } : {}), @@ -790,7 +790,7 @@ export function Detail({ : undefined, onClick: (e: React.MouseEvent) => { e.preventDefault(); - setSelectedPanel('custom'); + onDetailsTabClick?.('custom'); }, }); } @@ -806,7 +806,7 @@ export function Detail({ ), isSelected: panel === 'api-reference', 'data-test-subj': `tab-api-reference`, - href: routesEnabled + href: onDetailsTabClick ? getHref('integration_details_api_reference', { pkgkey: packageInfoKey, ...(integration ? { integration } : {}), @@ -814,7 +814,7 @@ export function Detail({ : undefined, onClick: (e: React.MouseEvent) => { e.preventDefault(); - setSelectedPanel('api-reference'); + onDetailsTabClick?.('api-reference'); }, }); } @@ -833,7 +833,7 @@ export function Detail({ showConfigTab, showCustomTab, showDocumentationTab, - routesEnabled, + onDetailsTabClick, numOfDeferredInstallations, ]); diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/confirm_agent_enrollment.tsx b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/confirm_agent_enrollment.tsx index f067351546bde..5a4a3146fbae1 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/confirm_agent_enrollment.tsx +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/confirm_agent_enrollment.tsx @@ -23,6 +23,7 @@ interface Props { policyId?: string; troubleshootLink: string; onClickViewAgents?: () => void; + onClickViewIncomingData?: () => void; agentCount: number; showLoading?: boolean; isLongEnrollment?: boolean; @@ -99,6 +100,7 @@ export const ConfirmAgentEnrollment: React.FunctionComponent = ({ policyId, troubleshootLink, onClickViewAgents, + onClickViewIncomingData, agentCount, showLoading = false, isLongEnrollment = false, @@ -198,6 +200,17 @@ export const ConfirmAgentEnrollment: React.FunctionComponent = ({ })} )} + {onClickViewIncomingData && ( + + {i18n.translate('xpack.fleet.agentEnrollment.confirmation.button', { + defaultMessage: 'View incoming data', + })} + + )} ); }; diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/instructions.tsx b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/instructions.tsx index bcb92303d8510..c5cdc3a433de6 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/instructions.tsx +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/instructions.tsx @@ -9,6 +9,7 @@ import React, { useEffect } from 'react'; import { EuiText, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; +import type { FleetStatus } from '../../hooks'; import { useFleetStatus, useFleetServerStandalone, useGetEnrollmentSettings } from '../../hooks'; import { FleetServerRequirementPage } from '../../applications/fleet/sections/agents/agent_requirements_page'; import { FLEET_SERVER_PACKAGE } from '../../constants'; @@ -19,6 +20,22 @@ import type { InstructionProps } from './types'; import { ManagedSteps, StandaloneSteps } from './steps'; import { DefaultMissingRequirements } from './default_missing_requirements'; +export const shouldShowFleetServerEnrollment = ({ + isFleetServerStandalone, + isFleetServerPolicySelected, + enrollmentSettings, + fleetStatusMissingRequirements, +}: { + isFleetServerStandalone: boolean; + isFleetServerPolicySelected: boolean | undefined; + enrollmentSettings: any; + fleetStatusMissingRequirements: FleetStatus['missingRequirements']; +}) => + !isFleetServerStandalone && + !isFleetServerPolicySelected && + (!enrollmentSettings?.fleet_server.has_active || + (fleetStatusMissingRequirements ?? []).some((r) => r === FLEET_SERVER_PACKAGE)); + export const Instructions = (props: InstructionProps) => { const { isFleetServerPolicySelected, @@ -28,7 +45,8 @@ export const Instructions = (props: InstructionProps) => { setSelectionType, mode, setMode, - isIntegrationFlow, + from, + handleAddFleetServer, } = props; const fleetStatus = useFleetStatus(); const { isFleetServerStandalone } = useFleetServerStandalone(); @@ -42,11 +60,12 @@ export const Instructions = (props: InstructionProps) => { isFleetServerStandalone || (fleetStatus.isReady && enrollmentSettings?.fleet_server.has_active && fleetServerHost); - const showFleetServerEnrollment = - !isFleetServerStandalone && - !isFleetServerPolicySelected && - (!enrollmentSettings?.fleet_server.has_active || - (fleetStatus.missingRequirements ?? []).some((r) => r === FLEET_SERVER_PACKAGE)); + const showFleetServerEnrollment = shouldShowFleetServerEnrollment({ + isFleetServerStandalone, + isFleetServerPolicySelected, + enrollmentSettings, + fleetStatusMissingRequirements: fleetStatus.missingRequirements, + }); useEffect(() => { // If we detect a CloudFormation integration, we want to hide the selection type @@ -56,12 +75,12 @@ export const Instructions = (props: InstructionProps) => { props.cloudSecurityIntegration?.cloudShellUrl ) { setSelectionType(undefined); - } else if (!isIntegrationFlow && showAgentEnrollment) { + } else if (showAgentEnrollment) { setSelectionType('radio'); } else { setSelectionType('tabs'); } - }, [isIntegrationFlow, showAgentEnrollment, setSelectionType, props.cloudSecurityIntegration]); + }, [from, showAgentEnrollment, setSelectionType, props.cloudSecurityIntegration]); if (isLoadingEnrollmentSettings || isLoadingAgentPolicies) return ; @@ -71,7 +90,12 @@ export const Instructions = (props: InstructionProps) => { if (mode === 'managed') { if (showFleetServerEnrollment) { - return setMode('standalone')} />; + return ( + setMode('standalone')} + handleAddFleetServer={handleAddFleetServer} + /> + ); } else if (showAgentEnrollment) { return ( <> diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/agent_enrollment_confirmation_step.tsx b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/agent_enrollment_confirmation_step.tsx index 761b662917d46..374feae579c11 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/agent_enrollment_confirmation_step.tsx +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/agent_enrollment_confirmation_step.tsx @@ -43,6 +43,7 @@ export const AgentEnrollmentConfirmationStep = ({ selectedPolicyId, troubleshootLink, onClickViewAgents, + onClickViewIncomingData, agentCount, showLoading, poll = true, @@ -51,6 +52,7 @@ export const AgentEnrollmentConfirmationStep = ({ selectedPolicyId?: string; troubleshootLink: string; onClickViewAgents?: () => void; + onClickViewIncomingData?: () => void; agentCount: number; poll?: boolean; showLoading?: boolean; @@ -72,6 +74,7 @@ export const AgentEnrollmentConfirmationStep = ({ policyId={selectedPolicyId} troubleshootLink={troubleshootLink} onClickViewAgents={onClickViewAgents} + onClickViewIncomingData={onClickViewIncomingData} agentCount={agentCount} showLoading={!isComplete || showLoading} isLongEnrollment={isLongEnrollment} diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/compute_steps.tsx b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/compute_steps.tsx index 660aafa339b47..fe633efc16208 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/compute_steps.tsx +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/compute_steps.tsx @@ -157,9 +157,11 @@ export const ManagedSteps: React.FunctionComponent = ({ setMode, selectionType, onClickViewAgents, + onClickViewIncomingData, isK8s, cloudSecurityIntegration, installedPackagePolicy, + from, }) => { const core = useStartServices(); const { docLinks } = core; @@ -265,13 +267,14 @@ export const ManagedSteps: React.FunctionComponent = ({ AgentEnrollmentConfirmationStep({ selectedPolicyId: selectedPolicy?.id, onClickViewAgents, + onClickViewIncomingData, troubleshootLink: link, agentCount: enrolledAgentIds.length, isLongEnrollment: cloudSecurityIntegration !== undefined, }) ); } - if (selectedPolicy) { + if (selectedPolicy && from !== 'onboarding-hub') { steps.push( IncomingDataConfirmationStep({ agentIds: enrolledAgentIds, @@ -295,18 +298,20 @@ export const ManagedSteps: React.FunctionComponent = ({ selectionType, cloudSecurityIntegration, apiKeyData, + from, mode, setMode, enrollToken, + fleetServerHost, installManagedCommands, + gcpProjectId, isK8s, - fleetServerHost, onClickViewAgents, + onClickViewIncomingData, link, enrolledAgentIds, agentDataConfirmed, installedPackagePolicy, - gcpProjectId, ]); if (!agentVersion) { diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/types.ts b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/types.ts index 0c2e51e294b14..6c872ffa655f1 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/types.ts +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/types.ts @@ -5,6 +5,7 @@ * 2.0. */ +import type { EditPackagePolicyFrom } from '../../applications/fleet/sections/agent_policy/create_package_policy_page/types'; import type { AgentPolicy, DownloadSource, FleetProxy } from '../../types'; import type { InstalledIntegrationPolicy } from './use_get_agent_incoming_data'; @@ -67,13 +68,21 @@ export interface FlyOutProps extends BaseProps { selectedAgentPolicies?: AgentPolicy[]; } +export interface AgentPolicySelectionProps extends BaseProps { + onCancel?: () => void; + defaultMode?: FlyoutMode; + selectedAgentPolicies?: AgentPolicy[]; + onNext: () => void; + setEnrolledAgentIds: (ids: string[]) => void; +} export interface InstructionProps extends BaseProps { agentPolicies: AgentPolicy[]; selectedPolicy: AgentPolicy | undefined; setSelectedPolicyId: (policyId?: string) => void; refreshAgentPolicies: () => void; isLoadingAgentPolicies?: boolean; - onClickViewAgents: () => void; + onClickViewAgents?: () => void; + onClickViewIncomingData?: () => void; mode: FlyoutMode; setMode: (v: FlyoutMode) => void; selectionType: SelectionType; @@ -84,4 +93,7 @@ export interface InstructionProps extends BaseProps { fleetProxy?: FleetProxy; downloadSource?: DownloadSource; downloadSourceProxy?: FleetProxy; + hasIncomingDataStep?: boolean; + handleAddFleetServer?: () => void; + from?: EditPackagePolicyFrom; } diff --git a/x-pack/plugins/fleet/public/hooks/use_fleet_status.tsx b/x-pack/plugins/fleet/public/hooks/use_fleet_status.tsx index 019940dc92238..320a1be5fc4cd 100644 --- a/x-pack/plugins/fleet/public/hooks/use_fleet_status.tsx +++ b/x-pack/plugins/fleet/public/hooks/use_fleet_status.tsx @@ -25,7 +25,7 @@ export interface FleetStatusProviderProps { spaceId?: string; } -interface FleetStatus extends FleetStatusProviderProps { +export interface FleetStatus extends FleetStatusProviderProps { refetch: () => Promise; // This flag allows us to opt into displaying the Fleet Server enrollment instructions even if diff --git a/x-pack/plugins/fleet/public/index.ts b/x-pack/plugins/fleet/public/index.ts index eea00d893c9d1..18aaa72ac5f84 100644 --- a/x-pack/plugins/fleet/public/index.ts +++ b/x-pack/plugins/fleet/public/index.ts @@ -10,7 +10,6 @@ import type { PluginInitializerContext } from '@kbn/core/public'; import { lazy } from 'react'; import { FleetPlugin } from './plugin'; -import type { UIExtensionsStorage } from './types'; export type { GetPackagesResponse } from './types'; export { installationStatuses } from '../common/constants'; 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 e3ffef62ac4ec..640fb52b45c71 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 @@ -35,6 +35,9 @@ export interface CreatePackagePolicyRouteState { onSaveQueryParams?: { [key in OnSaveQueryParamKeys]?: OnSaveQueryParamOpts; }; + pkgkey?: string; + + panel?: string; } /** @@ -58,6 +61,10 @@ export interface IntegrationsAppBrowseRouteState { forAgentPolicyId: string; /** The integration tab the user navigated to details from */ fromIntegrations: 'installed' | 'updates_available' | undefined; + + pkgkey?: string; + + panel?: string; } /** diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/integration_card_grid_tabs.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/integration_card_grid_tabs.tsx index 5f9b291d92be9..fd20aa0c8129e 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/integration_card_grid_tabs.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/integration_card_grid_tabs.tsx @@ -7,13 +7,11 @@ import React, { lazy, Suspense, useMemo, useCallback, useEffect, useRef, useState } from 'react'; import { - EuiButton, EuiButtonGroup, EuiFlexGroup, EuiFlexItem, EuiModal, EuiModalBody, - EuiModalFooter, EuiModalHeader, EuiPortal, EuiSkeletonText, @@ -24,6 +22,7 @@ import { noop } from 'lodash'; import { css } from '@emotion/react'; import { useKibana } from '@kbn/kibana-react-plugin/public'; +import type { DetailViewPanelName } from '@kbn/fleet-plugin/public/applications/integrations/sections/epm/screens/detail'; import { withLazyHook } from '../../../../../common/components/with_lazy_hook'; import { useStoredIntegrationSearchTerm, @@ -77,11 +76,13 @@ const FleetIntegrationsStateContextProvider = lazy(async () => ({ .then((pkg) => pkg.FleetIntegrationsStateContextProvider), })); -const integrationStepMap = { - 0: 'Add integration', - 1: 'Install Elastic Agent', - 2: 'Confirm incoming data', -} +const integrationStepMap = [ + 'Add integration', + 'Check fleet server requirement', + 'Add Fleet server', + 'Install Elastic Agent', + 'Confirm incoming data', +]; export const IntegrationsCardGridTabsComponent = React.memo( ({ installedIntegrationsCount, isAgentRequired, useAvailablePackages }) => { @@ -108,18 +109,19 @@ export const IntegrationsCardGridTabsComponent = React.memo(); const [modalView, setModalView] = useState<'overview' | 'configure-integration' | 'add-agent'>( 'overview' ); - const [integrationStep, setIntegrationStep] = useState(0); + const [integrationStep, onStepNext] = useState(0); const onAddIntegrationPolicyClick = useCallback(() => { setModalView('configure-integration'); }, []); const closeModal = useCallback(() => { setIsModalVisible(false); setModalView('overview'); - setIntegrationStep(0); + setSelectedDetailsTab('overview'); + onStepNext(0); }, []); const onCardClicked = useCallback((name: string) => { setIsModalVisible(true); @@ -138,6 +140,7 @@ export const IntegrationsCardGridTabsComponent = React.memo INTEGRATION_TABS_BY_ID[toggleIdSelected], [toggleIdSelected]); + const [selectedDetailsTab, setSelectedDetailsTab] = useState('overview'); const onSearchTermChanged = useCallback( (searchQuery: string) => { setSearchTerm(searchQuery); @@ -150,6 +153,15 @@ export const IntegrationsCardGridTabsComponent = React.memo { + setModalView('overview'); + setSelectedDetailsTab('assets'); + }, []); + + const onDetailsTabClick = useCallback((detailsTab: DetailViewPanelName) => { + setSelectedDetailsTab(detailsTab); + }, []); + useEffect(() => { setCategory(selectedTab.category ?? ''); setSelectedSubCategory(selectedTab.subCategory); @@ -261,30 +273,33 @@ export const IntegrationsCardGridTabsComponent = React.memo - {modalView === 'configure-integration' && ({`step indicator place holder. Integration step: ${integrationStepMap[integrationStep]}`})} + {modalView === 'configure-integration' && ( + {`step indicator place holder. Integration step: ${integrationStepMap[integrationStep]}`} + )} {modalView === 'overview' && ( )} {modalView === 'configure-integration' && ( )} diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/use_integration_card_list.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/use_integration_card_list.ts index 0af94c763f7f1..09c9f92688b71 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/use_integration_card_list.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/use_integration_card_list.ts @@ -101,6 +101,7 @@ const addSecuritySpecificProps = ({ APP_UI_ID, { path: ONBOARDING_PATH, state: { pkgkey: card.pkgkey, onCancelUrl: onboardingLink } }, ], + onDoneNavigateTo: [APP_UI_ID, { path: ONBOARDING_PATH, state: { pkgkey: card.pkgkey } }], onCancelUrl: onboardingLink, onSaveNavigateTo: [APP_UI_ID, { path: ONBOARDING_PATH, state: { pkgkey: card.pkgkey } }], pkgkey: card.pkgkey,