diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/overlay.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/overlay.tsx
new file mode 100644
index 0000000000000..dd0060f773b49
--- /dev/null
+++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/overlay.tsx
@@ -0,0 +1,93 @@
+/*
+ * 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 { EuiTabbedContent } from '@elastic/eui';
+import { FormattedMessage } from '@kbn/i18n/react';
+import { EuiPanel } from '@elastic/eui';
+import React, { CSSProperties, useMemo } from 'react';
+import { EuiText } from '@elastic/eui';
+import { EuiFlexGroup, EuiFlexItem, EuiButtonEmpty } from '@elastic/eui';
+import { euiStyled } from '../../../../../../../observability/public';
+import { InfraWaffleMapNode, InfraWaffleMapOptions } from '../../../../../lib/lib';
+import { InventoryItemType } from '../../../../../../common/inventory_models/types';
+import { MetricsTab } from './tabs/metrics';
+import { LogsTab } from './tabs/logs';
+import { ProcessesTab } from './tabs/processes';
+import { PropertiesTab } from './tabs/properties';
+
+interface Props {
+ isOpen: boolean;
+ onClose(): void;
+ options: InfraWaffleMapOptions;
+ currentTime: number;
+ node: InfraWaffleMapNode;
+ nodeType: InventoryItemType;
+}
+export const NodeContextPopover = ({
+ isOpen,
+ node,
+ nodeType,
+ currentTime,
+ options,
+ onClose,
+}: Props) => {
+ const tabConfigs = [MetricsTab, LogsTab, ProcessesTab, PropertiesTab];
+
+ const tabs = useMemo(() => {
+ return tabConfigs.map((m) => {
+ const TabContent = m.content;
+ return {
+ ...m,
+ content: (
+
+ ),
+ };
+ });
+ }, [tabConfigs, node, nodeType, currentTime, options]);
+
+ if (!isOpen) {
+ return null;
+ }
+
+ return (
+
+
+
+
+
+ {node.name}
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+const OverlayHeader = euiStyled.div`
+ border-color: ${(props) => props.theme.eui.euiBorderColor};
+ border-bottom-width: ${(props) => props.theme.eui.euiBorderWidthThick};
+ padding: ${(props) => props.theme.eui.euiSizeS};
+ padding-bottom: 0;
+ overflow: hidden;
+`;
+
+const panelStyle: CSSProperties = {
+ position: 'absolute',
+ right: 10,
+ top: -100,
+ width: '50%',
+ maxWidth: 600,
+ zIndex: 2,
+ height: '50vh',
+ overflow: 'hidden',
+};
diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/logs.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/logs.tsx
new file mode 100644
index 0000000000000..1a8bc374e79a3
--- /dev/null
+++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/logs.tsx
@@ -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;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { i18n } from '@kbn/i18n';
+import { TabContent, TabProps } from './shared';
+
+const TabComponent = (props: TabProps) => {
+ return Logs Placeholder;
+};
+
+export const LogsTab = {
+ id: 'logs',
+ name: i18n.translate('xpack.infra.nodeDetails.tabs.logs', {
+ defaultMessage: 'Logs',
+ }),
+ content: TabComponent,
+};
diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/metrics.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/metrics.tsx
new file mode 100644
index 0000000000000..e329a5771c41d
--- /dev/null
+++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/metrics.tsx
@@ -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;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { i18n } from '@kbn/i18n';
+import { TabContent, TabProps } from './shared';
+
+const TabComponent = (props: TabProps) => {
+ return Metrics Placeholder;
+};
+
+export const MetricsTab = {
+ id: 'metrics',
+ name: i18n.translate('xpack.infra.nodeDetails.tabs.metrics', {
+ defaultMessage: 'Metrics',
+ }),
+ content: TabComponent,
+};
diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes.tsx
new file mode 100644
index 0000000000000..94ba1150c20dd
--- /dev/null
+++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/processes.tsx
@@ -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;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { i18n } from '@kbn/i18n';
+import { TabContent, TabProps } from './shared';
+
+const TabComponent = (props: TabProps) => {
+ return Processes Placeholder;
+};
+
+export const ProcessesTab = {
+ id: 'processes',
+ name: i18n.translate('xpack.infra.nodeDetails.tabs.processes', {
+ defaultMessage: 'Processes',
+ }),
+ content: TabComponent,
+};
diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/properties.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/properties.tsx
new file mode 100644
index 0000000000000..8157aca9b1410
--- /dev/null
+++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/properties.tsx
@@ -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;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { i18n } from '@kbn/i18n';
+import { TabContent, TabProps } from './shared';
+
+const TabComponent = (props: TabProps) => {
+ return Properties Placeholder;
+};
+
+export const PropertiesTab = {
+ id: 'properties',
+ name: i18n.translate('xpack.infra.nodeDetails.tabs.properties', {
+ defaultMessage: 'Properties',
+ }),
+ content: TabComponent,
+};
diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/shared.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/shared.tsx
new file mode 100644
index 0000000000000..241ad7104836e
--- /dev/null
+++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/shared.tsx
@@ -0,0 +1,20 @@
+/*
+ * 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 { InventoryItemType } from '../../../../../../../common/inventory_models/types';
+import { InfraWaffleMapOptions, InfraWaffleMapNode } from '../../../../../../lib/lib';
+import { euiStyled } from '../../../../../../../../observability/public';
+
+export interface TabProps {
+ options: InfraWaffleMapOptions;
+ currentTime: number;
+ node: InfraWaffleMapNode;
+ nodeType: InventoryItemType;
+}
+
+export const TabContent = euiStyled.div`
+ padding: ${(props) => props.theme.eui.paddingSizes.l};
+`;
diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node.tsx
index cc177b895ca50..f2d9da960df81 100644
--- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node.tsx
+++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node.tsx
@@ -10,7 +10,6 @@ import React from 'react';
import { i18n } from '@kbn/i18n';
import { first } from 'lodash';
-import { ConditionalToolTip } from './conditional_tooltip';
import { euiStyled } from '../../../../../../../observability/public';
import {
InfraWaffleMapBounds,
@@ -18,11 +17,14 @@ import {
InfraWaffleMapOptions,
} from '../../../../../lib/lib';
import { colorFromValue } from '../../lib/color_from_value';
-import { NodeContextMenu } from './node_context_menu';
import { InventoryItemType } from '../../../../../../common/inventory_models/types';
+import { NodeContextPopover } from '../node_details/overlay';
+
+import { NodeContextMenu } from './node_context_menu';
const initialState = {
isPopoverOpen: false,
+ isOverlayOpen: false,
};
type State = Readonly;
@@ -53,22 +55,16 @@ export const Node = class extends React.PureComponent {
values: { nodeName: node.name },
});
return (
-
-
+
{
-
-
+
+
+ >
);
}
@@ -101,6 +105,13 @@ export const Node = class extends React.PureComponent {
this.setState((prevState) => ({ isPopoverOpen: !prevState.isPopoverOpen }));
};
+ private toggleNewOverlay = () => {
+ this.setState((prevState) => ({
+ isPopoverOpen: !prevState.isOverlayOpen === true ? false : prevState.isPopoverOpen,
+ isOverlayOpen: !prevState.isOverlayOpen,
+ }));
+ };
+
private closePopover = () => {
if (this.state.isPopoverOpen) {
this.setState({ isPopoverOpen: false });
diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node_context_menu.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node_context_menu.tsx
index d913261521383..91c6ad801000a 100644
--- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node_context_menu.tsx
+++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node_context_menu.tsx
@@ -37,6 +37,7 @@ interface Props {
isPopoverOpen: boolean;
closePopover: () => void;
popoverPosition: EuiPopoverProps['anchorPosition'];
+ openNewOverlay?: () => void;
}
export const NodeContextMenu: React.FC = withTheme(
@@ -50,6 +51,7 @@ export const NodeContextMenu: React.FC = withTheme
nodeType,
popoverPosition,
theme,
+ openNewOverlay,
}) => {
const [flyoutVisible, setFlyoutVisible] = useState(false);
const inventoryModel = findInventoryModel(nodeType);
@@ -159,6 +161,14 @@ export const NodeContextMenu: React.FC = withTheme
},
};
+ const openNewOverlayMenuItem: SectionLinkProps = {
+ label: i18n.translate('xpack.infra.nodeContextMenu.openNewOverlay', {
+ defaultMessage: '**** [NEW] Overlay ***',
+ }),
+ style: { color: theme?.eui.euiLinkColor || '#006BB4', fontWeight: 500, padding: 0 },
+ onClick: openNewOverlay,
+ };
+
return (
<>
= withTheme
+
diff --git a/x-pack/test/functional/apps/infra/feature_controls/infrastructure_security.ts b/x-pack/test/functional/apps/infra/feature_controls/infrastructure_security.ts
index 4cafe049fcbc9..aabbb5d860b92 100644
--- a/x-pack/test/functional/apps/infra/feature_controls/infrastructure_security.ts
+++ b/x-pack/test/functional/apps/infra/feature_controls/infrastructure_security.ts
@@ -15,7 +15,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
const testSubjects = getService('testSubjects');
const appsMenu = getService('appsMenu');
const globalNav = getService('globalNav');
- const retry = getService('retry');
describe('infrastructure security', () => {
describe('global infrastructure all privileges', () => {
@@ -97,24 +96,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
await testSubjects.existOrFail('~waffleMap');
});
- describe('context menu', () => {
- before(async () => {
- await testSubjects.click('~nodeContainer');
- });
-
- it(`does not show link to view logs`, async () => {
- await retry.waitFor('context menu', () => testSubjects.exists('~nodeContextMenu'));
- const link = await testSubjects.find('~viewLogsContextMenuItem');
- expect(await link.isEnabled()).to.be(false);
- });
-
- it(`does not show link to view apm traces`, async () => {
- await retry.waitFor('context menu', () => testSubjects.exists('~nodeContextMenu'));
- const link = await testSubjects.find('~viewApmTracesContextMenuItem');
- expect(await link.isEnabled()).to.be(false);
- });
- });
-
it(`doesn't show read-only badge`, async () => {
await globalNav.badgeMissingOrFail();
});
@@ -213,24 +194,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
await testSubjects.existOrFail('~waffleMap');
});
- describe('context menu', () => {
- before(async () => {
- await testSubjects.click('~nodeContainer');
- });
-
- it(`does not show link to view logs`, async () => {
- await retry.waitFor('context menu', () => testSubjects.exists('~nodeContextMenu'));
- const link = await testSubjects.find('~viewLogsContextMenuItem');
- expect(await link.isEnabled()).to.be(false);
- });
-
- it(`does not show link to view apm traces`, async () => {
- await retry.waitFor('context menu', () => testSubjects.exists('~nodeContextMenu'));
- const link = await testSubjects.find('~viewApmTracesContextMenuItem');
- expect(await link.isEnabled()).to.be(false);
- });
- });
-
it(`shows read-only badge`, async () => {
await globalNav.badgeExistsOrFail('Read only');
});
@@ -300,19 +263,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
after(async () => {
await esArchiver.unload('infra/metrics_and_logs');
});
-
- it(`context menu allows user to view logs`, async () => {
- await PageObjects.common.navigateToUrlWithBrowserHistory('infraOps', '', undefined, {
- ensureCurrentUrl: true,
- shouldLoginIfPrompted: false,
- });
- await PageObjects.infraHome.goToTime(DATE_WITH_DATA);
- await testSubjects.existOrFail('~waffleMap');
- await testSubjects.click('~nodeContainer');
- await retry.waitFor('context menu', () => testSubjects.exists('nodeContextMenu'));
- await testSubjects.click('~viewLogsContextMenuItem');
- await testSubjects.existOrFail('~infraLogsPage');
- });
});
});
@@ -366,19 +316,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
after(async () => {
await esArchiver.unload('infra/metrics_and_logs');
});
-
- it(`context menu allows user to view APM traces`, async () => {
- await PageObjects.common.navigateToUrlWithBrowserHistory('infraOps', '', undefined, {
- ensureCurrentUrl: true,
- shouldLoginIfPrompted: false,
- });
- await PageObjects.infraHome.goToTime(DATE_WITH_DATA);
- await testSubjects.existOrFail('~waffleMap');
- await testSubjects.click('~nodeContainer');
- await retry.waitFor('context menu', () => testSubjects.exists('~nodeContextMenu'));
- await testSubjects.click('~viewApmTracesContextMenuItem');
- await testSubjects.existOrFail('~apmMainContainer');
- });
});
});