[Unified Integrations] Create Services, Storybook, Replacements Card; add to Fleet (#113816)
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
2dd01c0484
commit
4f85f5e841
|
@ -8,6 +8,7 @@ const STORYBOOKS = [
|
|||
'canvas',
|
||||
'codeeditor',
|
||||
'ci_composite',
|
||||
'custom_integrations',
|
||||
'url_template_editor',
|
||||
'dashboard',
|
||||
'dashboard_enhanced',
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
"home": "src/plugins/home",
|
||||
"flot": "packages/kbn-ui-shared-deps-src/src/flot_charts",
|
||||
"charts": "src/plugins/charts",
|
||||
"customIntegrations": "src/plugins/custom_integrations",
|
||||
"esUi": "src/plugins/es_ui_shared",
|
||||
"devTools": "src/plugins/dev_tools",
|
||||
"expressions": "src/plugins/expressions",
|
||||
|
|
|
@ -12,6 +12,7 @@ export const storybookAliases = {
|
|||
canvas: 'x-pack/plugins/canvas/storybook',
|
||||
codeeditor: 'src/plugins/kibana_react/public/code_editor/.storybook',
|
||||
ci_composite: '.ci/.storybook',
|
||||
custom_integrations: 'src/plugins/custom_integrations/storybook',
|
||||
url_template_editor: 'src/plugins/kibana_react/public/url_template_editor/.storybook',
|
||||
dashboard: 'src/plugins/dashboard/.storybook',
|
||||
dashboard_enhanced: 'x-pack/plugins/dashboard_enhanced/.storybook',
|
||||
|
|
|
@ -12,5 +12,8 @@
|
|||
"extraPublicDirs": [
|
||||
"common"
|
||||
],
|
||||
"requiredPlugins": [
|
||||
"presentationUtil"
|
||||
],
|
||||
"optionalPlugins": []
|
||||
}
|
||||
|
|
31
src/plugins/custom_integrations/public/components/index.tsx
Normal file
31
src/plugins/custom_integrations/public/components/index.tsx
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React, { Suspense, ComponentType, ReactElement, Ref } from 'react';
|
||||
import { EuiLoadingSpinner, EuiErrorBoundary } from '@elastic/eui';
|
||||
|
||||
/**
|
||||
* A HOC which supplies React.Suspense with a fallback component, and a `EuiErrorBoundary` to contain errors.
|
||||
* @param Component A component deferred by `React.lazy`
|
||||
* @param fallback A fallback component to render while things load; default is `EuiLoadingSpinner`
|
||||
*/
|
||||
export const withSuspense = <P extends {}, R = {}>(
|
||||
Component: ComponentType<P>,
|
||||
fallback: ReactElement | null = <EuiLoadingSpinner />
|
||||
) =>
|
||||
React.forwardRef((props: P, ref: Ref<R>) => {
|
||||
return (
|
||||
<EuiErrorBoundary>
|
||||
<Suspense fallback={fallback}>
|
||||
<Component {...props} ref={ref} />
|
||||
</Suspense>
|
||||
</EuiErrorBoundary>
|
||||
);
|
||||
});
|
||||
|
||||
export const LazyReplacementCard = React.lazy(() => import('./replacement_card'));
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { ReplacementCard } from './replacement_card';
|
||||
|
||||
export { ReplacementCard, Props } from './replacement_card';
|
||||
|
||||
// required for dynamic import using React.lazy()
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default ReplacementCard;
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
/** @jsx jsx */
|
||||
|
||||
import { css, jsx } from '@emotion/react';
|
||||
|
||||
import {
|
||||
htmlIdGenerator,
|
||||
EuiButton,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiPanel,
|
||||
EuiText,
|
||||
EuiAccordion,
|
||||
EuiLink,
|
||||
useEuiTheme,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
import { CustomIntegration } from '../../../common';
|
||||
import { usePlatformService } from '../../services';
|
||||
|
||||
export interface Props {
|
||||
replacements: Array<Pick<CustomIntegration, 'id' | 'uiInternalPath' | 'title'>>;
|
||||
}
|
||||
|
||||
// TODO - clintandrewhall: should use doc-links service
|
||||
const URL_COMPARISON = 'https://ela.st/beats-agent-comparison';
|
||||
|
||||
const idGenerator = htmlIdGenerator('replacementCard');
|
||||
const alsoAvailable = i18n.translate('customIntegrations.components.replacementAccordionLabel', {
|
||||
defaultMessage: 'Also available in Beats',
|
||||
});
|
||||
|
||||
const link = (
|
||||
<EuiLink
|
||||
href={URL_COMPARISON}
|
||||
data-test-subj="customIntegrationsBeatsAgentComparisonLink"
|
||||
external
|
||||
>
|
||||
<FormattedMessage
|
||||
id="customIntegrations.components.replacementAccordion.comparisonPageLinkLabel"
|
||||
defaultMessage="comparison page"
|
||||
/>
|
||||
</EuiLink>
|
||||
);
|
||||
|
||||
/**
|
||||
* A pure component, an accordion panel which can display information about replacements for a given EPR module.
|
||||
*/
|
||||
export const ReplacementCard = ({ replacements }: Props) => {
|
||||
const { euiTheme } = useEuiTheme();
|
||||
const { getAbsolutePath } = usePlatformService();
|
||||
|
||||
if (replacements.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const buttons = replacements.map((replacement) => (
|
||||
<EuiFlexItem grow={false}>
|
||||
<span>
|
||||
<EuiButton
|
||||
key={replacement.id}
|
||||
href={getAbsolutePath(replacement.uiInternalPath)}
|
||||
fullWidth={false}
|
||||
size="s"
|
||||
>
|
||||
{replacement.title}
|
||||
</EuiButton>
|
||||
</span>
|
||||
</EuiFlexItem>
|
||||
));
|
||||
|
||||
return (
|
||||
<div
|
||||
css={css`
|
||||
& .euiAccordion__button {
|
||||
color: ${euiTheme.colors.link};
|
||||
}
|
||||
& .euiAccordion-isOpen .euiAccordion__childWrapper {
|
||||
margin-top: ${euiTheme.size.m};
|
||||
}
|
||||
`}
|
||||
>
|
||||
<EuiAccordion id={idGenerator()} buttonContent={alsoAvailable} paddingSize="none">
|
||||
<EuiPanel color="subdued" hasShadow={false} paddingSize="m">
|
||||
<EuiFlexGroup direction="column" gutterSize="m">
|
||||
<EuiFlexItem>
|
||||
<EuiText size="s">
|
||||
<FormattedMessage
|
||||
id="customIntegrations.components.replacementAccordion.recommendationDescription"
|
||||
defaultMessage="Elastic Agent Integrations are recommended, but you can also use Beats. For more
|
||||
details, check out our {link}."
|
||||
values={{
|
||||
link,
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup direction="column" gutterSize="m">
|
||||
{buttons}
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
</EuiAccordion>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Meta } from '@storybook/react';
|
||||
|
||||
import { ReplacementCard as ConnectedComponent } from './replacement_card';
|
||||
import { ReplacementCard as PureComponent } from './replacement_card.component';
|
||||
|
||||
export default {
|
||||
title: 'Replacement Card',
|
||||
description:
|
||||
'An accordion panel which can display information about Beats alternatives to a given EPR module, (if available)',
|
||||
decorators: [
|
||||
(storyFn, { globals }) => (
|
||||
<div
|
||||
style={{
|
||||
padding: 40,
|
||||
backgroundColor:
|
||||
globals.euiTheme === 'v8.dark' || globals.euiTheme === 'v7.dark' ? '#1D1E24' : '#FFF',
|
||||
width: 350,
|
||||
}}
|
||||
>
|
||||
{storyFn()}
|
||||
</div>
|
||||
),
|
||||
],
|
||||
} as Meta;
|
||||
|
||||
interface Args {
|
||||
eprPackageName: string;
|
||||
}
|
||||
|
||||
const args: Args = {
|
||||
eprPackageName: 'nginx',
|
||||
};
|
||||
|
||||
const argTypes = {
|
||||
eprPackageName: {
|
||||
control: {
|
||||
type: 'radio',
|
||||
options: ['nginx', 'okta', 'aws', 'apache'],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export function ReplacementCard({ eprPackageName }: Args) {
|
||||
return <ConnectedComponent {...{ eprPackageName }} />;
|
||||
}
|
||||
|
||||
ReplacementCard.args = args;
|
||||
ReplacementCard.argTypes = argTypes;
|
||||
|
||||
export function Component() {
|
||||
return (
|
||||
<PureComponent
|
||||
replacements={[
|
||||
{ id: 'foo', title: 'Foo', uiInternalPath: '#' },
|
||||
{ id: 'bar', title: 'Bar', uiInternalPath: '#' },
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { useFindService } from '../../services';
|
||||
|
||||
import { ReplacementCard as Component } from './replacement_card.component';
|
||||
|
||||
export interface Props {
|
||||
eprPackageName: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A data-connected component which can query about Beats-based replacement options for a given EPR module.
|
||||
*/
|
||||
export const ReplacementCard = ({ eprPackageName }: Props) => {
|
||||
const { findReplacementIntegrations } = useFindService();
|
||||
const integrations = useAsync(async () => {
|
||||
return await findReplacementIntegrations({ shipper: 'beats', eprPackageName });
|
||||
}, [eprPackageName]);
|
||||
|
||||
const { loading, value: replacements } = integrations;
|
||||
|
||||
if (loading || !replacements || replacements.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <Component {...{ replacements }} />;
|
||||
};
|
|
@ -13,4 +13,8 @@ import { CustomIntegrationsPlugin } from './plugin';
|
|||
export function plugin() {
|
||||
return new CustomIntegrationsPlugin();
|
||||
}
|
||||
|
||||
export { CustomIntegrationsSetup, CustomIntegrationsStart } from './types';
|
||||
|
||||
export { withSuspense, LazyReplacementCard } from './components';
|
||||
export { filterCustomIntegrations } from './services/find';
|
||||
|
|
|
@ -6,7 +6,11 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { CustomIntegrationsSetup } from './types';
|
||||
import { pluginServices } from './services';
|
||||
import { PluginServiceRegistry } from '../../presentation_util/public';
|
||||
import { CustomIntegrationsSetup, CustomIntegrationsStart } from './types';
|
||||
import { CustomIntegrationsServices } from './services';
|
||||
import { providers } from './services/stub';
|
||||
|
||||
function createCustomIntegrationsSetup(): jest.Mocked<CustomIntegrationsSetup> {
|
||||
const mock: jest.Mocked<CustomIntegrationsSetup> = {
|
||||
|
@ -16,6 +20,17 @@ function createCustomIntegrationsSetup(): jest.Mocked<CustomIntegrationsSetup> {
|
|||
return mock;
|
||||
}
|
||||
|
||||
function createCustomIntegrationsStart(): jest.Mocked<CustomIntegrationsStart> {
|
||||
const registry = new PluginServiceRegistry<CustomIntegrationsServices>(providers);
|
||||
pluginServices.setRegistry(registry.start({}));
|
||||
const ContextProvider = pluginServices.getContextProvider();
|
||||
|
||||
return {
|
||||
ContextProvider: jest.fn(ContextProvider),
|
||||
};
|
||||
}
|
||||
|
||||
export const customIntegrationsMock = {
|
||||
createSetup: createCustomIntegrationsSetup,
|
||||
createStart: createCustomIntegrationsStart,
|
||||
};
|
||||
|
|
|
@ -7,13 +7,20 @@
|
|||
*/
|
||||
|
||||
import { CoreSetup, CoreStart, Plugin } from 'src/core/public';
|
||||
import { CustomIntegrationsSetup, CustomIntegrationsStart } from './types';
|
||||
import {
|
||||
CustomIntegrationsSetup,
|
||||
CustomIntegrationsStart,
|
||||
CustomIntegrationsStartDependencies,
|
||||
} from './types';
|
||||
import {
|
||||
CustomIntegration,
|
||||
ROUTES_APPEND_CUSTOM_INTEGRATIONS,
|
||||
ROUTES_REPLACEMENT_CUSTOM_INTEGRATIONS,
|
||||
} from '../common';
|
||||
|
||||
import { pluginServices } from './services';
|
||||
import { pluginServiceRegistry } from './services/kibana';
|
||||
|
||||
export class CustomIntegrationsPlugin
|
||||
implements Plugin<CustomIntegrationsSetup, CustomIntegrationsStart>
|
||||
{
|
||||
|
@ -30,8 +37,14 @@ export class CustomIntegrationsPlugin
|
|||
};
|
||||
}
|
||||
|
||||
public start(core: CoreStart): CustomIntegrationsStart {
|
||||
return {};
|
||||
public start(
|
||||
coreStart: CoreStart,
|
||||
startPlugins: CustomIntegrationsStartDependencies
|
||||
): CustomIntegrationsStart {
|
||||
pluginServices.setRegistry(pluginServiceRegistry.start({ coreStart, startPlugins }));
|
||||
return {
|
||||
ContextProvider: pluginServices.getContextProvider(),
|
||||
};
|
||||
}
|
||||
|
||||
public stop() {}
|
||||
|
|
95
src/plugins/custom_integrations/public/services/find.test.ts
Normal file
95
src/plugins/custom_integrations/public/services/find.test.ts
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { filterCustomIntegrations } from './find';
|
||||
import { CustomIntegration } from '../../common';
|
||||
|
||||
describe('Custom Integrations Find Service', () => {
|
||||
const integrations: CustomIntegration[] = [
|
||||
{
|
||||
id: 'foo',
|
||||
title: 'Foo',
|
||||
description: 'test integration',
|
||||
type: 'ui_link',
|
||||
uiInternalPath: '/path/to/foo',
|
||||
isBeta: false,
|
||||
icons: [],
|
||||
categories: ['aws', 'cloud'],
|
||||
shipper: 'tests',
|
||||
},
|
||||
{
|
||||
id: 'bar',
|
||||
title: 'Bar',
|
||||
description: 'test integration',
|
||||
type: 'ui_link',
|
||||
uiInternalPath: '/path/to/bar',
|
||||
isBeta: false,
|
||||
icons: [],
|
||||
categories: ['aws'],
|
||||
shipper: 'other',
|
||||
eprOverlap: 'eprValue',
|
||||
},
|
||||
{
|
||||
id: 'bar',
|
||||
title: 'Bar',
|
||||
description: 'test integration',
|
||||
type: 'ui_link',
|
||||
uiInternalPath: '/path/to/bar',
|
||||
isBeta: false,
|
||||
icons: [],
|
||||
categories: ['cloud'],
|
||||
shipper: 'other',
|
||||
eprOverlap: 'eprValue',
|
||||
},
|
||||
{
|
||||
id: 'baz',
|
||||
title: 'Baz',
|
||||
description: 'test integration',
|
||||
type: 'ui_link',
|
||||
uiInternalPath: '/path/to/baz',
|
||||
isBeta: false,
|
||||
icons: [],
|
||||
categories: ['cloud'],
|
||||
shipper: 'tests',
|
||||
eprOverlap: 'eprOtherValue',
|
||||
},
|
||||
];
|
||||
|
||||
describe('filterCustomIntegrations', () => {
|
||||
test('filters on shipper', () => {
|
||||
let result = filterCustomIntegrations(integrations, { shipper: 'other' });
|
||||
expect(result.length).toBe(2);
|
||||
result = filterCustomIntegrations(integrations, { shipper: 'tests' });
|
||||
expect(result.length).toBe(2);
|
||||
result = filterCustomIntegrations(integrations, { shipper: 'foobar' });
|
||||
expect(result.length).toBe(0);
|
||||
});
|
||||
test('filters on eprOverlap', () => {
|
||||
let result = filterCustomIntegrations(integrations, { eprPackageName: 'eprValue' });
|
||||
expect(result.length).toBe(2);
|
||||
result = filterCustomIntegrations(integrations, { eprPackageName: 'eprOtherValue' });
|
||||
expect(result.length).toBe(1);
|
||||
result = filterCustomIntegrations(integrations, { eprPackageName: 'otherValue' });
|
||||
expect(result.length).toBe(0);
|
||||
});
|
||||
test('filters on categories and shipper, eprOverlap', () => {
|
||||
const result = filterCustomIntegrations(integrations, {
|
||||
shipper: 'other',
|
||||
eprPackageName: 'eprValue',
|
||||
});
|
||||
expect(result.length).toBe(2);
|
||||
});
|
||||
});
|
||||
});
|
46
src/plugins/custom_integrations/public/services/find.ts
Normal file
46
src/plugins/custom_integrations/public/services/find.ts
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { CustomIntegration } from '../../common';
|
||||
|
||||
interface FindParams {
|
||||
eprPackageName?: string;
|
||||
shipper?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A plugin service that finds and returns custom integrations.
|
||||
*/
|
||||
export interface CustomIntegrationsFindService {
|
||||
findReplacementIntegrations(params?: FindParams): Promise<CustomIntegration[]>;
|
||||
findAppendedIntegrations(params?: FindParams): Promise<CustomIntegration[]>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter a set of integrations by eprPackageName, and/or shipper.
|
||||
*/
|
||||
export const filterCustomIntegrations = (
|
||||
integrations: CustomIntegration[],
|
||||
{ eprPackageName, shipper }: FindParams = {}
|
||||
) => {
|
||||
if (!eprPackageName && !shipper) {
|
||||
return integrations;
|
||||
}
|
||||
|
||||
let result = integrations;
|
||||
|
||||
if (eprPackageName) {
|
||||
result = result.filter((integration) => integration.eprOverlap === eprPackageName);
|
||||
}
|
||||
|
||||
if (shipper) {
|
||||
result = result.filter((integration) => integration.shipper === shipper);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
36
src/plugins/custom_integrations/public/services/index.ts
Normal file
36
src/plugins/custom_integrations/public/services/index.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { PluginServices } from '../../../presentation_util/public';
|
||||
|
||||
import { CustomIntegrationsFindService } from './find';
|
||||
import { CustomIntegrationsPlatformService } from './platform';
|
||||
|
||||
/**
|
||||
* Services used by the custom integrations plugin.
|
||||
*/
|
||||
export interface CustomIntegrationsServices {
|
||||
find: CustomIntegrationsFindService;
|
||||
platform: CustomIntegrationsPlatformService;
|
||||
}
|
||||
|
||||
/**
|
||||
* The `PluginServices` object for the custom integrations plugin.
|
||||
* @see /src/plugins/presentation_util/public/services/create/index.ts
|
||||
*/
|
||||
export const pluginServices = new PluginServices<CustomIntegrationsServices>();
|
||||
|
||||
/**
|
||||
* A React hook that provides connections to the `CustomIntegrationsFindService`.
|
||||
*/
|
||||
export const useFindService = () => (() => pluginServices.getHooks().find.useService())();
|
||||
|
||||
/**
|
||||
* A React hook that provides connections to the `CustomIntegrationsPlatformService`.
|
||||
*/
|
||||
export const usePlatformService = () => (() => pluginServices.getHooks().platform.useService())();
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import {
|
||||
CustomIntegration,
|
||||
ROUTES_APPEND_CUSTOM_INTEGRATIONS,
|
||||
ROUTES_REPLACEMENT_CUSTOM_INTEGRATIONS,
|
||||
} from '../../../common';
|
||||
import { KibanaPluginServiceFactory } from '../../../../presentation_util/public';
|
||||
|
||||
import { CustomIntegrationsStartDependencies } from '../../types';
|
||||
import { CustomIntegrationsFindService, filterCustomIntegrations } from '../find';
|
||||
|
||||
/**
|
||||
* A type definition for a factory to produce the `CustomIntegrationsFindService` for use in Kibana.
|
||||
* @see /src/plugins/presentation_util/public/services/create/factory.ts
|
||||
*/
|
||||
export type CustomIntegrationsFindServiceFactory = KibanaPluginServiceFactory<
|
||||
CustomIntegrationsFindService,
|
||||
CustomIntegrationsStartDependencies
|
||||
>;
|
||||
|
||||
/**
|
||||
* A factory to produce the `CustomIntegrationsFindService` for use in Kibana.
|
||||
*/
|
||||
export const findServiceFactory: CustomIntegrationsFindServiceFactory = ({ coreStart }) => ({
|
||||
findAppendedIntegrations: async (params) => {
|
||||
const integrations: CustomIntegration[] = await coreStart.http.get(
|
||||
ROUTES_APPEND_CUSTOM_INTEGRATIONS
|
||||
);
|
||||
|
||||
return filterCustomIntegrations(integrations, params);
|
||||
},
|
||||
findReplacementIntegrations: async (params) => {
|
||||
const replacements: CustomIntegration[] = await coreStart.http.get(
|
||||
ROUTES_REPLACEMENT_CUSTOM_INTEGRATIONS
|
||||
);
|
||||
|
||||
return filterCustomIntegrations(replacements, params);
|
||||
},
|
||||
});
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import {
|
||||
PluginServiceProviders,
|
||||
PluginServiceProvider,
|
||||
PluginServiceRegistry,
|
||||
KibanaPluginServiceParams,
|
||||
} from '../../../../presentation_util/public';
|
||||
|
||||
import { CustomIntegrationsServices } from '..';
|
||||
import { CustomIntegrationsStartDependencies } from '../../types';
|
||||
|
||||
import { findServiceFactory } from './find';
|
||||
import { platformServiceFactory } from './platform';
|
||||
|
||||
export { findServiceFactory } from './find';
|
||||
export { platformServiceFactory } from './platform';
|
||||
|
||||
/**
|
||||
* A set of `PluginServiceProvider`s for use in Kibana.
|
||||
* @see /src/plugins/presentation_util/public/services/create/provider.tsx
|
||||
*/
|
||||
export const pluginServiceProviders: PluginServiceProviders<
|
||||
CustomIntegrationsServices,
|
||||
KibanaPluginServiceParams<CustomIntegrationsStartDependencies>
|
||||
> = {
|
||||
find: new PluginServiceProvider(findServiceFactory),
|
||||
platform: new PluginServiceProvider(platformServiceFactory),
|
||||
};
|
||||
|
||||
/**
|
||||
* A `PluginServiceRegistry` for use in Kibana.
|
||||
* @see /src/plugins/presentation_util/public/services/create/registry.tsx
|
||||
*/
|
||||
export const pluginServiceRegistry = new PluginServiceRegistry<
|
||||
CustomIntegrationsServices,
|
||||
KibanaPluginServiceParams<CustomIntegrationsStartDependencies>
|
||||
>(pluginServiceProviders);
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { KibanaPluginServiceFactory } from '../../../../presentation_util/public';
|
||||
|
||||
import type { CustomIntegrationsPlatformService } from '../platform';
|
||||
import type { CustomIntegrationsStartDependencies } from '../../types';
|
||||
|
||||
/**
|
||||
* A type definition for a factory to produce the `CustomIntegrationsPlatformService` for use in Kibana.
|
||||
* @see /src/plugins/presentation_util/public/services/create/factory.ts
|
||||
*/
|
||||
export type CustomIntegrationsPlatformServiceFactory = KibanaPluginServiceFactory<
|
||||
CustomIntegrationsPlatformService,
|
||||
CustomIntegrationsStartDependencies
|
||||
>;
|
||||
|
||||
/**
|
||||
* A factory to produce the `CustomIntegrationsPlatformService` for use in Kibana.
|
||||
*/
|
||||
export const platformServiceFactory: CustomIntegrationsPlatformServiceFactory = ({
|
||||
coreStart,
|
||||
}) => ({
|
||||
getBasePath: coreStart.http.basePath.get,
|
||||
getAbsolutePath: (path: string): string => coreStart.http.basePath.prepend(`${path}`),
|
||||
});
|
12
src/plugins/custom_integrations/public/services/platform.ts
Normal file
12
src/plugins/custom_integrations/public/services/platform.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export interface CustomIntegrationsPlatformService {
|
||||
getBasePath: () => string;
|
||||
getAbsolutePath: (path: string) => string;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import {
|
||||
PluginServiceProviders,
|
||||
PluginServiceProvider,
|
||||
PluginServiceRegistry,
|
||||
} from '../../../../presentation_util/public';
|
||||
|
||||
import { CustomIntegrationsServices } from '..';
|
||||
import { findServiceFactory } from '../stub/find';
|
||||
import { platformServiceFactory } from '../stub/platform';
|
||||
|
||||
export { findServiceFactory } from '../stub/find';
|
||||
export { platformServiceFactory } from '../stub/platform';
|
||||
|
||||
/**
|
||||
* A set of `PluginServiceProvider`s for use in Storybook.
|
||||
* @see /src/plugins/presentation_util/public/services/create/provider.tsx
|
||||
*/
|
||||
export const providers: PluginServiceProviders<CustomIntegrationsServices> = {
|
||||
find: new PluginServiceProvider(findServiceFactory),
|
||||
platform: new PluginServiceProvider(platformServiceFactory),
|
||||
};
|
||||
|
||||
/**
|
||||
* A `PluginServiceRegistry` for use in Storybook.
|
||||
* @see /src/plugins/presentation_util/public/services/create/registry.tsx
|
||||
*/
|
||||
export const registry = new PluginServiceRegistry<CustomIntegrationsServices>(providers);
|
32
src/plugins/custom_integrations/public/services/stub/find.ts
Normal file
32
src/plugins/custom_integrations/public/services/stub/find.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { PluginServiceFactory } from '../../../../presentation_util/public';
|
||||
|
||||
import { CustomIntegrationsFindService, filterCustomIntegrations } from '../find';
|
||||
|
||||
/**
|
||||
* A type definition for a factory to produce the `CustomIntegrationsFindService` with stubbed output.
|
||||
* @see /src/plugins/presentation_util/public/services/create/factory.ts
|
||||
*/
|
||||
export type CustomIntegrationsFindServiceFactory =
|
||||
PluginServiceFactory<CustomIntegrationsFindService>;
|
||||
|
||||
/**
|
||||
* A factory to produce the `CustomIntegrationsFindService` with stubbed output.
|
||||
*/
|
||||
export const findServiceFactory: CustomIntegrationsFindServiceFactory = () => ({
|
||||
findAppendedIntegrations: async (params) => {
|
||||
const { integrations } = await import('./fixtures/integrations');
|
||||
return filterCustomIntegrations(integrations, params);
|
||||
},
|
||||
findReplacementIntegrations: async (params) => {
|
||||
const { integrations } = await import('./fixtures/integrations');
|
||||
return filterCustomIntegrations(integrations, params);
|
||||
},
|
||||
});
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import {
|
||||
PluginServiceProviders,
|
||||
PluginServiceProvider,
|
||||
PluginServiceRegistry,
|
||||
} from '../../../../presentation_util/public';
|
||||
|
||||
import { CustomIntegrationsServices } from '..';
|
||||
import { findServiceFactory } from './find';
|
||||
import { platformServiceFactory } from './platform';
|
||||
|
||||
export { findServiceFactory } from './find';
|
||||
export { platformServiceFactory } from './platform';
|
||||
|
||||
export const providers: PluginServiceProviders<CustomIntegrationsServices> = {
|
||||
find: new PluginServiceProvider(findServiceFactory),
|
||||
platform: new PluginServiceProvider(platformServiceFactory),
|
||||
};
|
||||
|
||||
export const registry = new PluginServiceRegistry<CustomIntegrationsServices>(providers);
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { PluginServiceFactory } from '../../../../presentation_util/public';
|
||||
|
||||
import type { CustomIntegrationsPlatformService } from '../platform';
|
||||
|
||||
/**
|
||||
* A type definition for a factory to produce the `CustomIntegrationsPlatformService` with stubbed output.
|
||||
* @see /src/plugins/presentation_util/public/services/create/factory.ts
|
||||
*/
|
||||
export type CustomIntegrationsPlatformServiceFactory =
|
||||
PluginServiceFactory<CustomIntegrationsPlatformService>;
|
||||
|
||||
/**
|
||||
* A factory to produce the `CustomIntegrationsPlatformService` with stubbed output.
|
||||
*/
|
||||
export const platformServiceFactory: CustomIntegrationsPlatformServiceFactory = () => ({
|
||||
getBasePath: () => '/basePath',
|
||||
getAbsolutePath: (path: string): string => `/basePath${path}`,
|
||||
});
|
|
@ -6,14 +6,19 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { PresentationUtilPluginStart } from '../../presentation_util/public';
|
||||
|
||||
import { CustomIntegration } from '../common';
|
||||
|
||||
export interface CustomIntegrationsSetup {
|
||||
getAppendCustomIntegrations: () => Promise<CustomIntegration[]>;
|
||||
getReplacementCustomIntegrations: () => Promise<CustomIntegration[]>;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface CustomIntegrationsStart {}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface AppPluginStartDependencies {}
|
||||
export interface CustomIntegrationsStart {
|
||||
ContextProvider: React.FC;
|
||||
}
|
||||
|
||||
export interface CustomIntegrationsStartDependencies {
|
||||
presentationUtil: PresentationUtilPluginStart;
|
||||
}
|
||||
|
|
48
src/plugins/custom_integrations/storybook/decorator.tsx
Normal file
48
src/plugins/custom_integrations/storybook/decorator.tsx
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { DecoratorFn } from '@storybook/react';
|
||||
import { I18nProvider } from '@kbn/i18n/react';
|
||||
|
||||
import { PluginServiceRegistry } from '../../presentation_util/public';
|
||||
|
||||
import { pluginServices } from '../public/services';
|
||||
import { CustomIntegrationsServices } from '../public/services';
|
||||
import { providers } from '../public/services/storybook';
|
||||
import { EuiThemeProvider } from '../../kibana_react/common/eui_styled_components';
|
||||
|
||||
/**
|
||||
* Returns a Storybook Decorator that provides both the `I18nProvider` and access to `PluginServices`
|
||||
* for components rendered in Storybook.
|
||||
*/
|
||||
export const getCustomIntegrationsContextDecorator =
|
||||
(): DecoratorFn =>
|
||||
(story, { globals }) => {
|
||||
const ContextProvider = getCustomIntegrationsContextProvider();
|
||||
const darkMode = globals.euiTheme === 'v8.dark' || globals.euiTheme === 'v7.dark';
|
||||
|
||||
return (
|
||||
<I18nProvider>
|
||||
<EuiThemeProvider darkMode={darkMode}>
|
||||
<ContextProvider>{story()}</ContextProvider>
|
||||
</EuiThemeProvider>
|
||||
</I18nProvider>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Prepares `PluginServices` for use in Storybook and returns a React `Context.Provider` element
|
||||
* so components that access `PluginServices` can be rendered.
|
||||
*/
|
||||
export const getCustomIntegrationsContextProvider = () => {
|
||||
const registry = new PluginServiceRegistry<CustomIntegrationsServices>(providers);
|
||||
pluginServices.setRegistry(registry.start({}));
|
||||
return pluginServices.getContextProvider();
|
||||
};
|
12
src/plugins/custom_integrations/storybook/index.ts
Normal file
12
src/plugins/custom_integrations/storybook/index.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export {
|
||||
getCustomIntegrationsContextDecorator as getStorybookContextDecorator,
|
||||
getCustomIntegrationsContextProvider as getStorybookContextProvider,
|
||||
} from '../storybook/decorator';
|
11
src/plugins/custom_integrations/storybook/main.ts
Normal file
11
src/plugins/custom_integrations/storybook/main.ts
Normal file
|
@ -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
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { defaultConfig } from '@kbn/storybook';
|
||||
|
||||
module.exports = defaultConfig;
|
21
src/plugins/custom_integrations/storybook/manager.ts
Normal file
21
src/plugins/custom_integrations/storybook/manager.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { addons } from '@storybook/addons';
|
||||
import { create } from '@storybook/theming';
|
||||
import { PANEL_ID } from '@storybook/addon-actions';
|
||||
|
||||
addons.setConfig({
|
||||
theme: create({
|
||||
base: 'light',
|
||||
brandTitle: 'Kibana Custom Integrations Storybook',
|
||||
brandUrl: 'https://github.com/elastic/kibana/tree/master/src/plugins/custom_integrations',
|
||||
}),
|
||||
showPanel: true.valueOf,
|
||||
selectedPanel: PANEL_ID,
|
||||
});
|
28
src/plugins/custom_integrations/storybook/preview.tsx
Normal file
28
src/plugins/custom_integrations/storybook/preview.tsx
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Title, Subtitle, Description, Primary, Stories } from '@storybook/addon-docs/blocks';
|
||||
|
||||
import { getCustomIntegrationsContextDecorator } from './decorator';
|
||||
|
||||
export const decorators = [getCustomIntegrationsContextDecorator()];
|
||||
|
||||
export const parameters = {
|
||||
docs: {
|
||||
page: () => (
|
||||
<>
|
||||
<Title />
|
||||
<Subtitle />
|
||||
<Description />
|
||||
<Primary />
|
||||
<Stories />
|
||||
</>
|
||||
),
|
||||
},
|
||||
};
|
|
@ -6,8 +6,15 @@
|
|||
"declaration": true,
|
||||
"declarationMap": true
|
||||
},
|
||||
"include": ["common/**/*", "public/**/*", "server/**/*"],
|
||||
"include": [
|
||||
"../../../typings/**/*",
|
||||
"common/**/*",
|
||||
"public/**/*",
|
||||
"server/**/*",
|
||||
"storybook/**/*"
|
||||
],
|
||||
"references": [
|
||||
{ "path": "../../core/tsconfig.json" }
|
||||
{ "path": "../../core/tsconfig.json" },
|
||||
{ "path": "../presentation_util/tsconfig.json" }
|
||||
]
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ yarn storybook --site apm
|
|||
yarn storybook --site canvas
|
||||
yarn storybook --site codeeditor
|
||||
yarn storybook --site ci_composite
|
||||
yarn storybook --site custom_integrations
|
||||
yarn storybook --site url_template_editor
|
||||
yarn storybook --site dashboard
|
||||
yarn storybook --site dashboard_enhanced
|
||||
|
|
|
@ -201,13 +201,15 @@ export const IntegrationsAppContext: React.FC<{
|
|||
<EuiThemeProvider darkMode={isDarkMode}>
|
||||
<UIExtensionsContext.Provider value={extensions}>
|
||||
<FleetStatusProvider>
|
||||
<Router history={history}>
|
||||
<AgentPolicyContextProvider>
|
||||
<PackageInstallProvider notifications={startServices.notifications}>
|
||||
{children}
|
||||
</PackageInstallProvider>
|
||||
</AgentPolicyContextProvider>
|
||||
</Router>
|
||||
<startServices.customIntegrations.ContextProvider>
|
||||
<Router history={history}>
|
||||
<AgentPolicyContextProvider>
|
||||
<PackageInstallProvider notifications={startServices.notifications}>
|
||||
{children}
|
||||
</PackageInstallProvider>
|
||||
</AgentPolicyContextProvider>
|
||||
</Router>
|
||||
</startServices.customIntegrations.ContextProvider>
|
||||
</FleetStatusProvider>
|
||||
</UIExtensionsContext.Provider>
|
||||
</EuiThemeProvider>
|
||||
|
|
|
@ -18,6 +18,10 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import type { EuiDescriptionListProps } from '@elastic/eui/src/components/description_list/description_list';
|
||||
|
||||
import styled, { useTheme } from 'styled-components';
|
||||
|
||||
import type { EuiTheme } from '../../../../../../../../../../../src/plugins/kibana_react/common';
|
||||
|
||||
import type {
|
||||
PackageInfo,
|
||||
PackageSpecCategory,
|
||||
|
@ -28,13 +32,21 @@ import { entries } from '../../../../../types';
|
|||
import { useGetCategories } from '../../../../../hooks';
|
||||
import { AssetTitleMap, DisplayedAssets, ServiceTitleMap } from '../../../constants';
|
||||
|
||||
import {
|
||||
withSuspense,
|
||||
LazyReplacementCard,
|
||||
} from '../../../../../../../../../../../src/plugins/custom_integrations/public';
|
||||
|
||||
import { NoticeModal } from './notice_modal';
|
||||
|
||||
const ReplacementCard = withSuspense(LazyReplacementCard);
|
||||
|
||||
interface Props {
|
||||
packageInfo: PackageInfo;
|
||||
}
|
||||
|
||||
export const Details: React.FC<Props> = memo(({ packageInfo }) => {
|
||||
const theme = useTheme() as EuiTheme;
|
||||
const { data: categoriesData, isLoading: isLoadingCategories } = useGetCategories();
|
||||
const packageCategories: string[] = useMemo(() => {
|
||||
if (!isLoadingCategories && categoriesData && categoriesData.response) {
|
||||
|
@ -163,6 +175,23 @@ export const Details: React.FC<Props> = memo(({ packageInfo }) => {
|
|||
toggleNoticeModal,
|
||||
]);
|
||||
|
||||
const Replacements = styled(EuiFlexItem)`
|
||||
margin: 0;
|
||||
|
||||
& .euiAccordion {
|
||||
padding-top: ${parseInt(theme.eui.euiSizeL, 10) * 2}px;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
display: block;
|
||||
border-top: 1px solid ${theme.eui.euiColorLightShade};
|
||||
position: relative;
|
||||
top: -${theme.eui.euiSizeL};
|
||||
margin: 0 ${theme.eui.euiSizeXS};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
return (
|
||||
<>
|
||||
<EuiPortal>
|
||||
|
@ -181,6 +210,9 @@ export const Details: React.FC<Props> = memo(({ packageInfo }) => {
|
|||
<EuiFlexItem>
|
||||
<EuiDescriptionList type="column" compressed listItems={listItems} />
|
||||
</EuiFlexItem>
|
||||
<Replacements>
|
||||
<ReplacementCard eprPackageName={packageInfo.name} />
|
||||
</Replacements>
|
||||
</EuiFlexGroup>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -10,6 +10,7 @@ import type {
|
|||
CustomIntegration,
|
||||
IntegrationCategory,
|
||||
} from '../../../../../src/plugins/custom_integrations/common';
|
||||
import { filterCustomIntegrations } from '../../../../../src/plugins/custom_integrations/public';
|
||||
|
||||
// Export this as a utility to find replacements for a package (e.g. in the overview-page for an EPR package)
|
||||
function findReplacementsForEprPackage(
|
||||
|
@ -20,9 +21,7 @@ function findReplacementsForEprPackage(
|
|||
if (release === 'ga') {
|
||||
return [];
|
||||
}
|
||||
return replacements.filter((customIntegration: CustomIntegration) => {
|
||||
return customIntegration.eprOverlap === packageName;
|
||||
});
|
||||
return filterCustomIntegrations(replacements, { eprPackageName: packageName });
|
||||
}
|
||||
|
||||
export function useMergeEprPackagesWithReplacements(
|
||||
|
|
|
@ -26,5 +26,6 @@ export const createStartDepsMock = (): MockedFleetStartDeps => {
|
|||
return {
|
||||
data: dataPluginMock.createStartContract(),
|
||||
navigation: navigationPluginMock.createStartContract(),
|
||||
customIntegrations: customIntegrationsMock.createStart(),
|
||||
};
|
||||
};
|
||||
|
|
|
@ -16,8 +16,12 @@ import { i18n } from '@kbn/i18n';
|
|||
|
||||
import type { NavigationPublicPluginStart } from 'src/plugins/navigation/public';
|
||||
|
||||
import type {
|
||||
CustomIntegrationsStart,
|
||||
CustomIntegrationsSetup,
|
||||
} from 'src/plugins/custom_integrations/public';
|
||||
|
||||
import { DEFAULT_APP_CATEGORIES, AppNavLinkStatus } from '../../../../src/core/public';
|
||||
import type { CustomIntegrationsSetup } from '../../../../src/plugins/custom_integrations/public';
|
||||
|
||||
import type {
|
||||
DataPublicPluginSetup,
|
||||
|
@ -76,6 +80,7 @@ export interface FleetSetupDeps {
|
|||
export interface FleetStartDeps {
|
||||
data: DataPublicPluginStart;
|
||||
navigation: NavigationPublicPluginStart;
|
||||
customIntegrations: CustomIntegrationsStart;
|
||||
}
|
||||
|
||||
export interface FleetStartServices extends CoreStart, FleetStartDeps {
|
||||
|
|
|
@ -13,12 +13,12 @@ import { createBrowserHistory } from 'history';
|
|||
import { I18nProvider } from '@kbn/i18n/react';
|
||||
|
||||
import { ScopedHistory } from '../../../../../src/core/public';
|
||||
import { getStorybookContextProvider } from '../../../../../src/plugins/custom_integrations/storybook';
|
||||
import { IntegrationsAppContext } from '../../public/applications/integrations/app';
|
||||
import type { FleetConfigType, FleetStartServices } from '../../public/plugin';
|
||||
|
||||
// TODO: This is a contract leak, and should be on the context, rather than a setter.
|
||||
// TODO: These are contract leaks, and should be on the context, rather than a setter.
|
||||
import { setHttpClient } from '../../public/hooks/use_request';
|
||||
|
||||
import { setCustomIntegrations } from '../../public/services/custom_integrations';
|
||||
|
||||
import { getApplication } from './application';
|
||||
|
@ -36,7 +36,6 @@ import { stubbedStartServices } from './stubs';
|
|||
// Expect this to grow as components that are given Stories need access to mocked services.
|
||||
export const StorybookContext: React.FC<{ storyContext?: StoryContext }> = ({
|
||||
children: storyChildren,
|
||||
storyContext,
|
||||
}) => {
|
||||
const basepath = '';
|
||||
const browserHistory = createBrowserHistory();
|
||||
|
@ -56,6 +55,9 @@ export const StorybookContext: React.FC<{ storyContext?: StoryContext }> = ({
|
|||
injectedMetadata: {
|
||||
getInjectedVar: () => null,
|
||||
},
|
||||
customIntegrations: {
|
||||
ContextProvider: getStorybookContextProvider(),
|
||||
},
|
||||
...stubbedStartServices,
|
||||
};
|
||||
|
||||
|
|
|
@ -10,6 +10,6 @@ import type { DecoratorFn } from '@storybook/react';
|
|||
|
||||
import { StorybookContext } from './context';
|
||||
|
||||
export const decorator: DecoratorFn = (story: Function) => {
|
||||
export const decorator: DecoratorFn = (story, storybook) => {
|
||||
return <StorybookContext>{story()}</StorybookContext>;
|
||||
};
|
||||
|
|
|
@ -1653,12 +1653,6 @@
|
|||
"data.functions.esaggs.help": "AggConfig 集約を実行します",
|
||||
"data.functions.esaggs.inspector.dataRequest.description": "このリクエストはElasticsearchにクエリし、ビジュアライゼーション用のデータを取得します。",
|
||||
"data.functions.esaggs.inspector.dataRequest.title": "データ",
|
||||
"dataViews.indexPatternLoad.help": "インデックスパターンを読み込みます",
|
||||
"dataViews.functions.indexPatternLoad.id.help": "読み込むインデックスパターンID",
|
||||
"dataViews.ensureDefaultIndexPattern.bannerLabel": "Kibanaでデータの可視化と閲覧を行うには、Elasticsearchからデータを取得するためのインデックスパターンの作成が必要です。",
|
||||
"dataViews.fetchFieldErrorTitle": "インデックスパターンのフィールド取得中にエラーが発生 {title}(ID:{id})",
|
||||
"dataViews.indexPatternLoad.error.kibanaRequest": "サーバーでこの検索を実行するには、KibanaRequest が必要です。式実行パラメーターに要求オブジェクトを渡してください。",
|
||||
"dataViews.unableWriteLabel": "インデックスパターンを書き込めません。このインデックスパターンへの最新の変更を取得するには、ページを更新してください。",
|
||||
"data.inspector.table..dataDescriptionTooltip": "ビジュアライゼーションの元のデータを表示",
|
||||
"data.inspector.table.dataTitle": "データ",
|
||||
"data.inspector.table.downloadCSVToggleButtonLabel": "CSV をダウンロード",
|
||||
|
@ -2297,6 +2291,12 @@
|
|||
"data.searchSessions.sessionService.sessionObjectFetchError": "検索セッション情報を取得できませんでした",
|
||||
"data.triggers.applyFilterDescription": "Kibanaフィルターが適用されるとき。単一の値または範囲フィルターにすることができます。",
|
||||
"data.triggers.applyFilterTitle": "フィルターを適用",
|
||||
"dataViews.indexPatternLoad.help": "インデックスパターンを読み込みます",
|
||||
"dataViews.functions.indexPatternLoad.id.help": "読み込むインデックスパターンID",
|
||||
"dataViews.ensureDefaultIndexPattern.bannerLabel": "Kibanaでデータの可視化と閲覧を行うには、Elasticsearchからデータを取得するためのインデックスパターンの作成が必要です。",
|
||||
"dataViews.fetchFieldErrorTitle": "インデックスパターンのフィールド取得中にエラーが発生 {title}(ID:{id})",
|
||||
"dataViews.indexPatternLoad.error.kibanaRequest": "サーバーでこの検索を実行するには、KibanaRequest が必要です。式実行パラメーターに要求オブジェクトを渡してください。",
|
||||
"dataViews.unableWriteLabel": "インデックスパターンを書き込めません。このインデックスパターンへの最新の変更を取得するには、ページを更新してください。",
|
||||
"devTools.badge.readOnly.text": "読み取り専用",
|
||||
"devTools.badge.readOnly.tooltip": "を保存できませんでした",
|
||||
"devTools.devToolsTitle": "開発ツール",
|
||||
|
|
|
@ -1669,12 +1669,6 @@
|
|||
"data.functions.esaggs.help": "运行 AggConfig 聚合",
|
||||
"data.functions.esaggs.inspector.dataRequest.description": "此请求查询 Elasticsearch,以获取可视化的数据。",
|
||||
"data.functions.esaggs.inspector.dataRequest.title": "数据",
|
||||
"dataViews.indexPatternLoad.help": "加载索引模式",
|
||||
"dataViews.functions.indexPatternLoad.id.help": "要加载的索引模式 id",
|
||||
"dataViews.ensureDefaultIndexPattern.bannerLabel": "要在 Kibana 中可视化和浏览数据,必须创建索引模式,以从 Elasticsearch 中检索数据。",
|
||||
"dataViews.fetchFieldErrorTitle": "提取索引模式 {title} (ID: {id}) 的字段时出错",
|
||||
"dataViews.indexPatternLoad.error.kibanaRequest": "在服务器上执行此搜索时需要 Kibana 请求。请向表达式执行模式参数提供请求对象。",
|
||||
"dataViews.unableWriteLabel": "无法写入索引模式!请刷新页面以获取此索引模式的最新更改。",
|
||||
"data.inspector.table..dataDescriptionTooltip": "查看可视化后面的数据",
|
||||
"data.inspector.table.dataTitle": "数据",
|
||||
"data.inspector.table.downloadCSVToggleButtonLabel": "下载 CSV",
|
||||
|
@ -2319,6 +2313,12 @@
|
|||
"data.searchSessions.sessionService.sessionObjectFetchError": "无法提取搜索会话信息",
|
||||
"data.triggers.applyFilterDescription": "应用 kibana 筛选时。可能是单个值或范围筛选。",
|
||||
"data.triggers.applyFilterTitle": "应用筛选",
|
||||
"dataViews.indexPatternLoad.help": "加载索引模式",
|
||||
"dataViews.functions.indexPatternLoad.id.help": "要加载的索引模式 id",
|
||||
"dataViews.ensureDefaultIndexPattern.bannerLabel": "要在 Kibana 中可视化和浏览数据,必须创建索引模式,以从 Elasticsearch 中检索数据。",
|
||||
"dataViews.fetchFieldErrorTitle": "提取索引模式 {title} (ID: {id}) 的字段时出错",
|
||||
"dataViews.indexPatternLoad.error.kibanaRequest": "在服务器上执行此搜索时需要 Kibana 请求。请向表达式执行模式参数提供请求对象。",
|
||||
"dataViews.unableWriteLabel": "无法写入索引模式!请刷新页面以获取此索引模式的最新更改。",
|
||||
"devTools.badge.readOnly.text": "只读",
|
||||
"devTools.badge.readOnly.tooltip": "无法保存",
|
||||
"devTools.devToolsTitle": "开发工具",
|
||||
|
|
Loading…
Reference in a new issue