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 cd5b997d9c788..9a1c943763bd8 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 @@ -267,6 +267,29 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ ); const extensionView = useUIExtension(packagePolicy.package?.name ?? '', 'package-policy-create'); + const replaceDefineStepView = useUIExtension( + packagePolicy.package?.name ?? '', + 'package-policy-replace-define-step' + ); + + if (replaceDefineStepView && extensionView) { + throw new Error( + "'package-policy-create' and 'package-policy-replace-define-step' cannot both be registered as UI extensions" + ); + } + + const replaceStepConfigurePackagePolicy = replaceDefineStepView && packageInfo?.name && ( + + + + ); const stepConfigurePackagePolicy = useMemo( () => @@ -329,7 +352,7 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ defaultMessage: 'Configure integration', }), 'data-test-subj': 'dataCollectionSetupStep', - children: stepConfigurePackagePolicy, + children: replaceStepConfigurePackagePolicy || stepConfigurePackagePolicy, }, { title: i18n.translate('xpack.fleet.createPackagePolicy.stepSelectAgentPolicyTitle', { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.test.tsx index c295cdd41cecb..303629a99bb69 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.test.tsx @@ -331,11 +331,42 @@ describe('edit package policy page', () => { expect(useStartServices().application.navigateToUrl).not.toHaveBeenCalled(); }); - it('should show ready for upgrade if package useLatestPackageVersion and no conflicts', async () => { - (useUIExtension as MockFn).mockReturnValue({ - useLatestPackageVersion: true, - Component: TestComponent, + it("throws when both 'package-policy-edit' and 'package-policy-replace-define-step' are defined", async () => { + (useUIExtension as MockFn) + .mockReturnValueOnce({ + view: 'package-policy-edit', + Component: TestComponent, + }) + .mockReturnValueOnce({ + view: 'package-policy-replace-define-step', + Component: TestComponent, + }) + .mockReturnValueOnce({ + view: 'package-policy-edit-tabs', + Component: TestComponent, + }); + + render(); + + await waitFor(() => { + expect(renderResult.getByTestId('euiErrorBoundary')).toBeVisible(); }); + }); + + it('should show ready for upgrade if package useLatestPackageVersion and no conflicts', async () => { + (useUIExtension as MockFn) + .mockReturnValueOnce({ + view: 'package-policy-edit', + useLatestPackageVersion: true, + Component: TestComponent, + }) + .mockReturnValueOnce(undefined) + .mockReturnValueOnce({ + view: 'package-policy-edit-tabs', + useLatestPackageVersion: true, + Component: TestComponent, + }); + (sendUpgradePackagePolicyDryRun as MockFn).mockResolvedValue({ data: [ { @@ -357,10 +388,19 @@ describe('edit package policy page', () => { }); it('should show review field conflicts if package useLatestPackageVersion and has conflicts', async () => { - (useUIExtension as MockFn).mockReturnValue({ - useLatestPackageVersion: true, - Component: TestComponent, - }); + (useUIExtension as MockFn) + .mockReturnValueOnce({ + view: 'package-policy-edit', + useLatestPackageVersion: true, + Component: TestComponent, + }) + .mockReturnValueOnce(undefined) + .mockReturnValueOnce({ + view: 'package-policy-edit-tabs', + useLatestPackageVersion: true, + Component: TestComponent, + }); + (sendUpgradePackagePolicyDryRun as MockFn).mockResolvedValue({ data: [ { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx index afab7a48ebb76..b066457b0aa2e 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/index.tsx @@ -35,7 +35,7 @@ import { } from '../../../../integrations/hooks'; import { Loading, - Error, + Error as ErrorComponent, ExtensionWrapper, EuiButtonWithTooltip, DevtoolsRequestFlyoutButton, @@ -240,10 +240,21 @@ export const EditPackagePolicyForm = memo<{ }; const extensionView = useUIExtension(packagePolicy.package?.name ?? '', 'package-policy-edit'); + const replaceDefineStepView = useUIExtension( + packagePolicy.package?.name ?? '', + 'package-policy-replace-define-step' + ); const extensionTabsView = useUIExtension( packagePolicy.package?.name ?? '', 'package-policy-edit-tabs' ); + + if (replaceDefineStepView && extensionView) { + throw new Error( + "'package-policy-create' and 'package-policy-replace-define-step' cannot both be registered as UI extensions" + ); + } + const tabsViews = extensionTabsView?.tabs; const [selectedTab, setSelectedTab] = useState(0); @@ -339,6 +350,20 @@ export const EditPackagePolicyForm = memo<{ ] ); + const replaceConfigurePackage = replaceDefineStepView && originalPackagePolicy && packageInfo && ( + + + + ); + const { showDevtoolsRequest: isShowDevtoolRequestExperimentEnabled } = ExperimentalFeaturesService.get(); @@ -361,7 +386,7 @@ export const EditPackagePolicyForm = memo<{ {isLoadingData ? ( ) : loadingError || !agentPolicy || !packageInfo ? ( - )} - {configurePackage} + {replaceConfigurePackage || configurePackage} {/* Extra space to accomodate the EuiBottomBar height */} diff --git a/x-pack/plugins/fleet/public/types/ui_extensions.ts b/x-pack/plugins/fleet/public/types/ui_extensions.ts index fc8726e7b813a..53ae5322f0d9d 100644 --- a/x-pack/plugins/fleet/public/types/ui_extensions.ts +++ b/x-pack/plugins/fleet/public/types/ui_extensions.ts @@ -10,7 +10,9 @@ import type { ComponentType, LazyExoticComponent } from 'react'; import type { FleetServerAgentComponentUnit } from '../../common/types/models/agent'; -import type { Agent, NewPackagePolicy, PackageInfo, PackagePolicy } from '.'; +import type { PackagePolicyValidationResults } from '../services'; + +import type { Agent, AgentPolicy, NewPackagePolicy, PackageInfo, PackagePolicy } from '.'; /** Register a Fleet UI extension */ export type UIExtensionRegistrationCallback = (extensionPoint: UIExtensionPoint) => void; @@ -20,6 +22,22 @@ export interface UIExtensionsStorage { [key: string]: Partial>; } +/** + * UI Component Extension is used to replace the Define Step on + * the pages displaying the ability to edit/create an Integration Policy + */ +export type PackagePolicyReplaceDefineStepExtensionComponent = + ComponentType; + +export type PackagePolicyReplaceDefineStepExtensionComponentProps = ( + | (PackagePolicyEditExtensionComponentProps & { isEditPage: true }) + | (PackagePolicyCreateExtensionComponentProps & { isEditPage: false }) +) & { + validationResults?: PackagePolicyValidationResults; + agentPolicy?: AgentPolicy; + packageInfo: PackageInfo; +}; + /** * UI Component Extension is used on the pages displaying the ability to edit an * Integration Policy @@ -73,6 +91,12 @@ export interface PackageGenericErrorsListProps { packageErrors: FleetServerAgentComponentUnit[]; } +export interface PackagePolicyReplaceDefineStepExtension { + package: string; + view: 'package-policy-replace-define-step'; + Component: LazyExoticComponent; +} + /** Extension point registration contract for Integration Policy Edit views */ export interface PackagePolicyEditExtension { package: string; @@ -184,6 +208,7 @@ export interface AgentEnrollmentFlyoutFinalStepExtension { /** Fleet UI Extension Point */ export type UIExtensionPoint = + | PackagePolicyReplaceDefineStepExtension | PackagePolicyEditExtension | PackagePolicyResponseExtension | PackagePolicyEditTabsExtension