[SLO] Fix card view title overlap (#172344)

This commit is contained in:
Shahzad 2023-12-01 13:03:20 +01:00 committed by GitHub
parent abac134908
commit 4fd75a9436
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 85 additions and 33 deletions

View file

@ -0,0 +1,34 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React, { ReactNode, useEffect, useMemo } from 'react';
import { createHtmlPortalNode, InPortal, OutPortal } from 'react-reverse-portal';
import ReactDOM from 'react-dom';
export interface Props {
children: ReactNode;
containerRef: React.RefObject<HTMLDivElement>;
}
export function SloCardBadgesPortal({ children, containerRef }: Props) {
const portalNode = useMemo(() => createHtmlPortalNode(), []);
useEffect(() => {
if (containerRef?.current) {
setTimeout(() => {
const gapDiv = containerRef?.current?.querySelector('.echMetricText__gap');
if (!gapDiv) return;
ReactDOM.render(<OutPortal node={portalNode} />, gapDiv);
}, 100);
}
return () => {
portalNode.unmount();
};
}, [portalNode, containerRef]);
return <InPortal node={portalNode}>{children}</InPortal>;
}

View file

@ -9,16 +9,17 @@ import React, { useState } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import {
Chart,
DARK_THEME,
isMetricElementEvent,
Metric,
Settings,
DARK_THEME,
MetricTrendShape,
Settings,
} from '@elastic/charts';
import { EuiIcon, EuiPanel, useEuiBackgroundColor } from '@elastic/eui';
import { SLOWithSummaryResponse, HistoricalSummaryResponse, ALL_VALUE } from '@kbn/slo-schema';
import { ALL_VALUE, HistoricalSummaryResponse, SLOWithSummaryResponse } from '@kbn/slo-schema';
import { Rule } from '@kbn/triggers-actions-ui-plugin/public';
import { i18n } from '@kbn/i18n';
import { SloCardBadgesPortal } from './badges_portal';
import { useSloListActions } from '../../hooks/use_slo_list_actions';
import { BurnRateRuleFlyout } from '../common/burn_rate_rule_flyout';
import { formatHistoricalData } from '../../../../utils/slo/chart_data_formatter';
@ -52,12 +53,7 @@ const useCardColor = (status?: SLOWithSummaryResponse['summary']['status']) => {
};
const getSubTitle = (slo: SLOWithSummaryResponse, cardsPerRow: number) => {
const subTitle =
slo.groupBy && slo.groupBy !== ALL_VALUE ? `${slo.groupBy}: ${slo.instanceId}` : '';
if (cardsPerRow === 4) {
return subTitle.substring(0, 30) + (subTitle.length > 30 ? '..' : '');
}
return subTitle.substring(0, 40) + (subTitle.length > 40 ? '..' : '');
return slo.groupBy && slo.groupBy !== ALL_VALUE ? `${slo.groupBy}: ${slo.instanceId}` : '';
};
export function SloCardItem({ slo, rules, activeAlerts, historicalSummary, cardsPerRow }: Props) {
@ -65,6 +61,8 @@ export function SloCardItem({ slo, rules, activeAlerts, historicalSummary, cards
application: { navigateToUrl },
} = useKibana().services;
const containerRef = React.useRef<HTMLDivElement>(null);
const [isMouseOver, setIsMouseOver] = useState(false);
const [isActionsPopoverOpen, setIsActionsPopoverOpen] = useState(false);
const [isAddRuleFlyoutOpen, setIsAddRuleFlyoutOpen] = useState(false);
@ -88,6 +86,7 @@ export function SloCardItem({ slo, rules, activeAlerts, historicalSummary, cards
return (
<>
<EuiPanel
panelRef={containerRef as React.Ref<HTMLDivElement>}
onMouseOver={() => {
if (!isMouseOver) {
setIsMouseOver(true);
@ -145,13 +144,6 @@ export function SloCardItem({ slo, rules, activeAlerts, historicalSummary, cards
]}
/>
</Chart>
<SloCardItemBadges
slo={slo}
rules={rules}
activeAlerts={activeAlerts}
handleCreateRule={handleCreateRule}
hasGroupBy={Boolean(slo.groupBy && slo.groupBy !== ALL_VALUE)}
/>
{(isMouseOver || isActionsPopoverOpen) && (
<SloCardItemActions
slo={slo}
@ -162,6 +154,15 @@ export function SloCardItem({ slo, rules, activeAlerts, historicalSummary, cards
/>
)}
</EuiPanel>
<SloCardBadgesPortal containerRef={containerRef}>
<SloCardItemBadges
slo={slo}
rules={rules}
activeAlerts={activeAlerts}
handleCreateRule={handleCreateRule}
hasGroupBy={Boolean(slo.groupBy && slo.groupBy !== ALL_VALUE)}
/>
</SloCardBadgesPortal>
<BurnRateRuleFlyout
slo={slo}

View file

@ -25,25 +25,15 @@ interface Props {
handleCreateRule: () => void;
}
const Container = styled.div<{ hasGroupBy: boolean }>`
position: absolute;
const Container = styled.div`
display: inline-block;
top: ${({ hasGroupBy }) => (hasGroupBy ? '55px' : '35px')};
left: 7px;
z-index: 1;
border-radius: ${({ theme }) => theme.eui.euiBorderRadius};
margin-top: 5px;
`;
export function SloCardItemBadges({
slo,
activeAlerts,
rules,
handleCreateRule,
hasGroupBy,
}: Props) {
export function SloCardItemBadges({ slo, activeAlerts, rules, handleCreateRule }: Props) {
return (
<Container hasGroupBy={hasGroupBy}>
<EuiFlexGroup direction="row" responsive={false} gutterSize="s" alignItems="center" wrap>
<Container>
<EuiFlexGroup direction="row" responsive={false} gutterSize="xs" alignItems="center" wrap>
{!slo.summary ? (
<LoadingBadges />
) : (

View file

@ -6,7 +6,13 @@
*/
import React from 'react';
import { EuiFlexGrid, EuiFlexItem, EuiPanel, EuiSkeletonText } from '@elastic/eui';
import {
EuiFlexGrid,
EuiFlexItem,
EuiPanel,
EuiSkeletonText,
useIsWithinBreakpoints,
} from '@elastic/eui';
import { SLOWithSummaryResponse, ALL_VALUE } from '@kbn/slo-schema';
import { EuiFlexGridProps } from '@elastic/eui/src/components/flex/flex_grid';
import { ActiveAlerts } from '../../../../hooks/slo/use_fetch_active_alerts';
@ -23,6 +29,25 @@ export interface Props {
rulesBySlo?: UseFetchRulesForSloResponse['data'];
}
const useColumns = (cardsPerRow: string | undefined) => {
const isMobile = useIsWithinBreakpoints(['xs', 's']);
const isMedium = useIsWithinBreakpoints(['m']);
const isLarge = useIsWithinBreakpoints(['l']);
const columns = (Number(cardsPerRow) as EuiFlexGridProps['columns']) ?? 3;
switch (true) {
case isMobile:
return 1;
case isMedium:
return columns > 2 ? 2 : columns;
case isLarge:
return columns > 3 ? 3 : columns;
default:
return columns;
}
};
export function SloListCardView({
sloList,
loading,
@ -36,12 +61,14 @@ export function SloListCardView({
list: sloList.map((slo) => ({ sloId: slo.id, instanceId: slo.instanceId ?? ALL_VALUE })),
});
const columns = useColumns(cardsPerRow);
if (loading && sloList.length === 0) {
return <LoadingSloGrid gridSize={Number(cardsPerRow)} />;
}
return (
<EuiFlexGrid columns={Number(cardsPerRow) as EuiFlexGridProps['columns']}>
<EuiFlexGrid columns={columns}>
{sloList.map((slo) => (
<EuiFlexItem key={`${slo.id}-${slo.instanceId ?? 'ALL_VALUE'}`}>
<SloCardItem