Skip to content

Commit

Permalink
[Fleet] Human readable documentation for integration inputs & streams (
Browse files Browse the repository at this point in the history
  • Loading branch information
nchaulet authored Sep 19, 2022
1 parent c522506 commit fc4a64b
Show file tree
Hide file tree
Showing 4 changed files with 303 additions and 1 deletion.
8 changes: 7 additions & 1 deletion x-pack/plugins/fleet/common/types/models/epm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,13 @@ export type InstallSource = 'registry' | 'upload' | 'bundled';

export type EpmPackageInstallStatus = 'installed' | 'installing' | 'install_failed';

export type DetailViewPanelName = 'overview' | 'policies' | 'assets' | 'settings' | 'custom';
export type DetailViewPanelName =
| 'overview'
| 'policies'
| 'assets'
| 'settings'
| 'custom'
| 'api-reference';
export type ServiceName = 'kibana' | 'elasticsearch';
export type AgentAssetType = typeof agentAssetTypes;
export type DocAssetType = 'doc' | 'notice';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React, { useMemo } from 'react';
import {
EuiAccordion,
EuiBasicTable,
EuiCode,
EuiFlexGroup,
EuiFlexItem,
EuiTitle,
EuiSpacer,
EuiText,
EuiLink,
EuiBetaBadge,
} from '@elastic/eui';
import type { EuiInMemoryTableProps } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';

import type {
PackageInfo,
RegistryVarsEntry,
RegistryStream,
RegistryInput,
} from '../../../../../types';
import { useStartServices } from '../../../../../../../hooks';
import { getStreamsForInputType } from '../../../../../../../../common/services';

interface Props {
packageInfo: PackageInfo;
integration?: string | null;
}

export const DocumentationPage: React.FunctionComponent<Props> = ({ packageInfo, integration }) => {
const { docLinks } = useStartServices();

const content = (
<>
<EuiFlexGroup gutterSize="m" justifyContent="spaceBetween">
<EuiFlexItem grow={6}>
<EuiText>
<FormattedMessage
id="xpack.fleet.epm.packageDetails.apiReference.description"
defaultMessage="This documents all the inputs, streams, and variables available to use this integration programmatically via the Fleet Kibana API. {learnMore}"
values={{
learnMore: (
<EuiLink href={docLinks.links.fleet.guide}>
<FormattedMessage
id="xpack.fleet.epm.packageDetails.apiReference.learnMoreLink"
defaultMessage="Learn more"
/>
</EuiLink>
),
}}
/>
</EuiText>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiBetaBadge label="beta" />
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="m" />
<PackageVars vars={packageInfo.vars} />

<Inputs packageInfo={packageInfo} integration={integration} />
<EuiSpacer size="m" />
</>
);

return (
<EuiFlexGroup alignItems="flexStart">
<EuiFlexItem grow={1} />
<EuiFlexItem grow={6}>{content}</EuiFlexItem>
</EuiFlexGroup>
);
};

type RegistryInputWithStreams = RegistryInput & {
key: string;
streams: Array<RegistryStream & { data_stream: { type: string; dataset: string } }>;
};

const Inputs: React.FunctionComponent<{
packageInfo: PackageInfo;
integration?: string | null;
}> = ({ packageInfo, integration }) => {
const inputs = useMemo(
() =>
packageInfo.policy_templates?.reduce((acc, policyTemplate) => {
if (integration && policyTemplate.name !== integration) {
return acc;
}
if ('inputs' in policyTemplate && policyTemplate.inputs) {
return [
...acc,
...policyTemplate.inputs.map((input) => ({
key: `${policyTemplate.name}-${input.type}`,
...input,
streams: getStreamsForInputType(input.type, packageInfo, []),
})),
];
}
return acc;
}, [] as RegistryInputWithStreams[]),
[packageInfo, integration]
);
return (
<>
<EuiSpacer size="m" />
<EuiTitle size="xs">
<h4>
<FormattedMessage
id="xpack.fleet.epm.packageDetails.apiReference.inputsTitle"
defaultMessage="Inputs"
/>
</h4>
</EuiTitle>
<EuiSpacer size="s" />
{inputs?.map((input) => {
return (
<EuiAccordion
key={input.key}
id={input.key}
buttonContent={
<EuiText>
<EuiCode>{input.key}</EuiCode>({input.title})
</EuiText>
}
initialIsOpen={false}
paddingSize={'m'}
>
<EuiText>{input.description}</EuiText>
{input.vars ? (
<>
<EuiSpacer size="m" />
<VarsTable vars={input.vars} />
</>
) : null}
<EuiSpacer size="m" />
<EuiTitle size="xs">
<h6>
<FormattedMessage
id="xpack.fleet.epm.packageDetails.apiReference.streamsTitle"
defaultMessage="Streams"
/>
</h6>
</EuiTitle>
<EuiSpacer size="m" />
{input.streams.map((dataStream) => (
<EuiAccordion
key={dataStream.data_stream.type + dataStream.data_stream.dataset}
id={dataStream.data_stream.type + dataStream.data_stream.dataset}
buttonContent={
<EuiText>
<EuiCode>{dataStream.data_stream.dataset}</EuiCode>({dataStream.title})
</EuiText>
}
initialIsOpen={false}
paddingSize={'m'}
>
<EuiText>{dataStream.description}</EuiText>
{dataStream.vars ? (
<>
<EuiSpacer size="m" />
<VarsTable vars={dataStream.vars} />
</>
) : null}
</EuiAccordion>
))}
</EuiAccordion>
);
}) ?? null}
</>
);
};

const PackageVars: React.FunctionComponent<{ vars: PackageInfo['vars'] }> = ({ vars }) => {
if (!vars) {
return null;
}

return (
<>
<EuiTitle size="xs">
<h4>
<FormattedMessage
id="xpack.fleet.epm.packageDetails.apiReference.globalVariablesTitle"
defaultMessage="Package variables"
/>
</h4>
</EuiTitle>
<EuiSpacer size="m" />
<VarsTable vars={vars} />
<EuiSpacer size="m" />
</>
);
};

const VarsTable: React.FunctionComponent<{ vars: RegistryVarsEntry[] }> = ({ vars }) => {
const columns = useMemo((): EuiInMemoryTableProps<RegistryVarsEntry>['columns'] => {
return [
{
field: 'name',
name: (
<FormattedMessage
id="xpack.fleet.epm.packageDetails.apiReference.columnKeyName"
defaultMessage="Key"
/>
),
render: (name: string) => <EuiCode>{name}</EuiCode>,
},
{
field: 'title',
name: (
<FormattedMessage
id="xpack.fleet.epm.packageDetails.apiReference.columnTitleName"
defaultMessage="Title"
/>
),
},
{
field: 'type',
name: (
<FormattedMessage
id="xpack.fleet.epm.packageDetails.apiReference.columnTypeName"
defaultMessage="Type"
/>
),
},
{
field: 'required',
width: '70px',
name: (
<FormattedMessage
id="xpack.fleet.epm.packageDetails.apiReference.columnRequiredName"
defaultMessage="Required"
/>
),
},
{
field: 'multi',
width: '70px',
name: (
<FormattedMessage
id="xpack.fleet.epm.packageDetails.apiReference.columnMultidName"
defaultMessage="Multi"
/>
),
},
];
}, []);

return (
<>
<EuiTitle size="xxs">
<h6>
<FormattedMessage
id="xpack.fleet.epm.packageDetails.apiReference.variableTableTitle"
defaultMessage="Variables"
/>
</h6>
</EuiTitle>
<EuiBasicTable columns={columns} items={vars} />
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ import { OverviewPage } from './overview';
import { PackagePoliciesPage } from './policies';
import { SettingsPage } from './settings';
import { CustomViewPage } from './custom';
import { DocumentationPage } from './documentation';

import './index.scss';

Expand Down Expand Up @@ -489,6 +490,22 @@ export function Detail() {
});
}

tabs.push({
id: 'api-reference',
name: (
<FormattedMessage
id="xpack.fleet.epm.packageDetailsNav.documentationLinkText"
defaultMessage="API reference"
/>
),
isSelected: panel === 'api-reference',
'data-test-subj': `tab-api-reference`,
href: getHref('integration_details_api_reference', {
pkgkey: packageInfoKey,
...(integration ? { integration } : {}),
}),
});

return tabs;
}, [
packageInfo,
Expand Down Expand Up @@ -575,6 +592,9 @@ export function Detail() {
<Route path={INTEGRATIONS_ROUTING_PATHS.integration_details_custom}>
<CustomViewPage packageInfo={packageInfo} />
</Route>
<Route path={INTEGRATIONS_ROUTING_PATHS.integration_details_api_reference}>
<DocumentationPage packageInfo={packageInfo} integration={integrationInfo?.name} />
</Route>
<Redirect to={INTEGRATIONS_ROUTING_PATHS.integration_details_overview} />
</Switch>
)}
Expand Down
6 changes: 6 additions & 0 deletions x-pack/plugins/fleet/public/constants/page_paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export type DynamicPage =
| 'integration_details_assets'
| 'integration_details_settings'
| 'integration_details_custom'
| 'integration_details_api_reference'
| 'integration_policy_edit'
| 'integration_policy_upgrade'
| 'policy_details'
Expand Down Expand Up @@ -90,6 +91,7 @@ export const INTEGRATIONS_ROUTING_PATHS = {
integration_details_assets: '/detail/:pkgkey/assets',
integration_details_settings: '/detail/:pkgkey/settings',
integration_details_custom: '/detail/:pkgkey/custom',
integration_details_api_reference: '/detail/:pkgkey/api-reference',
integration_policy_edit: '/edit-integration/:packagePolicyId',
integration_policy_upgrade: '/edit-integration/:packagePolicyId',
};
Expand Down Expand Up @@ -143,6 +145,10 @@ export const pagePathGetters: {
INTEGRATIONS_BASE_PATH,
`/detail/${pkgkey}/custom${integration ? `?integration=${integration}` : ''}`,
],
integration_details_api_reference: ({ pkgkey, integration }) => [
INTEGRATIONS_BASE_PATH,
`/detail/${pkgkey}/api-reference${integration ? `?integration=${integration}` : ''}`,
],
integration_policy_edit: ({ packagePolicyId }) => [
INTEGRATIONS_BASE_PATH,
`/edit-integration/${packagePolicyId}`,
Expand Down

0 comments on commit fc4a64b

Please sign in to comment.