[FLEET] New Integration Policy Details page for use in Integrations section (#85355)
* new UI route to show Edit Package Policy page * Package policy List items point to new Integration Policy details page * Refactor to use common service to generate pkgKey * add breadcrumb for edit policy under integrations
This commit is contained in:
parent
5bb47d48b0
commit
6c52ac84c6
|
@ -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();
|
||||
|
@ -41,7 +42,7 @@ const TutorialModuleNotice: TutorialModuleNoticeComponent = memo(({ moduleName }
|
|||
availableAsIntegrationLink: (
|
||||
<EuiLink
|
||||
href={getHref('integration_details', {
|
||||
pkgkey: `${pkgInfo.name}-${pkgInfo.version}`,
|
||||
pkgkey: pkgKeyFromPackageInfo(pkgInfo),
|
||||
})}
|
||||
>
|
||||
<FormattedMessage
|
||||
|
|
|
@ -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'
|
||||
|
@ -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?',
|
||||
|
@ -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}` : ''}`,
|
||||
|
|
|
@ -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,
|
||||
{
|
||||
|
|
|
@ -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}>
|
||||
|
@ -76,7 +76,7 @@ export const CreatePackagePolicyPageLayout: React.FunctionComponent<{
|
|||
);
|
||||
}
|
||||
|
||||
return from === 'edit' ? (
|
||||
return from === 'edit' || from === 'package-edit' ? (
|
||||
<EuiText>
|
||||
<h1>
|
||||
<FormattedMessage
|
||||
|
@ -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."
|
||||
|
|
|
@ -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 {
|
||||
|
@ -404,7 +405,7 @@ export const CreatePackagePolicyPage: React.FunctionComponent = () => {
|
|||
? packageInfo && (
|
||||
<IntegrationBreadcrumb
|
||||
pkgTitle={packageInfo.title}
|
||||
pkgkey={`${packageInfo.name}-${packageInfo.version}`}
|
||||
pkgkey={pkgKeyFromPackageInfo(packageInfo)}
|
||||
/>
|
||||
)
|
||||
: agentPolicy && (
|
||||
|
|
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
@ -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>();
|
||||
|
||||
|
@ -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]);
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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';
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -150,7 +174,7 @@ export const EditPackagePolicyPage: React.FunctionComponent = () => {
|
|||
}
|
||||
};
|
||||
|
||||
if (isFleetEnabled) {
|
||||
if (isFleetEnabled && policyId) {
|
||||
getAgentCount();
|
||||
}
|
||||
}, [policyId, isFleetEnabled]);
|
||||
|
@ -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'
|
||||
? 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');
|
||||
|
@ -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}'`,
|
||||
|
@ -287,7 +335,7 @@ export const EditPackagePolicyPage: React.FunctionComponent = () => {
|
|||
};
|
||||
|
||||
const layoutProps = {
|
||||
from: 'edit' as CreatePackagePolicyFrom,
|
||||
from,
|
||||
cancelUrl,
|
||||
agentPolicy,
|
||||
packageInfo,
|
||||
|
@ -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',
|
||||
})
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<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}
|
||||
|
@ -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;
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
|
@ -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>
|
||||
))
|
||||
|
|
|
@ -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');
|
||||
|
@ -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>
|
||||
|
|
|
@ -10,17 +10,26 @@ import React, { lazy, memo } from 'react';
|
|||
import { PAGE_ROUTING_PATHS, pagePathGetters } from '../../../../constants';
|
||||
import { Route } from 'react-router-dom';
|
||||
import {
|
||||
GetAgentPoliciesResponse,
|
||||
GetFleetStatusResponse,
|
||||
GetInfoResponse,
|
||||
GetPackagePoliciesResponse,
|
||||
} from '../../../../../../../common/types/rest_spec';
|
||||
import { DetailViewPanelName, KibanaAssetType } from '../../../../../../../common/types/models';
|
||||
import { epmRouteService, fleetSetupRouteService } from '../../../../../../../common/services';
|
||||
import { act } from '@testing-library/react';
|
||||
import {
|
||||
agentPolicyRouteService,
|
||||
epmRouteService,
|
||||
fleetSetupRouteService,
|
||||
packagePolicyRouteService,
|
||||
} from '../../../../../../../common/services';
|
||||
import { act, cleanup } from '@testing-library/react';
|
||||
|
||||
describe('when on integration detail', () => {
|
||||
const detailPageUrlPath = pagePathGetters.integration_details({ pkgkey: 'nginx-0.3.7' });
|
||||
const pkgkey = 'nginx-0.3.7';
|
||||
const detailPageUrlPath = pagePathGetters.integration_details({ pkgkey });
|
||||
let testRenderer: TestRenderer;
|
||||
let renderResult: ReturnType<typeof testRenderer.render>;
|
||||
let mockedApi: MockedApi;
|
||||
const render = () =>
|
||||
(renderResult = testRenderer.render(
|
||||
<Route path={PAGE_ROUTING_PATHS.integration_details}>
|
||||
|
@ -30,10 +39,15 @@ describe('when on integration detail', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
testRenderer = createTestRendererMock();
|
||||
mockApiCalls(testRenderer.startServices.http);
|
||||
mockedApi = mockApiCalls(testRenderer.startServices.http);
|
||||
testRenderer.history.push(detailPageUrlPath);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
window.location.hash = '#/';
|
||||
});
|
||||
|
||||
describe('and a custom UI extension is NOT registered', () => {
|
||||
beforeEach(() => render());
|
||||
|
||||
|
@ -137,9 +151,48 @@ describe('when on integration detail', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('and on the Policies Tab', () => {
|
||||
const policiesTabURLPath = pagePathGetters.integration_details({ pkgkey, panel: 'policies' });
|
||||
beforeEach(() => {
|
||||
testRenderer.history.push(policiesTabURLPath);
|
||||
render();
|
||||
});
|
||||
|
||||
it('should display policies list', () => {
|
||||
const table = renderResult.getByTestId('integrationPolicyTable');
|
||||
expect(table).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should link to integration policy detail when an integration policy is clicked', async () => {
|
||||
await mockedApi.waitForApi();
|
||||
const firstPolicy = renderResult.getByTestId('integrationNameLink') as HTMLAnchorElement;
|
||||
expect(firstPolicy.href).toEqual(
|
||||
'http://localhost/mock/app/fleet#/integrations/edit-integration/e8a37031-2907-44f6-89d2-98bd493f60dc'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const mockApiCalls = (http: MockedFleetStartServices['http']) => {
|
||||
interface MockedApi {
|
||||
/** Will return a promise that resolves when triggered APIs are complete */
|
||||
waitForApi: () => Promise<void>;
|
||||
}
|
||||
|
||||
const mockApiCalls = (http: MockedFleetStartServices['http']): MockedApi => {
|
||||
let inflightApiCalls = 0;
|
||||
const apiDoneListeners: Array<() => void> = [];
|
||||
const markApiCallAsHandled = async () => {
|
||||
inflightApiCalls++;
|
||||
await new Promise((r) => setTimeout(r, 1));
|
||||
inflightApiCalls--;
|
||||
|
||||
// If no more pending API calls, then notify listeners
|
||||
if (inflightApiCalls === 0 && apiDoneListeners.length > 0) {
|
||||
apiDoneListeners.splice(0).forEach((listener) => listener());
|
||||
}
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
const epmPackageResponse: GetInfoResponse = {
|
||||
response: {
|
||||
|
@ -369,7 +422,7 @@ const mockApiCalls = (http: MockedFleetStartServices['http']) => {
|
|||
owner: { github: 'elastic/integrations-services' },
|
||||
latestVersion: '0.3.7',
|
||||
removable: true,
|
||||
status: 'not_installed',
|
||||
status: 'installed',
|
||||
},
|
||||
} as GetInfoResponse;
|
||||
|
||||
|
@ -388,24 +441,162 @@ On Windows, the module was tested with Nginx installed from the Chocolatey repos
|
|||
|
||||
const agentsSetupResponse: GetFleetStatusResponse = { isReady: true, missing_requirements: [] };
|
||||
|
||||
const packagePoliciesResponse: GetPackagePoliciesResponse = {
|
||||
items: [
|
||||
{
|
||||
id: 'e8a37031-2907-44f6-89d2-98bd493f60dc',
|
||||
version: 'WzgzMiwxXQ==',
|
||||
name: 'nginx-1',
|
||||
description: '',
|
||||
namespace: 'default',
|
||||
policy_id: '521c1b70-3976-11eb-ad1c-3baa423084d9',
|
||||
enabled: true,
|
||||
output_id: '',
|
||||
inputs: [
|
||||
{
|
||||
type: 'logfile',
|
||||
enabled: true,
|
||||
streams: [
|
||||
{
|
||||
enabled: true,
|
||||
data_stream: { type: 'logs', dataset: 'nginx.access' },
|
||||
vars: { paths: { value: ['/var/log/nginx/access.log*'], type: 'text' } },
|
||||
id: 'logfile-nginx.access-e8a37031-2907-44f6-89d2-98bd493f60dc',
|
||||
compiled_stream: {
|
||||
paths: ['/var/log/nginx/access.log*'],
|
||||
exclude_files: ['.gz$'],
|
||||
processors: [{ add_locale: null }],
|
||||
},
|
||||
},
|
||||
{
|
||||
enabled: true,
|
||||
data_stream: { type: 'logs', dataset: 'nginx.error' },
|
||||
vars: { paths: { value: ['/var/log/nginx/error.log*'], type: 'text' } },
|
||||
id: 'logfile-nginx.error-e8a37031-2907-44f6-89d2-98bd493f60dc',
|
||||
compiled_stream: {
|
||||
paths: ['/var/log/nginx/error.log*'],
|
||||
exclude_files: ['.gz$'],
|
||||
multiline: {
|
||||
pattern: '^\\d{4}\\/\\d{2}\\/\\d{2} ',
|
||||
negate: true,
|
||||
match: 'after',
|
||||
},
|
||||
processors: [{ add_locale: null }],
|
||||
},
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
data_stream: { type: 'logs', dataset: 'nginx.ingress_controller' },
|
||||
vars: { paths: { value: ['/var/log/nginx/ingress.log*'], type: 'text' } },
|
||||
id: 'logfile-nginx.ingress_controller-e8a37031-2907-44f6-89d2-98bd493f60dc',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'nginx/metrics',
|
||||
enabled: true,
|
||||
streams: [
|
||||
{
|
||||
enabled: true,
|
||||
data_stream: { type: 'metrics', dataset: 'nginx.stubstatus' },
|
||||
vars: {
|
||||
period: { value: '10s', type: 'text' },
|
||||
server_status_path: { value: '/nginx_status', type: 'text' },
|
||||
},
|
||||
id: 'nginx/metrics-nginx.stubstatus-e8a37031-2907-44f6-89d2-98bd493f60dc',
|
||||
compiled_stream: {
|
||||
metricsets: ['stubstatus'],
|
||||
hosts: ['http://127.0.0.1:80'],
|
||||
period: '10s',
|
||||
server_status_path: '/nginx_status',
|
||||
},
|
||||
},
|
||||
],
|
||||
vars: { hosts: { value: ['http://127.0.0.1:80'], type: 'text' } },
|
||||
},
|
||||
],
|
||||
package: { name: 'nginx', title: 'Nginx', version: '0.3.7' },
|
||||
revision: 1,
|
||||
created_at: '2020-12-09T13:46:31.013Z',
|
||||
created_by: 'elastic',
|
||||
updated_at: '2020-12-09T13:46:31.013Z',
|
||||
updated_by: 'elastic',
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
page: 1,
|
||||
perPage: 20,
|
||||
};
|
||||
|
||||
const agentPoliciesResponse: GetAgentPoliciesResponse = {
|
||||
items: [
|
||||
{
|
||||
id: '521c1b70-3976-11eb-ad1c-3baa423084d9',
|
||||
name: 'Default',
|
||||
namespace: 'default',
|
||||
description: 'Default agent policy created by Kibana',
|
||||
status: 'active',
|
||||
package_policies: [
|
||||
'4d09bd78-b0ad-4238-9fa3-d87d3c887c73',
|
||||
'2babac18-eb8e-4ce4-b53b-4b7c5f507019',
|
||||
'e8a37031-2907-44f6-89d2-98bd493f60dc',
|
||||
],
|
||||
is_default: true,
|
||||
monitoring_enabled: ['logs', 'metrics'],
|
||||
revision: 6,
|
||||
updated_at: '2020-12-09T13:46:31.840Z',
|
||||
updated_by: 'elastic',
|
||||
agents: 0,
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
page: 1,
|
||||
perPage: 100,
|
||||
};
|
||||
|
||||
http.get.mockImplementation(async (path) => {
|
||||
if (typeof path === 'string') {
|
||||
if (path === epmRouteService.getInfoPath(`nginx-0.3.7`)) {
|
||||
markApiCallAsHandled();
|
||||
return epmPackageResponse;
|
||||
}
|
||||
|
||||
if (path === epmRouteService.getFilePath('/package/nginx/0.3.7/docs/README.md')) {
|
||||
markApiCallAsHandled();
|
||||
return packageReadMe;
|
||||
}
|
||||
|
||||
if (path === fleetSetupRouteService.getFleetSetupPath()) {
|
||||
markApiCallAsHandled();
|
||||
return agentsSetupResponse;
|
||||
}
|
||||
|
||||
if (path === packagePolicyRouteService.getListPath()) {
|
||||
markApiCallAsHandled();
|
||||
return packagePoliciesResponse;
|
||||
}
|
||||
|
||||
if (path === agentPolicyRouteService.getListPath()) {
|
||||
markApiCallAsHandled();
|
||||
return agentPoliciesResponse;
|
||||
}
|
||||
|
||||
const err = new Error(`API [GET ${path}] is not MOCKED!`);
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(err);
|
||||
console.error(err);
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
waitForApi() {
|
||||
return new Promise((resolve) => {
|
||||
if (inflightApiCalls > 0) {
|
||||
apiDoneListeners.push(resolve);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -43,6 +43,7 @@ import { Content } from './content';
|
|||
import './index.scss';
|
||||
import { useUIExtension } from '../../../../hooks/use_ui_extension';
|
||||
import { PLUGIN_ID } from '../../../../../../../common/constants';
|
||||
import { pkgKeyFromPackageInfo } from '../../../../services/pkg_key_from_package_info';
|
||||
|
||||
export const DEFAULT_PANEL: DetailViewPanelName = 'overview';
|
||||
|
||||
|
@ -315,7 +316,7 @@ export function Detail() {
|
|||
isSelected: panelId === panel,
|
||||
'data-test-subj': `tab-${panelId}`,
|
||||
href: getHref('integration_details', {
|
||||
pkgkey: `${packageInfo?.name}-${packageInfo?.version}`,
|
||||
pkgkey: pkgKeyFromPackageInfo(packageInfo || {}),
|
||||
panel: panelId,
|
||||
}),
|
||||
};
|
||||
|
|
|
@ -36,8 +36,8 @@ const IntegrationDetailsLink = memo<{
|
|||
return (
|
||||
<EuiLink
|
||||
className="eui-textTruncate"
|
||||
href={getHref('edit_integration', {
|
||||
policyId: packagePolicy.policy_id,
|
||||
data-test-subj="integrationNameLink"
|
||||
href={getHref('integration_policy_edit', {
|
||||
packagePolicyId: packagePolicy.id,
|
||||
})}
|
||||
>
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { memo } from 'react';
|
||||
import { useRouteMatch } from 'react-router-dom';
|
||||
import { EditPackagePolicyForm } from '../../../agent_policy/edit_package_policy_page';
|
||||
|
||||
export const Policy = memo(() => {
|
||||
const {
|
||||
params: { packagePolicyId },
|
||||
} = useRouteMatch<{ packagePolicyId: string }>();
|
||||
|
||||
return <EditPackagePolicyForm packagePolicyId={packagePolicyId} from="package-edit" />;
|
||||
});
|
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export const pkgKeyFromPackageInfo = <T extends { name: string; version: string }>(
|
||||
packageInfo: T
|
||||
): string => {
|
||||
return `${packageInfo.name}-${packageInfo.version}`;
|
||||
};
|
Loading…
Reference in a new issue