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

[Infra UI] Implement telemetry for the asset details flyout #163078

Merged
merged 9 commits into from
Aug 10, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type { DataViewField, DataView } from '@kbn/data-views-plugin/common';
import { UseAssetDetailsStateProps } from '../../../hooks/use_asset_details_state';

export const assetDetailsState: UseAssetDetailsStateProps['state'] = {
node: {
asset: {
name: 'host1',
id: 'host1-macOS',
ip: '192.168.0.1',
Expand All @@ -29,7 +29,7 @@ export const assetDetailsState: UseAssetDetailsStateProps['state'] = {
showActionsColumn: true,
},
},
nodeType: 'host',
assetType: 'host',
dateRange: {
from: '2023-04-09T11:07:49Z',
to: '2023-04-09T11:23:49Z',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,42 +22,36 @@ const tabs: Tab[] = [
name: i18n.translate('xpack.infra.nodeDetails.tabs.overview.title', {
defaultMessage: 'Overview',
}),
'data-test-subj': 'hostsView-flyout-tabs-overview',
},
{
id: FlyoutTabIds.LOGS,
name: i18n.translate('xpack.infra.nodeDetails.tabs.logs', {
defaultMessage: 'Logs',
}),
'data-test-subj': 'hostsView-flyout-tabs-logs',
},
{
id: FlyoutTabIds.METADATA,
name: i18n.translate('xpack.infra.metrics.nodeDetails.tabs.metadata', {
defaultMessage: 'Metadata',
}),
'data-test-subj': 'hostsView-flyout-tabs-metadata',
},
{
id: FlyoutTabIds.PROCESSES,
name: i18n.translate('xpack.infra.metrics.nodeDetails.tabs.processes', {
defaultMessage: 'Processes',
}),
'data-test-subj': 'hostsView-flyout-tabs-processes',
},
{
id: FlyoutTabIds.ANOMALIES,
name: i18n.translate('xpack.infra.nodeDetails.tabs.anomalies', {
defaultMessage: 'Anomalies',
}),
'data-test-subj': 'hostsView-flyout-tabs-anomalies',
},
{
id: FlyoutTabIds.LINK_TO_APM,
name: i18n.translate('xpack.infra.infra.nodeDetails.apmTabLabel', {
defaultMessage: 'APM',
}),
'data-test-subj': 'hostsView-flyout-apm-link',
},
];

Expand Down Expand Up @@ -96,7 +90,7 @@ const FlyoutTemplate: Story<AssetDetailsProps> = (args) => {
Open flyout
</EuiButton>
<div hidden={!isOpen}>
{isOpen && <AssetDetails {...args} renderMode={{ showInFlyout: true, closeFlyout }} />}
{isOpen && <AssetDetails {...args} renderMode={{ mode: 'flyout', closeFlyout }} />}
</div>
</div>
);
Expand All @@ -107,7 +101,7 @@ export const Page = PageTemplate.bind({});
export const Flyout = FlyoutTemplate.bind({});
Flyout.args = {
renderMode: {
showInFlyout: true,
mode: 'flyout',
Copy link
Member

Choose a reason for hiding this comment

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

I realized that this will conflict with my changes in my PR where I use showInFlyout as a boolean. I can adapt that once this PR is merged. It is all good, I am just curious now if it is somehow used in the telemetry object or not yet (I don't see the mode when I check it just want to be sure that I am not missing something)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

renderMode will only be used to determine the componentName attribute. I changed it because this way seems more explanatory to differentiate between render mode: page vs flyout. Not sure if you agree.

Copy link
Member

Choose a reason for hiding this comment

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

Ok, got it! Yeah, it makes sense, we can also extend with other modes that way! I used the boolean to have the "default" view and "flyout" view so the consumer should add a prop only in case a flyout is needed, but your change is good, thanks for explaining 👍

closeFlyout: () => {},
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,17 @@

import React from 'react';
import { EuiFlyout, EuiFlyoutHeader, EuiFlyoutBody } from '@elastic/eui';
import useEffectOnce from 'react-use/lib/useEffectOnce';
import type { AssetDetailsProps, RenderMode } from './types';
import { Content } from './content/content';
import { Header } from './header/header';
import { TabSwitcherProvider } from './hooks/use_tab_switcher';
import { AssetDetailsStateProvider } from './hooks/use_asset_details_state';
import { TabSwitcherProvider, useTabSwitcherContext } from './hooks/use_tab_switcher';
import {
AssetDetailsStateProvider,
useAssetDetailsStateContext,
} from './hooks/use_asset_details_state';
import { useKibanaContextForPlugin } from '../../hooks/use_kibana';
import { ASSET_DETAILS_FLYOUT_COMPONENT_NAME } from './constants';

interface ContentTemplateProps {
header: React.ReactElement;
Expand All @@ -20,8 +26,27 @@ interface ContentTemplateProps {
}

const ContentTemplate = ({ header, body, renderMode }: ContentTemplateProps) => {
return renderMode.showInFlyout ? (
<EuiFlyout onClose={renderMode.closeFlyout} ownFocus={false}>
const { assetType } = useAssetDetailsStateContext();
const { initialActiveTabId } = useTabSwitcherContext();
const {
services: { telemetry },
} = useKibanaContextForPlugin();

useEffectOnce(() => {
telemetry.reportAssetDetailsFlyoutViewed({
componentName: ASSET_DETAILS_FLYOUT_COMPONENT_NAME,
assetType,
tabId: initialActiveTabId,
});
});

return renderMode.mode === 'flyout' ? (
<EuiFlyout
onClose={renderMode.closeFlyout}
ownFocus={false}
data-component-name={ASSET_DETAILS_FLYOUT_COMPONENT_NAME}
data-asset-type={assetType}
>
<EuiFlyoutHeader hasBorder>{header}</EuiFlyoutHeader>
<EuiFlyoutBody>{body}</EuiFlyoutBody>
</EuiFlyout>
Expand All @@ -34,25 +59,27 @@ const ContentTemplate = ({ header, body, renderMode }: ContentTemplateProps) =>
};

export const AssetDetails = ({
node,
asset,
dateRange,
activeTabId,
overrides,
onTabsStateChange,
tabs = [],
links = [],
nodeType = 'host',
assetType = 'host',
renderMode = {
showInFlyout: false,
mode: 'page',
},
}: AssetDetailsProps) => {
return (
<AssetDetailsStateProvider state={{ node, nodeType, overrides, onTabsStateChange, dateRange }}>
<AssetDetailsStateProvider
state={{ asset, assetType, overrides, onTabsStateChange, dateRange }}
>
<TabSwitcherProvider
initialActiveTabId={tabs.length > 0 ? activeTabId ?? tabs[0].id : undefined}
>
<ContentTemplate
header={<Header compact={renderMode.showInFlyout} tabs={tabs} links={links} />}
header={<Header compact={renderMode.mode === 'flyout'} tabs={tabs} links={links} />}
body={<Content />}
renderMode={renderMode}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ export class AssetDetailsEmbeddable extends Embeddable<AssetDetailsEmbeddableInp
<LazyAssetDetailsWrapper
activeTabId={this.input.activeTabId}
dateRange={this.input.dateRange}
node={this.input.node}
nodeType={this.input.nodeType}
asset={this.input.asset}
assetType={this.input.assetType}
overrides={this.input.overrides}
renderMode={this.input.renderMode}
tabs={this.input.tabs}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const AlertsTooltipContent = React.memo(() => {
values={{
documentation: (
<EuiLink
data-test-subj="assetDetailsTooltipDocumentationLink"
data-test-subj="infraAssetDetailsTooltipDocumentationLink"
href={ALERTS_DOC_HREF}
target="_blank"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ export const ExpandableContent = (props: ExpandableContentProps) => {
{shouldShowMore && (
<>
{' ... '}
<EuiLink data-test-subj="infraExpandableContentCountMoreLink" onClick={toggle}>
<EuiLink
data-test-subj="infraAssetDetailsExpandableContentCountMoreLink"
onClick={toggle}
>
<FormattedMessage
id="xpack.infra.nodeDetails.tabs.metadata.seeMore"
defaultMessage="+{count} more"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
* 2.0.
*/

export const ASSET_DETAILS_FLYOUT_COMPONENT_NAME = 'infraAssetDetailsFlyout';
Copy link
Member

Choose a reason for hiding this comment

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

Do we want to have a different name in case it's open as page? Maybe I am missing something but I don't see a different component value or passing renderMode to this event 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. the name will be different. Probably infraAssetDetailsPage

export const METRIC_CHART_HEIGHT = 300;
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
useEuiMinBreakpoint,
} from '@elastic/eui';
import { css } from '@emotion/react';
import { capitalize } from 'lodash';
import { AssetDetailsProps, FlyoutTabIds, LinkOptions, Tab, TabIds } from '../types';
import {
LinkToApmServices,
Expand All @@ -36,7 +37,7 @@ type Props = Pick<AssetDetailsProps, 'links' | 'tabs'> & {
const APM_FIELD = 'host.hostname';

export const Header = ({ tabs = [], links = [], compact }: Props) => {
const { node, nodeType, overrides, dateRange: timeRange } = useAssetDetailsStateContext();
const { asset, assetType, overrides, dateRange: timeRange } = useAssetDetailsStateContext();
const { euiTheme } = useEuiTheme();
const { showTab, activeTabId } = useTabSwitcherContext();

Expand All @@ -46,23 +47,23 @@ export const Header = ({ tabs = [], links = [], compact }: Props) => {

const tabLinkComponents = {
[FlyoutTabIds.LINK_TO_APM]: (tab: Tab) => (
<TabToApmTraces nodeName={node.name} apmField={APM_FIELD} {...tab} />
<TabToApmTraces assetName={asset.name} apmField={APM_FIELD} {...tab} />
),
[FlyoutTabIds.LINK_TO_UPTIME]: (tab: Tab) => (
<TabToUptime nodeName={node.name} nodeType={nodeType} nodeIp={node.ip} {...tab} />
<TabToUptime assetName={asset.name} assetType={assetType} nodeIp={asset.ip} {...tab} />
),
};

const topCornerLinkComponents: Record<LinkOptions, JSX.Element> = {
nodeDetails: (
<LinkToNodeDetails
nodeName={node.name}
nodeType={nodeType}
assetName={asset.name}
assetType={assetType}
currentTimestamp={toTimestampRange(timeRange).to}
/>
),
alertRule: <LinkToAlertsRule onClick={overrides?.alertRule?.onCreateRuleClick} />,
apmServices: <LinkToApmServices nodeName={node.name} apmField={APM_FIELD} />,
apmServices: <LinkToApmServices assetName={asset.name} apmField={APM_FIELD} />,
};

const tabEntries = tabs.map(({ name, ...tab }) => {
Expand All @@ -77,6 +78,7 @@ export const Header = ({ tabs = [], links = [], compact }: Props) => {
return (
<EuiTab
{...tab}
data-test-subj={`infraAssetDetails${capitalize(tab.id)}Tab`}
key={tab.id}
onClick={() => onTabClick(tab.id)}
isSelected={tab.id === activeTabId}
Expand All @@ -102,7 +104,7 @@ export const Header = ({ tabs = [], links = [], compact }: Props) => {
`}
>
<EuiTitle size={compact ? 'xs' : 'm'}>
{compact ? <h4>{node.name}</h4> : <h1>{node.name}</h1>}
{compact ? <h4>{asset.name}</h4> : <h1>{asset.name}</h1>}
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ const DEFAULT_DATE_RANGE = {
export interface UseAssetDetailsStateProps {
state: Pick<
AssetDetailsProps,
'node' | 'nodeType' | 'overrides' | 'dateRange' | 'onTabsStateChange'
'asset' | 'assetType' | 'overrides' | 'dateRange' | 'onTabsStateChange'
>;
}

export function useAssetDetailsState({ state }: UseAssetDetailsStateProps) {
const { node, nodeType, dateRange: rawDateRange, onTabsStateChange, overrides } = state;
const { asset, assetType, dateRange: rawDateRange, onTabsStateChange, overrides } = state;

const dateRange = useMemo(() => {
const { from = DEFAULT_DATE_RANGE.from, to = DEFAULT_DATE_RANGE.to } =
Expand All @@ -36,8 +36,8 @@ export function useAssetDetailsState({ state }: UseAssetDetailsStateProps) {
const dateRangeTs = toTimestampRange(dateRange);

return {
node,
nodeType,
asset,
assetType,
dateRange,
dateRangeTs,
onTabsStateChange,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export function useTabSwitcher({ initialActiveTabId }: TabSwitcherParams) {
};

return {
initialActiveTabId,
activeTabId,
renderedTabsSet,
showTab,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export interface LinkToAlertsRuleProps {
export const LinkToAlertsRule = ({ onClick }: LinkToAlertsRuleProps) => {
return (
<EuiButtonEmpty
data-test-subj="infraNodeContextPopoverCreateInventoryRuleButton"
data-test-subj="infraAssetDetailsCreateAlertsRuleButton"
onClick={onClick}
size="xs"
iconSide="left"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,18 @@ import { ALERTS_PATH } from '../../../common/alerts/constants';
import { useKibanaContextForPlugin } from '../../../hooks/use_kibana';

export interface LinkToAlertsPageProps {
nodeName: string;
queryField: string;
assetName: string;
dateRange: TimeRange;
queryField: string;
}

export const LinkToAlertsPage = ({ nodeName, queryField, dateRange }: LinkToAlertsPageProps) => {
export const LinkToAlertsPage = ({ assetName, queryField, dateRange }: LinkToAlertsPageProps) => {
const { services } = useKibanaContextForPlugin();
const { http } = services;

const linkToAlertsPage = http.basePath.prepend(
`${ALERTS_PATH}?_a=${encode({
kuery: `${queryField}:"${nodeName}"`,
kuery: `${queryField}:"${assetName}"`,
rangeFrom: dateRange.from,
rangeTo: dateRange.to,
status: 'all',
Expand All @@ -35,7 +35,7 @@ export const LinkToAlertsPage = ({ nodeName, queryField, dateRange }: LinkToAler
return (
<RedirectAppLinks coreStart={services}>
<EuiButtonEmpty
data-test-subj="assetDetails-flyout-alerts-link"
data-test-subj="infraAssetDetailsAlertsShowAllButton"
size="xs"
iconSide="right"
iconType="sortRight"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,18 @@ import { EuiButtonEmpty } from '@elastic/eui';
import { useKibanaContextForPlugin } from '../../../hooks/use_kibana';

export interface LinkToApmServicesProps {
nodeName: string;
assetName: string;
apmField: string;
}

export const LinkToApmServices = ({ nodeName, apmField }: LinkToApmServicesProps) => {
export const LinkToApmServices = ({ assetName, apmField }: LinkToApmServicesProps) => {
const { services } = useKibanaContextForPlugin();
const { http } = services;

const queryString = new URLSearchParams(
encode(
stringify({
kuery: `${apmField}:"${nodeName}"`,
kuery: `${apmField}:"${assetName}"`,
})
)
);
Expand All @@ -34,7 +34,7 @@ export const LinkToApmServices = ({ nodeName, apmField }: LinkToApmServicesProps
return (
<RedirectAppLinks coreStart={services}>
<EuiButtonEmpty
data-test-subj="hostsView-flyout-apm-services-link"
data-test-subj="infraAssetDetailsViewAPMServicesButton"
size="xs"
flush="both"
href={linkToApmServices}
Expand Down
Loading