import {Fragment} from 'react';
import isPropValid from '@emotion/is-prop-valid';
import styled from '@emotion/styled';
import {LocationDescriptor} from 'history';
import {TagSegment} from 'sentry/actionCreators/events';
import Link from 'sentry/components/links/link';
import Tooltip from 'sentry/components/tooltip';
import Version from 'sentry/components/version';
import {t} from 'sentry/locale';
import space from 'sentry/styles/space';
import {percent} from 'sentry/utils';
type Props = {
segments: TagSegment[];
title: string;
totalValues: number;
hasError?: boolean;
isLoading?: boolean;
onTagClick?: (title: string, value: TagSegment) => void;
renderEmpty?: () => React.ReactNode;
renderError?: () => React.ReactNode;
renderLoading?: () => React.ReactNode;
showReleasePackage?: boolean;
};
type SegmentValue = {
index: number;
onClick: () => void;
to: LocationDescriptor;
};
function TagDistributionMeter({
isLoading = false,
hasError = false,
renderLoading = () => null,
renderEmpty = () =>
{t('No recent data.')}
,
renderError = () => null,
showReleasePackage = false,
segments,
title,
totalValues,
onTagClick,
}: Props) {
function renderTitle() {
if (!Array.isArray(segments) || segments.length <= 0) {
return (
{title}
);
}
const largestSegment = segments[0];
const pct = percent(largestSegment.count, totalValues);
const pctLabel = Math.floor(pct);
const renderLabel = () => {
switch (title) {
case 'release':
return (
);
default:
return ;
}
};
return (
{title}
{renderLabel()}
{isLoading || hasError ? null : {pctLabel}%}
);
}
function renderSegments() {
if (isLoading) {
return renderLoading();
}
if (hasError) {
return {renderError()};
}
if (totalValues === 0) {
return {renderEmpty()};
}
return (
{segments.map((value, index) => {
const pct = percent(value.count, totalValues);
const pctLabel = Math.floor(pct);
const renderTooltipValue = () => {
switch (title) {
case 'release':
return (
);
default:
return value.name || t('n/a');
}
};
const tooltipHtml = (
{renderTooltipValue()}
{pctLabel}%
);
const segmentProps: SegmentValue = {
index,
to: value.url,
onClick: () => onTagClick?.(title, value),
};
return (
{value.isOther ? (
) : (
)}
);
})}
);
}
const totalVisible = segments.reduce((sum, value) => sum + value.count, 0);
const hasOther = totalVisible < totalValues;
if (hasOther) {
segments.push({
isOther: true,
name: t('Other'),
value: 'other',
count: totalValues - totalVisible,
url: '',
});
}
return (
{renderTitle()}
{renderSegments()}
);
}
export default TagDistributionMeter;
const COLORS = [
'#3A3387',
'#5F40A3',
'#8C4FBD',
'#B961D3',
'#DE76E4',
'#EF91E8',
'#F7B2EC',
'#FCD8F4',
'#FEEBF9',
];
const TagSummary = styled('div')`
margin-bottom: ${space(1)};
`;
const SegmentBar = styled('div')`
display: flex;
overflow: hidden;
border-radius: ${p => p.theme.borderRadius};
`;
const Title = styled('div')`
display: flex;
font-size: ${p => p.theme.fontSizeSmall};
justify-content: space-between;
margin-bottom: ${space(0.25)};
line-height: 1.1;
`;
const TitleType = styled('div')`
color: ${p => p.theme.textColor};
font-weight: bold;
${p => p.theme.overflowEllipsis};
`;
const TitleDescription = styled('div')`
display: flex;
color: ${p => p.theme.gray300};
text-align: right;
`;
const Label = styled('div')`
${p => p.theme.overflowEllipsis};
max-width: 150px;
`;
const Percent = styled('div')`
font-weight: bold;
font-variant-numeric: tabular-nums;
padding-left: ${space(0.5)};
color: ${p => p.theme.textColor};
`;
const OtherSegment = styled('span')`
display: block;
width: 100%;
height: 16px;
color: inherit;
outline: none;
background-color: ${COLORS[COLORS.length - 1]};
`;
const Segment = styled(Link, {shouldForwardProp: isPropValid})`
display: block;
width: 100%;
height: 16px;
color: inherit;
outline: none;
background-color: ${p => COLORS[p.index]};
border-radius: 0;
`;