mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Infra] Use asset details flyout overview and metadata for containers (#183767)
Closes #183727 ## Summary This PR adds asset details flyout to the inventory containers view. The feature flag `observability:enableInfrastructureContainerAssetView` should be enabled to see it. To handle the asset type switching in the asset details flyout this PR adds asset type to the `assetDetailsFlyout` URL param Before:  After: - Overview  - Metadata  ## Testing - Enable `observability:enableInfrastructureContainerAssetView` in infra settings - Go to containers view, click on a container, and check the content5ba578e6
-6cdd-4561-a1f6-27ff4962ef6f
This commit is contained in:
parent
742dff0f22
commit
df74eb609c
9 changed files with 81 additions and 29 deletions
|
@ -90,6 +90,13 @@ const dashboardsTab: Tab = {
|
|||
),
|
||||
};
|
||||
|
||||
const linkToApmTab: Tab = {
|
||||
id: ContentTabIds.LINK_TO_APM,
|
||||
name: i18n.translate('xpack.infra.assetDetails.tabs.linkToApm', {
|
||||
defaultMessage: 'APM',
|
||||
}),
|
||||
};
|
||||
|
||||
export const hostDetailsTabs: Tab[] = [
|
||||
overviewTab,
|
||||
metadataTab,
|
||||
|
@ -101,8 +108,11 @@ export const hostDetailsTabs: Tab[] = [
|
|||
osqueryTab,
|
||||
dashboardsTab,
|
||||
];
|
||||
export const hostDetailsFlyoutTabs: Tab[] = [...hostDetailsTabs, linkToApmTab];
|
||||
|
||||
// Profiling and Logs tab would be added in next iteration
|
||||
export const containerDetailsTabs: Tab[] = [overviewTab, metadataTab];
|
||||
export const containerDetailsFlyoutTabs: Tab[] = [overviewTab, metadataTab, linkToApmTab];
|
||||
|
||||
export const getAssetDetailsTabs = (type: string): Tab[] => {
|
||||
switch (type) {
|
||||
|
@ -114,3 +124,14 @@ export const getAssetDetailsTabs = (type: string): Tab[] => {
|
|||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
export const getAssetDetailsFlyoutTabs = (type: string): Tab[] => {
|
||||
switch (type) {
|
||||
case 'host':
|
||||
return hostDetailsFlyoutTabs;
|
||||
case 'container':
|
||||
return containerDetailsFlyoutTabs;
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
|
|
@ -5,12 +5,18 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { INTEGRATION_NAME } from './types';
|
||||
import { INTEGRATION_NAME, ASSET_DETAILS_ASSET_TYPE } from './types';
|
||||
|
||||
export const ASSET_DETAILS_FLYOUT_COMPONENT_NAME = 'infraAssetDetailsFlyout';
|
||||
export const ASSET_DETAILS_PAGE_COMPONENT_NAME = 'infraAssetDetailsPage';
|
||||
|
||||
export const APM_HOST_FILTER_FIELD = 'host.hostname';
|
||||
export const APM_CONTAINER_FILTER_FIELD = 'container.id';
|
||||
|
||||
export const APM_FILTER_FIELD_PER_ASSET_TYPE = {
|
||||
[ASSET_DETAILS_ASSET_TYPE.container]: APM_CONTAINER_FILTER_FIELD,
|
||||
[ASSET_DETAILS_ASSET_TYPE.host]: APM_HOST_FILTER_FIELD,
|
||||
};
|
||||
|
||||
export const ASSET_DETAILS_URL_STATE_KEY = 'assetDetails';
|
||||
|
||||
|
|
|
@ -22,11 +22,11 @@ import { usePluginConfig } from '../../../containers/plugin_config_context';
|
|||
import { useKibanaContextForPlugin } from '../../../hooks/use_kibana';
|
||||
import { useProfilingIntegrationSetting } from '../../../hooks/use_profiling_integration_setting';
|
||||
import { CreateAlertRuleButton } from '../../shared/alerts/links/create_alert_rule_button';
|
||||
import { APM_HOST_FILTER_FIELD } from '../constants';
|
||||
import { LinkToNodeDetails } from '../links';
|
||||
import { ContentTabIds, type LinkOptions, type RouteState, type Tab, type TabIds } from '../types';
|
||||
import { useAssetDetailsRenderPropsContext } from './use_asset_details_render_props';
|
||||
import { useTabSwitcherContext } from './use_tab_switcher';
|
||||
import { getApmField } from '../utils';
|
||||
|
||||
type TabItem = NonNullable<Pick<EuiPageHeaderProps, 'tabs'>['tabs']>[number];
|
||||
|
||||
|
@ -157,7 +157,7 @@ const useTabs = (tabs: Tab[]) => {
|
|||
app: 'apm',
|
||||
hash: 'traces',
|
||||
search: {
|
||||
kuery: `${APM_HOST_FILTER_FIELD}:"${asset.name}"`,
|
||||
kuery: `${getApmField(asset.type)}:"${asset.id}"`,
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -102,3 +102,8 @@ export enum INTEGRATION_NAME {
|
|||
kubernetesContainer = 'kubernetesContainer',
|
||||
docker = 'docker',
|
||||
}
|
||||
|
||||
export enum ASSET_DETAILS_ASSET_TYPE {
|
||||
container = 'container',
|
||||
host = 'host',
|
||||
}
|
||||
|
|
|
@ -5,8 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { InventoryItemType } from '@kbn/metrics-data-access-plugin/common';
|
||||
import type { InfraMetadata } from '../../../common/http_api';
|
||||
import { INTEGRATIONS } from './constants';
|
||||
import { INTEGRATIONS, APM_FILTER_FIELD_PER_ASSET_TYPE } from './constants';
|
||||
|
||||
export const toTimestampRange = ({ from, to }: { from: string; to: string }) => {
|
||||
const fromTs = new Date(from).getTime();
|
||||
|
@ -34,3 +35,14 @@ export const getIntegrationsAvailable = (metadata?: InfraMetadata | null) => {
|
|||
.filter(([_, fields]) => metadata?.features?.some((f) => fields.includes(f.name)))
|
||||
.map(([name]) => name);
|
||||
};
|
||||
|
||||
export const getApmField = (assetType: InventoryItemType): string => {
|
||||
switch (assetType) {
|
||||
case 'host':
|
||||
return APM_FILTER_FIELD_PER_ASSET_TYPE.host;
|
||||
case 'container':
|
||||
return APM_FILTER_FIELD_PER_ASSET_TYPE.container;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { usePerformanceContext } from '@kbn/ebt-tools';
|
||||
import React, { useCallback } from 'react';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { useCurrentEuiBreakpoint } from '@elastic/eui';
|
||||
import { euiStyled } from '@kbn/kibana-react-plugin/common';
|
||||
import { InventoryItemType } from '@kbn/metrics-data-access-plugin/common';
|
||||
|
@ -63,11 +63,20 @@ export const NodesOverview = ({
|
|||
isAutoReloading,
|
||||
}: Props) => {
|
||||
const currentBreakpoint = useCurrentEuiBreakpoint();
|
||||
const [{ detailsItemId }, setFlyoutUrlState] = useAssetDetailsFlyoutState();
|
||||
const [{ detailsItemId, assetType }, setFlyoutUrlState] = useAssetDetailsFlyoutState();
|
||||
const { onPageReady } = usePerformanceContext();
|
||||
|
||||
const nodeName = useMemo(
|
||||
() => nodes.find((node) => node.path[0].value === detailsItemId)?.name,
|
||||
[detailsItemId, nodes]
|
||||
);
|
||||
|
||||
const closeFlyout = useCallback(
|
||||
() => setFlyoutUrlState({ detailsItemId: null }),
|
||||
() =>
|
||||
setFlyoutUrlState({
|
||||
detailsItemId: null,
|
||||
assetType: null,
|
||||
}),
|
||||
[setFlyoutUrlState]
|
||||
);
|
||||
|
||||
|
@ -149,9 +158,10 @@ export const NodesOverview = ({
|
|||
bottomMargin={bottomMargin}
|
||||
staticHeight={isStatic}
|
||||
/>
|
||||
{nodeType === 'host' && detailsItemId && (
|
||||
{nodeType === assetType && detailsItemId && (
|
||||
<AssetDetailsFlyout
|
||||
assetName={detailsItemId}
|
||||
assetId={detailsItemId}
|
||||
assetName={nodeName}
|
||||
assetType={nodeType}
|
||||
closeFlyout={closeFlyout}
|
||||
currentTime={currentTime}
|
||||
|
|
|
@ -5,17 +5,16 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React, { useMemo } from 'react';
|
||||
import { InventoryItemType } from '@kbn/metrics-data-access-plugin/common';
|
||||
import type { InventoryItemType } from '@kbn/metrics-data-access-plugin/common';
|
||||
import type { InfraWaffleMapOptions } from '../../../../../lib/lib';
|
||||
import { ContentTabIds } from '../../../../../components/asset_details/types';
|
||||
import { AssetDetails } from '../../../../../components/asset_details';
|
||||
import { useSourceContext } from '../../../../../containers/metrics_source';
|
||||
import { hostDetailsTabs } from '../../../../../common/asset_details_config/asset_details_tabs';
|
||||
import { getAssetDetailsFlyoutTabs } from '../../../../../common/asset_details_config/asset_details_tabs';
|
||||
|
||||
interface Props {
|
||||
assetName: string;
|
||||
assetName?: string;
|
||||
assetId: string;
|
||||
assetType: InventoryItemType;
|
||||
closeFlyout: () => void;
|
||||
currentTime: number;
|
||||
|
@ -24,20 +23,11 @@ interface Props {
|
|||
refreshInterval?: number;
|
||||
}
|
||||
|
||||
const flyoutTabs = [
|
||||
...hostDetailsTabs,
|
||||
{
|
||||
id: ContentTabIds.LINK_TO_APM,
|
||||
name: i18n.translate('xpack.infra.assetDetails.tabs.linkToApm', {
|
||||
defaultMessage: 'APM',
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
||||
const ONE_HOUR = 60 * 60 * 1000;
|
||||
|
||||
export const AssetDetailsFlyout = ({
|
||||
assetName,
|
||||
assetId,
|
||||
assetType,
|
||||
closeFlyout,
|
||||
currentTime,
|
||||
|
@ -62,7 +52,7 @@ export const AssetDetailsFlyout = ({
|
|||
|
||||
return source ? (
|
||||
<AssetDetails
|
||||
assetId={assetName}
|
||||
assetId={assetId}
|
||||
assetName={assetName}
|
||||
assetType={assetType}
|
||||
overrides={{
|
||||
|
@ -73,7 +63,7 @@ export const AssetDetailsFlyout = ({
|
|||
options,
|
||||
},
|
||||
}}
|
||||
tabs={flyoutTabs}
|
||||
tabs={getAssetDetailsFlyoutTabs(assetType)}
|
||||
links={['nodeDetails']}
|
||||
renderMode={{
|
||||
mode: 'flyout',
|
||||
|
|
|
@ -11,6 +11,8 @@ import { first } from 'lodash';
|
|||
import { EuiPopover, EuiToolTip } from '@elastic/eui';
|
||||
import { InventoryItemType } from '@kbn/metrics-data-access-plugin/common';
|
||||
import { useBoolean } from '@kbn/react-hooks';
|
||||
import { useUiSetting } from '@kbn/kibana-react-plugin/public';
|
||||
import { enableInfrastructureContainerAssetView } from '@kbn/observability-plugin/common';
|
||||
import {
|
||||
InfraWaffleMapBounds,
|
||||
InfraWaffleMapNode,
|
||||
|
@ -54,9 +56,13 @@ export const Node = ({
|
|||
const color = colorFromValue(options.legend, rawValue, bounds);
|
||||
const value = formatter(rawValue);
|
||||
|
||||
const isContainerAssetViewEnabled = useUiSetting(enableInfrastructureContainerAssetView);
|
||||
|
||||
const showContainerAssetDetailPage = nodeType === 'container' && isContainerAssetViewEnabled;
|
||||
|
||||
const toggleAssetPopover = () => {
|
||||
if (nodeType === 'host') {
|
||||
setFlyoutUrlState({ detailsItemId: node.name });
|
||||
if (nodeType === 'host' || showContainerAssetDetailPage) {
|
||||
setFlyoutUrlState({ detailsItemId: node.id, assetType: nodeType });
|
||||
} else {
|
||||
togglePopover();
|
||||
}
|
||||
|
@ -71,7 +77,7 @@ export const Node = ({
|
|||
color={color}
|
||||
nodeName={node.name}
|
||||
value={value}
|
||||
showBorder={detailsItemId === node.name || isPopoverOpen}
|
||||
showBorder={detailsItemId === node.id || isPopoverOpen}
|
||||
/>
|
||||
);
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import { useUrlState } from '../../../../utils/use_url_state';
|
|||
|
||||
export const GET_DEFAULT_PROPERTIES: AssetDetailsFlyoutProperties = {
|
||||
detailsItemId: null,
|
||||
assetType: null,
|
||||
};
|
||||
|
||||
const ASSET_DETAILS_FLYOUT_URL_STATE_KEY = 'assetDetailsFlyout';
|
||||
|
@ -35,6 +36,7 @@ export const useAssetDetailsFlyoutState = (): [
|
|||
|
||||
const AssetDetailsFlyoutStateRT = rt.type({
|
||||
detailsItemId: rt.union([rt.string, rt.null]),
|
||||
assetType: rt.union([rt.string, rt.null]),
|
||||
});
|
||||
|
||||
export type AssetDetailsFlyoutState = rt.TypeOf<typeof AssetDetailsFlyoutStateRT>;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue