[Metrics UI] Inventory view cleanup (#79881)

* Add background to Show History

* Fix legend centering

* Fix sentence casing in timeline popovers

* Improve small-screen responsiveness of filter dropdowns

* Improve top action responsiveness

* Remove unneeded align center

* Improve waffle map small screen responsiveness

* Fix inventory timeline color legend

* Fix loading spinner wrap

* Fix color legend

* Improve filter responsiveness

* Fix z-index on view switcher

* Move manage views flyout into portal

* Set waffle map to di display: static at s breakpoint

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Zacqary Adam Xeper 2020-10-14 16:34:35 -05:00 committed by GitHub
parent cb934344d3
commit f3ee7a32ca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 132 additions and 108 deletions

View file

@ -27,10 +27,8 @@ export const LoadingPage = ({
<FlexPage data-test-subj={dataTestSubj}>
<EuiPageBody>
<EuiPageContent verticalPosition="center" horizontalPosition="center">
<EuiFlexGroup alignItems="center">
<EuiFlexItem grow={false}>
<EuiLoadingSpinner size="xl" />
</EuiFlexItem>
<EuiFlexGroup alignItems="center" style={{ flexWrap: 'nowrap' }}>
<EuiLoadingSpinner size="xl" style={{ marginRight: '8px' }} />
<EuiFlexItem data-test-subj="loadingMessage">{message}</EuiFlexItem>
</EuiFlexGroup>
</EuiPageContent>

View file

@ -16,6 +16,7 @@ import {
EuiInMemoryTable,
EuiFlexGroup,
EuiButton,
EuiPortal,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
@ -157,34 +158,36 @@ export function SavedViewManageViewsFlyout<ViewState>({
];
return (
<EuiFlyout onClose={close} data-test-subj="loadViewsFlyout">
<EuiFlyoutHeader>
<EuiTitle size="m">
<h2>
<FormattedMessage
defaultMessage="Manage saved views"
id="xpack.infra.openView.flyoutHeader"
/>
</h2>
</EuiTitle>
</EuiFlyoutHeader>
<EuiPortal>
<EuiFlyout onClose={close} data-test-subj="loadViewsFlyout">
<EuiFlyoutHeader>
<EuiTitle size="m">
<h2>
<FormattedMessage
defaultMessage="Manage saved views"
id="xpack.infra.openView.flyoutHeader"
/>
</h2>
</EuiTitle>
</EuiFlyoutHeader>
<EuiFlyoutBody>
<EuiInMemoryTable
items={views}
columns={columns}
loading={loading}
search={true}
pagination={true}
sorting={true}
/>
</EuiFlyoutBody>
<EuiFlyoutBody>
<EuiInMemoryTable
items={views}
columns={columns}
loading={loading}
search={true}
pagination={true}
sorting={true}
/>
</EuiFlyoutBody>
<EuiModalFooter>
<EuiButtonEmpty data-test-subj="cancelSavedViewModal" onClick={close}>
<FormattedMessage defaultMessage="Cancel" id="xpack.infra.openView.cancelButton" />
</EuiButtonEmpty>
</EuiModalFooter>
</EuiFlyout>
<EuiModalFooter>
<EuiButtonEmpty data-test-subj="cancelSavedViewModal" onClick={close}>
<FormattedMessage defaultMessage="Cancel" id="xpack.infra.openView.cancelButton" />
</EuiButtonEmpty>
</EuiModalFooter>
</EuiFlyout>
</EuiPortal>
);
}

View file

@ -121,24 +121,29 @@ export const InfrastructurePage = ({ match }: RouteComponentProps) => {
]}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<Route path={'/inventory'} component={AnomalyDetectionFlyout} />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<Route path={'/explorer'} component={MetricsAlertDropdown} />
<Route path={'/inventory'} component={InventoryAlertDropdown} />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonEmpty
href={kibana.services?.application?.getUrlForApp(
'/home#/tutorial_directory/metrics'
)}
size="s"
color="primary"
iconType="plusInCircle"
>
{ADD_DATA_LABEL}
</EuiButtonEmpty>
<EuiFlexItem
grow={false}
style={{ flexDirection: 'row', alignItems: 'center' }}
>
<EuiFlexItem grow={false}>
<Route path={'/inventory'} component={AnomalyDetectionFlyout} />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<Route path={'/explorer'} component={MetricsAlertDropdown} />
<Route path={'/inventory'} component={InventoryAlertDropdown} />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonEmpty
href={kibana.services?.application?.getUrlForApp(
'/home#/tutorial_directory/metrics'
)}
size="s"
color="primary"
iconType="plusInCircle"
>
{ADD_DATA_LABEL}
</EuiButtonEmpty>
</EuiFlexItem>
</EuiFlexItem>
</EuiFlexGroup>
</AppNavigation>

View file

@ -47,15 +47,12 @@ export const BottomDrawer: React.FC<{
style={{
position: 'relative',
minWidth: 400,
alignSelf: 'center',
height: '16px',
}}
>
{children}
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiSpacer size="xs" />
</EuiFlexItem>
<RightSideSpacer />
</BottomActionTopBar>
<EuiFlexGroup style={{ marginTop: 0 }}>
<Timeline isVisible={isOpen} interval={interval} yAxisFormatter={formatter} />
@ -85,3 +82,7 @@ const BottomActionTopBar = euiStyled(EuiFlexGroup).attrs({
const ShowHideButton = euiStyled(EuiButtonEmpty).attrs({ size: 's' })`
width: 140px;
`;
const RightSideSpacer = euiStyled(EuiSpacer).attrs({ size: 'xs' })`
width: 140px;
`;

View file

@ -104,46 +104,57 @@ export const Layout = () => {
<>
<PageContent>
<MainContainer>
<TopActionContainer>
<EuiFlexGroup justifyContent="spaceBetween" alignItems="center" gutterSize="m">
<Toolbar nodeType={nodeType} />
<EuiFlexItem grow={false}>
<IntervalLabel intervalAsString={intervalAsString} />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<ViewSwitcher view={view} onChange={changeView} />
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer />
<SavedViewContainer>
<SavedViewsToolbarControls viewState={viewState} />
</SavedViewContainer>
</TopActionContainer>
<AutoSizer bounds>
{({ measureRef, bounds: { height = 0 } }) => (
{({ measureRef: topActionMeasureRef, bounds: { height: topActionHeight = 0 } }) => (
<>
<NodesOverview
nodes={nodes}
options={options}
nodeType={nodeType}
loading={loading}
reload={reload}
onDrilldown={applyFilterQuery}
currentTime={currentTime}
view={view}
autoBounds={autoBounds}
boundsOverride={boundsOverride}
formatter={formatter}
bottomMargin={height}
/>
<BottomDrawer measureRef={measureRef} interval={interval} formatter={formatter}>
<Legend
formatter={formatter}
bounds={bounds}
dataBounds={dataBounds}
legend={options.legend}
/>
</BottomDrawer>
<TopActionContainer ref={topActionMeasureRef}>
<EuiFlexGroup justifyContent="spaceBetween" alignItems="center" gutterSize="m">
<Toolbar nodeType={nodeType} />
<EuiFlexItem grow={false}>
<IntervalLabel intervalAsString={intervalAsString} />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<ViewSwitcher view={view} onChange={changeView} />
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer />
<SavedViewContainer>
<SavedViewsToolbarControls viewState={viewState} />
</SavedViewContainer>
</TopActionContainer>
<AutoSizer bounds>
{({ measureRef, bounds: { height = 0 } }) => (
<>
<NodesOverview
nodes={nodes}
options={options}
nodeType={nodeType}
loading={loading}
reload={reload}
onDrilldown={applyFilterQuery}
currentTime={currentTime}
view={view}
autoBounds={autoBounds}
boundsOverride={boundsOverride}
formatter={formatter}
bottomMargin={height}
topMargin={topActionHeight}
/>
<BottomDrawer
measureRef={measureRef}
interval={interval}
formatter={formatter}
>
<Legend
formatter={formatter}
bounds={bounds}
dataBounds={dataBounds}
legend={options.legend}
/>
</BottomDrawer>
</>
)}
</AutoSizer>
</>
)}
</AutoSizer>

View file

@ -6,6 +6,7 @@
import { i18n } from '@kbn/i18n';
import React, { useCallback } from 'react';
import { getBreakpoint } from '@elastic/eui';
import { InventoryItemType } from '../../../../../common/inventory_models/types';
import { euiStyled } from '../../../../../../observability/public';
@ -35,6 +36,7 @@ interface Props {
autoBounds: boolean;
formatter: InfraFormatter;
bottomMargin: number;
topMargin: number;
}
export const NodesOverview = ({
@ -50,6 +52,7 @@ export const NodesOverview = ({
formatter,
onDrilldown,
bottomMargin,
topMargin,
}: Props) => {
const handleDrilldown = useCallback(
(filter: string) => {
@ -94,6 +97,7 @@ export const NodesOverview = ({
}
const dataBounds = calculateBoundsFromNodes(nodes);
const bounds = autoBounds ? dataBounds : boundsOverride;
const isStatic = ['xs', 's'].includes(getBreakpoint(window.innerWidth)!);
if (view === 'table') {
return (
@ -110,7 +114,7 @@ export const NodesOverview = ({
);
}
return (
<MapContainer>
<MapContainer top={topMargin} positionStatic={isStatic}>
<Map
nodeType={nodeType}
nodes={nodes}
@ -121,6 +125,7 @@ export const NodesOverview = ({
bounds={bounds}
dataBounds={dataBounds}
bottomMargin={bottomMargin}
staticHeight={isStatic}
/>
</MapContainer>
);
@ -130,10 +135,10 @@ const TableContainer = euiStyled.div`
padding: ${(props) => props.theme.eui.paddingSizes.l};
`;
const MapContainer = euiStyled.div`
position: absolute;
const MapContainer = euiStyled.div<{ top: number; positionStatic: boolean }>`
position: ${(props) => (props.positionStatic ? 'static' : 'absolute')};
display: flex;
top: 70px;
top: ${(props) => props.top}px;
right: 0;
bottom: 0;
left: 0;

View file

@ -27,7 +27,7 @@ import { EuiIcon } from '@elastic/eui';
import { useUiSetting } from '../../../../../../../../../src/plugins/kibana_react/public';
import { toMetricOpt } from '../../../../../../common/snapshot_metric_i18n';
import { MetricsExplorerAggregation } from '../../../../../../common/http_api';
import { Color } from '../../../../../../common/color_palette';
import { colorTransformer, Color } from '../../../../../../common/color_palette';
import { useSourceContext } from '../../../../../containers/source';
import { useTimeline } from '../../hooks/use_timeline';
import { useWaffleOptionsContext } from '../../hooks/use_waffle_options';
@ -102,11 +102,12 @@ export const Timeline: React.FC<Props> = ({ interval, yAxisFormatter, isVisible
}, [nodeType, metricsHostsAnomalies, metricsK8sAnomalies]);
const metricLabel = toMetricOpt(metric.type)?.textLC;
const metricPopoverLabel = toMetricOpt(metric.type)?.text;
const chartMetric = {
color: Color.color0,
aggregation: 'avg' as MetricsExplorerAggregation,
label: metricLabel,
label: metricPopoverLabel,
};
const dateFormatter = useMemo(() => {
@ -225,10 +226,7 @@ export const Timeline: React.FC<Props> = ({ interval, yAxisFormatter, isVisible
<EuiFlexItem grow={false}>
<EuiFlexGroup gutterSize={'s'} alignItems={'center'}>
<EuiFlexItem grow={false}>
<EuiIcon
color={getTimelineChartTheme(isDarkMode).crosshair.band.fill}
type={'dot'}
/>
<EuiIcon color={colorTransformer(chartMetric.color)} type={'dot'} />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size={'xs'}>
@ -335,11 +333,11 @@ const TimelineLoadingContainer = euiStyled.div`
`;
const noHistoryDataTitle = i18n.translate('xpack.infra.inventoryTimeline.noHistoryDataTitle', {
defaultMessage: 'There is no history data to display.',
defaultMessage: 'There is no historical data to display.',
});
const errorTitle = i18n.translate('xpack.infra.inventoryTimeline.errorTitle', {
defaultMessage: 'Unable to display history data.',
defaultMessage: 'Unable to show historical data.',
});
const checkNewDataButtonLabel = i18n.translate(

View file

@ -5,7 +5,7 @@
*/
import React from 'react';
import { EuiFlexItem } from '@elastic/eui';
import { EuiFlexItem, EuiFlexGroup } from '@elastic/eui';
import { fieldToName } from '../../lib/field_to_display_name';
import { useSourceContext } from '../../../../../containers/source';
import { useWaffleOptionsContext } from '../../hooks/use_waffle_options';
@ -38,7 +38,7 @@ export const ToolbarWrapper = (props: Props) => {
} = useWaffleOptionsContext();
const { createDerivedIndexPattern } = useSourceContext();
return (
<>
<EuiFlexGroup responsive={false} wrap gutterSize="m">
<EuiFlexItem grow={false}>
<WaffleInventorySwitcher />
</EuiFlexItem>
@ -62,7 +62,7 @@ export const ToolbarWrapper = (props: Props) => {
customMetrics,
changeCustomMetrics,
})}
</>
</EuiFlexGroup>
);
};

View file

@ -27,6 +27,7 @@ interface Props {
bounds: InfraWaffleMapBounds;
dataBounds: InfraWaffleMapBounds;
bottomMargin: number;
staticHeight: boolean;
}
export const Map: React.FC<Props> = ({
@ -39,6 +40,7 @@ export const Map: React.FC<Props> = ({
nodeType,
dataBounds,
bottomMargin,
staticHeight,
}) => {
const sortedNodes = sortNodes(options.sort, nodes);
const map = nodesToWaffleMap(sortedNodes);
@ -51,6 +53,7 @@ export const Map: React.FC<Props> = ({
ref={(el: any) => measureRef(el)}
bottomMargin={bottomMargin}
data-test-subj="waffleMap"
staticHeight={staticHeight}
>
<WaffleMapInnerContainer>
{groupsWithLayout.map((group) => {
@ -92,7 +95,7 @@ export const Map: React.FC<Props> = ({
);
};
const WaffleMapOuterContainer = euiStyled.div<{ bottomMargin: number }>`
const WaffleMapOuterContainer = euiStyled.div<{ bottomMargin: number; staticHeight: boolean }>`
flex: 1 0 0%;
display: flex;
justify-content: flex-start;
@ -100,6 +103,7 @@ const WaffleMapOuterContainer = euiStyled.div<{ bottomMargin: number }>`
overflow-x: hidden;
overflow-y: auto;
margin-bottom: ${(props) => props.bottomMargin}px;
${(props) => props.staticHeight && 'min-height: 300px;'}
`;
const WaffleMapInnerContainer = euiStyled.div`

View file

@ -6,7 +6,6 @@
import { EuiButtonGroup, EuiButtonGroupProps } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
interface Props {