Skip to content
/ kibana Public
forked from elastic/kibana

Commit c9baaef

Browse files
[7.x] [Metrics UI] Add basic interaction and shell for node details overlay (elastic#82013) (elastic#83388)
* [Metrics UI] Add basic interaction and shell for node details overlay (elastic#82013) * Add basic interaction and shell for node details overlay * Fix typecheck * Remove context menu tests because context menu doesn't exist * Remove outdated tests * Remove unused variable * Show the old overlay by default * Fix typecheck * Fix typo Co-authored-by: Kibana Machine <[email protected]> # Conflicts: # x-pack/test/functional/apps/infra/feature_controls/infrastructure_security.ts * Fix merge issue Co-authored-by: Kibana Machine <[email protected]>
1 parent 9bc8cea commit c9baaef

File tree

9 files changed

+237
-101
lines changed

9 files changed

+237
-101
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import { EuiTabbedContent } from '@elastic/eui';
8+
import { FormattedMessage } from '@kbn/i18n/react';
9+
import { EuiPanel } from '@elastic/eui';
10+
import React, { CSSProperties, useMemo } from 'react';
11+
import { EuiText } from '@elastic/eui';
12+
import { EuiFlexGroup, EuiFlexItem, EuiButtonEmpty } from '@elastic/eui';
13+
import { euiStyled } from '../../../../../../../observability/public';
14+
import { InfraWaffleMapNode, InfraWaffleMapOptions } from '../../../../../lib/lib';
15+
import { InventoryItemType } from '../../../../../../common/inventory_models/types';
16+
import { MetricsTab } from './tabs/metrics';
17+
import { LogsTab } from './tabs/logs';
18+
import { ProcessesTab } from './tabs/processes';
19+
import { PropertiesTab } from './tabs/properties';
20+
21+
interface Props {
22+
isOpen: boolean;
23+
onClose(): void;
24+
options: InfraWaffleMapOptions;
25+
currentTime: number;
26+
node: InfraWaffleMapNode;
27+
nodeType: InventoryItemType;
28+
}
29+
export const NodeContextPopover = ({
30+
isOpen,
31+
node,
32+
nodeType,
33+
currentTime,
34+
options,
35+
onClose,
36+
}: Props) => {
37+
const tabConfigs = [MetricsTab, LogsTab, ProcessesTab, PropertiesTab];
38+
39+
const tabs = useMemo(() => {
40+
return tabConfigs.map((m) => {
41+
const TabContent = m.content;
42+
return {
43+
...m,
44+
content: (
45+
<TabContent node={node} nodeType={nodeType} currentTime={currentTime} options={options} />
46+
),
47+
};
48+
});
49+
}, [tabConfigs, node, nodeType, currentTime, options]);
50+
51+
if (!isOpen) {
52+
return null;
53+
}
54+
55+
return (
56+
<EuiPanel hasShadow={true} paddingSize={'none'} style={panelStyle}>
57+
<OverlayHeader>
58+
<EuiFlexGroup alignItems={'center'}>
59+
<EuiFlexItem grow={true}>
60+
<EuiText>
61+
<h4>{node.name}</h4>
62+
</EuiText>
63+
</EuiFlexItem>
64+
<EuiFlexItem grow={false}>
65+
<EuiButtonEmpty onClick={onClose} iconType={'cross'}>
66+
<FormattedMessage id="xpack.infra.infra.nodeDetails.close" defaultMessage="Close" />
67+
</EuiButtonEmpty>
68+
</EuiFlexItem>
69+
</EuiFlexGroup>
70+
</OverlayHeader>
71+
<EuiTabbedContent tabs={tabs} />
72+
</EuiPanel>
73+
);
74+
};
75+
76+
const OverlayHeader = euiStyled.div`
77+
border-color: ${(props) => props.theme.eui.euiBorderColor};
78+
border-bottom-width: ${(props) => props.theme.eui.euiBorderWidthThick};
79+
padding: ${(props) => props.theme.eui.euiSizeS};
80+
padding-bottom: 0;
81+
overflow: hidden;
82+
`;
83+
84+
const panelStyle: CSSProperties = {
85+
position: 'absolute',
86+
right: 10,
87+
top: -100,
88+
width: '50%',
89+
maxWidth: 600,
90+
zIndex: 2,
91+
height: '50vh',
92+
overflow: 'hidden',
93+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import React from 'react';
8+
import { i18n } from '@kbn/i18n';
9+
import { TabContent, TabProps } from './shared';
10+
11+
const TabComponent = (props: TabProps) => {
12+
return <TabContent>Logs Placeholder</TabContent>;
13+
};
14+
15+
export const LogsTab = {
16+
id: 'logs',
17+
name: i18n.translate('xpack.infra.nodeDetails.tabs.logs', {
18+
defaultMessage: 'Logs',
19+
}),
20+
content: TabComponent,
21+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import React from 'react';
8+
import { i18n } from '@kbn/i18n';
9+
import { TabContent, TabProps } from './shared';
10+
11+
const TabComponent = (props: TabProps) => {
12+
return <TabContent>Metrics Placeholder</TabContent>;
13+
};
14+
15+
export const MetricsTab = {
16+
id: 'metrics',
17+
name: i18n.translate('xpack.infra.nodeDetails.tabs.metrics', {
18+
defaultMessage: 'Metrics',
19+
}),
20+
content: TabComponent,
21+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import React from 'react';
8+
import { i18n } from '@kbn/i18n';
9+
import { TabContent, TabProps } from './shared';
10+
11+
const TabComponent = (props: TabProps) => {
12+
return <TabContent>Processes Placeholder</TabContent>;
13+
};
14+
15+
export const ProcessesTab = {
16+
id: 'processes',
17+
name: i18n.translate('xpack.infra.nodeDetails.tabs.processes', {
18+
defaultMessage: 'Processes',
19+
}),
20+
content: TabComponent,
21+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import React from 'react';
8+
import { i18n } from '@kbn/i18n';
9+
import { TabContent, TabProps } from './shared';
10+
11+
const TabComponent = (props: TabProps) => {
12+
return <TabContent>Properties Placeholder</TabContent>;
13+
};
14+
15+
export const PropertiesTab = {
16+
id: 'properties',
17+
name: i18n.translate('xpack.infra.nodeDetails.tabs.properties', {
18+
defaultMessage: 'Properties',
19+
}),
20+
content: TabComponent,
21+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import { InventoryItemType } from '../../../../../../../common/inventory_models/types';
8+
import { InfraWaffleMapOptions, InfraWaffleMapNode } from '../../../../../../lib/lib';
9+
import { euiStyled } from '../../../../../../../../observability/public';
10+
11+
export interface TabProps {
12+
options: InfraWaffleMapOptions;
13+
currentTime: number;
14+
node: InfraWaffleMapNode;
15+
nodeType: InventoryItemType;
16+
}
17+
18+
export const TabContent = euiStyled.div`
19+
padding: ${(props) => props.theme.eui.paddingSizes.l};
20+
`;

x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node.tsx

+29-18
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,21 @@ import React from 'react';
1010
import { i18n } from '@kbn/i18n';
1111

1212
import { first } from 'lodash';
13-
import { ConditionalToolTip } from './conditional_tooltip';
1413
import { euiStyled } from '../../../../../../../observability/public';
1514
import {
1615
InfraWaffleMapBounds,
1716
InfraWaffleMapNode,
1817
InfraWaffleMapOptions,
1918
} from '../../../../../lib/lib';
2019
import { colorFromValue } from '../../lib/color_from_value';
21-
import { NodeContextMenu } from './node_context_menu';
2220
import { InventoryItemType } from '../../../../../../common/inventory_models/types';
21+
import { NodeContextPopover } from '../node_details/overlay';
22+
23+
import { NodeContextMenu } from './node_context_menu';
2324

2425
const initialState = {
2526
isPopoverOpen: false,
27+
isOverlayOpen: false,
2628
};
2729

2830
type State = Readonly<typeof initialState>;
@@ -53,22 +55,16 @@ export const Node = class extends React.PureComponent<Props, State> {
5355
values: { nodeName: node.name },
5456
});
5557
return (
56-
<NodeContextMenu
57-
node={node}
58-
nodeType={nodeType}
59-
isPopoverOpen={isPopoverOpen}
60-
closePopover={this.closePopover}
61-
options={options}
62-
currentTime={currentTime}
63-
popoverPosition="downCenter"
64-
>
65-
<ConditionalToolTip
66-
currentTime={currentTime}
67-
formatter={formatter}
68-
hidden={isPopoverOpen}
58+
<>
59+
<NodeContextMenu
6960
node={node}
70-
options={options}
7161
nodeType={nodeType}
62+
isPopoverOpen={isPopoverOpen}
63+
closePopover={this.closePopover}
64+
options={options}
65+
currentTime={currentTime}
66+
popoverPosition="downCenter"
67+
openNewOverlay={this.toggleNewOverlay}
7268
>
7369
<NodeContainer
7470
data-test-subj="nodeContainer"
@@ -92,15 +88,30 @@ export const Node = class extends React.PureComponent<Props, State> {
9288
</SquareInner>
9389
</SquareOuter>
9490
</NodeContainer>
95-
</ConditionalToolTip>
96-
</NodeContextMenu>
91+
</NodeContextMenu>
92+
<NodeContextPopover
93+
node={node}
94+
nodeType={nodeType}
95+
isOpen={this.state.isOverlayOpen}
96+
options={options}
97+
currentTime={currentTime}
98+
onClose={this.toggleNewOverlay}
99+
/>
100+
</>
97101
);
98102
}
99103

100104
private togglePopover = () => {
101105
this.setState((prevState) => ({ isPopoverOpen: !prevState.isPopoverOpen }));
102106
};
103107

108+
private toggleNewOverlay = () => {
109+
this.setState((prevState) => ({
110+
isPopoverOpen: !prevState.isOverlayOpen === true ? false : prevState.isPopoverOpen,
111+
isOverlayOpen: !prevState.isOverlayOpen,
112+
}));
113+
};
114+
104115
private closePopover = () => {
105116
if (this.state.isPopoverOpen) {
106117
this.setState({ isPopoverOpen: false });

x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node_context_menu.tsx

+11
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ interface Props {
3737
isPopoverOpen: boolean;
3838
closePopover: () => void;
3939
popoverPosition: EuiPopoverProps['anchorPosition'];
40+
openNewOverlay?: () => void;
4041
}
4142

4243
export const NodeContextMenu: React.FC<Props & { theme?: EuiTheme }> = withTheme(
@@ -50,6 +51,7 @@ export const NodeContextMenu: React.FC<Props & { theme?: EuiTheme }> = withTheme
5051
nodeType,
5152
popoverPosition,
5253
theme,
54+
openNewOverlay,
5355
}) => {
5456
const [flyoutVisible, setFlyoutVisible] = useState(false);
5557
const inventoryModel = findInventoryModel(nodeType);
@@ -159,6 +161,14 @@ export const NodeContextMenu: React.FC<Props & { theme?: EuiTheme }> = withTheme
159161
},
160162
};
161163

164+
const openNewOverlayMenuItem: SectionLinkProps = {
165+
label: i18n.translate('xpack.infra.nodeContextMenu.openNewOverlay', {
166+
defaultMessage: '**** [NEW] Overlay ***',
167+
}),
168+
style: { color: theme?.eui.euiLinkColor || '#006BB4', fontWeight: 500, padding: 0 },
169+
onClick: openNewOverlay,
170+
};
171+
162172
return (
163173
<>
164174
<ActionMenu
@@ -194,6 +204,7 @@ export const NodeContextMenu: React.FC<Props & { theme?: EuiTheme }> = withTheme
194204
<SectionLink data-test-subj="viewApmTracesContextMenuItem" {...apmTracesMenuItem} />
195205
<SectionLink {...uptimeMenuItem} />
196206
<SectionLink {...createAlertMenuItem} />
207+
<SectionLink {...openNewOverlayMenuItem} />
197208
</SectionLinks>
198209
</Section>
199210
</div>

0 commit comments

Comments
 (0)