Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FLEET] New Integration Policy Details page for use in Integrations section #85355

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { FormattedMessage } from '@kbn/i18n/react';
import { EuiText, EuiLink, EuiSpacer } from '@elastic/eui';
import { TutorialModuleNoticeComponent } from 'src/plugins/home/public';
import { useGetPackages, useLink, useCapabilities } from '../../hooks';
import { pkgKeyFromPackageInfo } from '../../services/pkg_key_from_package_info';

const TutorialModuleNotice: TutorialModuleNoticeComponent = memo(({ moduleName }) => {
const { getHref } = useLink();
Expand Down Expand Up @@ -41,7 +42,7 @@ const TutorialModuleNotice: TutorialModuleNoticeComponent = memo(({ moduleName }
availableAsIntegrationLink: (
<EuiLink
href={getHref('integration_details', {
pkgkey: `${pkgInfo.name}-${pkgInfo.version}`,
pkgkey: pkgKeyFromPackageInfo(pkgInfo),
})}
>
<FormattedMessage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export type StaticPage =

export type DynamicPage =
| 'integration_details'
| 'integration_policy_edit'
| 'policy_details'
| 'add_integration_from_policy'
| 'add_integration_to_policy'
Expand All @@ -41,6 +42,7 @@ export const PAGE_ROUTING_PATHS = {
integrations_all: '/integrations',
integrations_installed: '/integrations/installed',
integration_details: '/integrations/detail/:pkgkey/:panel?',
integration_policy_edit: '/integrations/edit-integration/:packagePolicyId',
policies: '/policies',
policies_list: '/policies',
policy_details: '/policies/:policyId/:tabId?',
Expand Down Expand Up @@ -69,6 +71,8 @@ export const pagePathGetters: {
integrations_installed: () => '/integrations/installed',
integration_details: ({ pkgkey, panel }) =>
`/integrations/detail/${pkgkey}${panel ? `/${panel}` : ''}`,
integration_policy_edit: ({ packagePolicyId }) =>
`/integrations/edit-integration/${packagePolicyId}`,
policies: () => '/policies',
policies_list: () => '/policies',
policy_details: ({ policyId, tabId }) => `/policies/${policyId}${tabId ? `/${tabId}` : ''}`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,20 @@ const breadcrumbGetters: {
},
{ text: pkgTitle },
],
integration_policy_edit: ({ pkgTitle, pkgkey, policyName }) => [
BASE_BREADCRUMB,
{
href: pagePathGetters.integrations(),
text: i18n.translate('xpack.fleet.breadcrumbs.integrationPageTitle', {
defaultMessage: 'Integration',
}),
},
{
href: pagePathGetters.integration_details({ pkgkey, panel: 'policies' }),
text: pkgTitle,
},
{ text: policyName },
],
policies: () => [
BASE_BREADCRUMB,
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const CreatePackagePolicyPageLayout: React.FunctionComponent<{
'data-test-subj': dataTestSubj,
}) => {
const pageTitle = useMemo(() => {
if ((from === 'package' || from === 'edit') && packageInfo) {
if ((from === 'package' || from === 'package-edit' || from === 'edit') && packageInfo) {
return (
<EuiFlexGroup alignItems="center" gutterSize="m">
<EuiFlexItem grow={false}>
Expand Down Expand Up @@ -76,7 +76,7 @@ export const CreatePackagePolicyPageLayout: React.FunctionComponent<{
);
}

return from === 'edit' ? (
return from === 'edit' || from === 'package-edit' ? (
<EuiText>
<h1>
<FormattedMessage
Expand All @@ -98,7 +98,7 @@ export const CreatePackagePolicyPageLayout: React.FunctionComponent<{
}, [from, packageInfo]);

const pageDescription = useMemo(() => {
return from === 'edit' ? (
return from === 'edit' || from === 'package-edit' ? (
<FormattedMessage
id="xpack.fleet.editPackagePolicy.pageDescription"
defaultMessage="Modify integration settings and deploy changes to the selected agent policy."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import { useUIExtension } from '../../../hooks/use_ui_extension';
import { ExtensionWrapper } from '../../../components/extension_wrapper';
import { PackagePolicyEditExtensionComponentProps } from '../../../types';
import { PLUGIN_ID } from '../../../../../../common/constants';
import { pkgKeyFromPackageInfo } from '../../../services/pkg_key_from_package_info';

const StepsWithLessPadding = styled(EuiSteps)`
.euiStep__content {
Expand Down Expand Up @@ -404,7 +405,7 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => {
? packageInfo && (
<IntegrationBreadcrumb
pkgTitle={packageInfo.title}
pkgkey={`${packageInfo.name}-${packageInfo.version}`}
pkgkey={pkgKeyFromPackageInfo(packageInfo)}
/>
)
: agentPolicy && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { AgentPolicy, PackageInfo, PackagePolicy, NewPackagePolicy } from '../..
import { packageToPackagePolicyInputs } from '../../../services';
import { Loading } from '../../../components';
import { PackagePolicyValidationResults } from './services';
import { pkgKeyFromPackageInfo } from '../../../services/pkg_key_from_package_info';

export const StepDefinePackagePolicy: React.FunctionComponent<{
agentPolicy: AgentPolicy;
Expand All @@ -34,8 +35,8 @@ export const StepDefinePackagePolicy: React.FunctionComponent<{
// Update package policy's package and agent policy info
useEffect(() => {
const pkg = packagePolicy.package;
const currentPkgKey = pkg ? `${pkg.name}-${pkg.version}` : '';
const pkgKey = `${packageInfo.name}-${packageInfo.version}`;
const currentPkgKey = pkg ? pkgKeyFromPackageInfo(pkg) : '';
const pkgKey = pkgKeyFromPackageInfo(packageInfo);

// If package has changed, create shell package policy with input&stream values based on package info
if (currentPkgKey !== pkgKey) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
sendGetPackageInfoByKey,
} from '../../../hooks';
import { PackageIcon } from '../../../components/package_icon';
import { pkgKeyFromPackageInfo } from '../../../services/pkg_key_from_package_info';

export const StepSelectPackage: React.FunctionComponent<{
agentPolicyId: string;
Expand All @@ -32,7 +33,7 @@ export const StepSelectPackage: React.FunctionComponent<{
}) => {
// Selected package state
const [selectedPkgKey, setSelectedPkgKey] = useState<string | undefined>(
packageInfo ? `${packageInfo.name}-${packageInfo.version}` : undefined
packageInfo ? pkgKeyFromPackageInfo(packageInfo) : undefined
);
const [selectedPkgError, setSelectedPkgError] = useState<Error>();

Expand Down Expand Up @@ -92,7 +93,7 @@ export const StepSelectPackage: React.FunctionComponent<{
updatePackageInfo(undefined);
}
};
if (!packageInfo || selectedPkgKey !== `${packageInfo.name}-${packageInfo.version}`) {
if (!packageInfo || selectedPkgKey !== pkgKeyFromPackageInfo(packageInfo)) {
fetchPackageInfo();
}
}, [selectedPkgKey, packageInfo, updatePackageInfo, setIsLoadingSecondStep]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
* you may not use this file except in compliance with the Elastic License.
*/

export type CreatePackagePolicyFrom = 'package' | 'policy' | 'edit';
export type CreatePackagePolicyFrom = 'package' | 'package-edit' | 'policy' | 'edit';
export type PackagePolicyFormState = 'VALID' | 'INVALID' | 'CONFIRM' | 'LOADING' | 'SUBMITTED';
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import React, { useState, useEffect, useCallback, useMemo } from 'react';
import React, { useState, useEffect, useCallback, useMemo, memo } from 'react';
import { useRouteMatch, useHistory } from 'react-router-dom';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
Expand Down Expand Up @@ -45,15 +45,24 @@ import { useUIExtension } from '../../../hooks/use_ui_extension';
import { ExtensionWrapper } from '../../../components/extension_wrapper';
import { GetOnePackagePolicyResponse } from '../../../../../../common/types/rest_spec';
import { PackagePolicyEditExtensionComponentProps } from '../../../types';
import { pkgKeyFromPackageInfo } from '../../../services/pkg_key_from_package_info';

export const EditPackagePolicyPage: React.FunctionComponent = () => {
export const EditPackagePolicyPage = memo(() => {
const {
params: { packagePolicyId },
} = useRouteMatch<{ policyId: string; packagePolicyId: string }>();

return <EditPackagePolicyForm packagePolicyId={packagePolicyId} />;
});

export const EditPackagePolicyForm = memo<{
packagePolicyId: string;
from?: CreatePackagePolicyFrom;
}>(({ packagePolicyId, from = 'edit' }) => {
const { notifications } = useStartServices();
const {
agents: { enabled: isFleetEnabled },
} = useConfig();
const {
params: { policyId, packagePolicyId },
} = useRouteMatch<{ policyId: string; packagePolicyId: string }>();
const history = useHistory();
const { getHref, getPath } = useLink();

Expand All @@ -76,16 +85,31 @@ export const EditPackagePolicyPage: React.FunctionComponent = () => {
GetOnePackagePolicyResponse['item']
>();

const policyId = agentPolicy?.id ?? '';

// Retrieve agent policy, package, and package policy info
useEffect(() => {
const getData = async () => {
setIsLoadingData(true);
setLoadingError(undefined);
try {
const [{ data: agentPolicyData }, { data: packagePolicyData }] = await Promise.all([
sendGetOneAgentPolicy(policyId),
sendGetOnePackagePolicy(packagePolicyId),
]);
const {
data: packagePolicyData,
error: packagePolicyError,
} = await sendGetOnePackagePolicy(packagePolicyId);

if (packagePolicyError) {
throw packagePolicyError;
}

const { data: agentPolicyData, error: agentPolicyError } = await sendGetOneAgentPolicy(
packagePolicyData!.item.policy_id
);

if (agentPolicyError) {
throw agentPolicyError;
}

if (agentPolicyData?.item) {
setAgentPolicy(agentPolicyData.item);
}
Expand Down Expand Up @@ -123,7 +147,7 @@ export const EditPackagePolicyPage: React.FunctionComponent = () => {
setPackagePolicy(newPackagePolicy);
if (packagePolicyData.item.package) {
const { data: packageData } = await sendGetPackageInfoByKey(
`${packagePolicyData.item.package.name}-${packagePolicyData.item.package.version}`
pkgKeyFromPackageInfo(packagePolicyData.item.package)
);
if (packageData?.response) {
setPackageInfo(packageData.response);
Expand All @@ -150,7 +174,7 @@ export const EditPackagePolicyPage: React.FunctionComponent = () => {
}
};

if (isFleetEnabled) {
if (isFleetEnabled && policyId) {
getAgentCount();
}
}, [policyId, isFleetEnabled]);
Expand Down Expand Up @@ -214,8 +238,32 @@ export const EditPackagePolicyPage: React.FunctionComponent = () => {
[updatePackagePolicy]
);

// Cancel url
const cancelUrl = getHref('policy_details', { policyId });
// Cancel url + Success redirect Path:
// if `from === 'edit'` then it links back to Policy Details
// if `from === 'package-edit'` then it links back to the Integration Policy List
const cancelUrl = useMemo((): string => {
if (packageInfo && policyId) {
return from === 'package-edit'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we expect this to expand to more pages, perhaps a switch here so we can be explicit about the default case (if from is something unexpected, perhaps new places added down the road, where the PR forgot to add themselves here).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, agreed a switch will make sense if we add more types for from. I don't see that happening at this time and when I get around to introducing the layout that the mocks call for, I hope to revert this in favor of having props that specifically allow for setting things like the cancelUrl that should be used in the form.

? getHref('integration_details', {
pkgkey: pkgKeyFromPackageInfo(packageInfo!),
panel: 'policies',
})
: getHref('policy_details', { policyId });
}
return '/';
}, [from, getHref, packageInfo, policyId]);

const successRedirectPath = useMemo(() => {
if (packageInfo && policyId) {
return from === 'package-edit'
? getPath('integration_details', {
pkgkey: pkgKeyFromPackageInfo(packageInfo!),
panel: 'policies',
})
: getPath('policy_details', { policyId });
}
return '/';
}, [from, getPath, packageInfo, policyId]);

// Save package policy
const [formState, setFormState] = useState<PackagePolicyFormState>('INVALID');
Expand All @@ -237,7 +285,7 @@ export const EditPackagePolicyPage: React.FunctionComponent = () => {
}
const { error } = await savePackagePolicy();
if (!error) {
history.push(getPath('policy_details', { policyId }));
history.push(successRedirectPath);
notifications.toasts.addSuccess({
title: i18n.translate('xpack.fleet.editPackagePolicy.updatedNotificationTitle', {
defaultMessage: `Successfully updated '{packagePolicyName}'`,
Expand Down Expand Up @@ -287,7 +335,7 @@ export const EditPackagePolicyPage: React.FunctionComponent = () => {
};

const layoutProps = {
from: 'edit' as CreatePackagePolicyFrom,
from,
cancelUrl,
agentPolicy,
packageInfo,
Expand Down Expand Up @@ -363,13 +411,21 @@ export const EditPackagePolicyPage: React.FunctionComponent = () => {
error={
loadingError ||
i18n.translate('xpack.fleet.editPackagePolicy.errorLoadingDataMessage', {
defaultMessage: 'There was an error loading this intergration information',
defaultMessage: 'There was an error loading this integration information',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All credit goes to WebStorm 🎉

})
}
/>
) : (
<>
<Breadcrumb policyName={agentPolicy.name} policyId={policyId} />
{from === 'package' || from === 'package-edit' ? (
<IntegrationsBreadcrumb
pkgkey={pkgKeyFromPackageInfo(packageInfo)}
pkgTitle={packageInfo.title}
policyName={packagePolicy.name}
/>
) : (
<PoliciesBreadcrumb policyName={agentPolicy.name} policyId={policyId} />
)}
{formState === 'CONFIRM' && (
<ConfirmDeployAgentPolicyModal
agentCount={agentCount}
Expand Down Expand Up @@ -424,12 +480,21 @@ export const EditPackagePolicyPage: React.FunctionComponent = () => {
)}
</CreatePackagePolicyPageLayout>
);
};
});

const Breadcrumb: React.FunctionComponent<{ policyName: string; policyId: string }> = ({
const PoliciesBreadcrumb: React.FunctionComponent<{ policyName: string; policyId: string }> = ({
policyName,
policyId,
}) => {
useBreadcrumbs('edit_integration', { policyName, policyId });
return null;
};

const IntegrationsBreadcrumb = memo<{
pkgTitle: string;
policyName: string;
pkgkey: string;
}>(({ pkgTitle, policyName, pkgkey }) => {
useBreadcrumbs('integration_policy_edit', { policyName, pkgTitle, pkgkey });
return null;
});
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { Loading } from '../../../components';
import { PackageList } from '../../../types';
import { useLocalSearch, searchIdField } from '../hooks';
import { PackageCard } from './package_card';
import { pkgKeyFromPackageInfo } from '../../../services/pkg_key_from_package_info';

interface ListProps {
isLoading?: boolean;
Expand Down Expand Up @@ -118,7 +119,7 @@ function GridColumn({ list }: GridColumnProps) {
<EuiFlexGrid gutterSize="l" columns={3}>
{list.length ? (
list.map((item) => (
<EuiFlexItem key={`${item.name}-${item.version}`}>
<EuiFlexItem key={pkgKeyFromPackageInfo(item)}>
<PackageCard {...item} />
</EuiFlexItem>
))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useBreadcrumbs } from '../../hooks';
import { CreatePackagePolicyPage } from '../agent_policy/create_package_policy_page';
import { EPMHomePage } from './screens/home';
import { Detail } from './screens/detail';
import { Policy } from './screens/policy';

export const EPMApp: React.FunctionComponent = () => {
useBreadcrumbs('integrations');
Expand All @@ -20,6 +21,9 @@ export const EPMApp: React.FunctionComponent = () => {
<Route path={PAGE_ROUTING_PATHS.add_integration_to_policy}>
<CreatePackagePolicyPage />
</Route>
<Route path={PAGE_ROUTING_PATHS.integration_policy_edit}>
<Policy />
</Route>
<Route path={PAGE_ROUTING_PATHS.integration_details}>
<Detail />
</Route>
Expand Down
Loading