diff --git a/datahub-web-react/src/app/entity/chart/shared/ChartStatsSummary.tsx b/datahub-web-react/src/app/entity/chart/shared/ChartStatsSummary.tsx
index 29b58ba756..566a9f9db5 100644
--- a/datahub-web-react/src/app/entity/chart/shared/ChartStatsSummary.tsx
+++ b/datahub-web-react/src/app/entity/chart/shared/ChartStatsSummary.tsx
@@ -6,6 +6,8 @@ import { formatNumberWithoutAbbreviation } from '../../../shared/formatNumber';
import { ANTD_GRAY } from '../../shared/constants';
import { toLocalDateTimeString, toRelativeTimeString } from '../../../shared/time/timeUtils';
import { StatsSummary } from '../../shared/components/styled/StatsSummary';
+import { countFormatter, needsFormatting } from '../../../../utils/formatter';
+import ExpandingStat from '../../dataset/shared/ExpandingStat';
const StatText = styled.span`
color: ${ANTD_GRAY[8]};
@@ -33,9 +35,15 @@ export const ChartStatsSummary = ({
}: Props) => {
const statsViews = [
(!!chartCount && (
-
- {chartCount} charts
-
+ (
+
+ {isExpanded ? formatNumberWithoutAbbreviation(chartCount) : countFormatter(chartCount)}{' '}
+ charts
+
+ )}
+ />
)) ||
undefined,
(!!viewCount && (
diff --git a/datahub-web-react/src/app/entity/dashboard/shared/DashboardStatsSummary.tsx b/datahub-web-react/src/app/entity/dashboard/shared/DashboardStatsSummary.tsx
index 510c94efde..e8fb4c16ac 100644
--- a/datahub-web-react/src/app/entity/dashboard/shared/DashboardStatsSummary.tsx
+++ b/datahub-web-react/src/app/entity/dashboard/shared/DashboardStatsSummary.tsx
@@ -6,6 +6,8 @@ import { formatNumberWithoutAbbreviation } from '../../../shared/formatNumber';
import { ANTD_GRAY } from '../../shared/constants';
import { toLocalDateTimeString, toRelativeTimeString } from '../../../shared/time/timeUtils';
import { StatsSummary } from '../../shared/components/styled/StatsSummary';
+import { countFormatter, needsFormatting } from '../../../../utils/formatter';
+import ExpandingStat from '../../dataset/shared/ExpandingStat';
const StatText = styled.span`
color: ${ANTD_GRAY[8]};
@@ -33,9 +35,15 @@ export const DashboardStatsSummary = ({
}: Props) => {
const statsViews = [
(!!chartCount && (
-
- {chartCount} charts
-
+ (
+
+ {isExpanded ? formatNumberWithoutAbbreviation(chartCount) : countFormatter(chartCount)}{' '}
+ charts
+
+ )}
+ />
)) ||
undefined,
(!!viewCount && (
diff --git a/datahub-web-react/src/app/entity/dataset/shared/DatasetStatsSummary.tsx b/datahub-web-react/src/app/entity/dataset/shared/DatasetStatsSummary.tsx
index 0dcc06bc2a..14f550de25 100644
--- a/datahub-web-react/src/app/entity/dataset/shared/DatasetStatsSummary.tsx
+++ b/datahub-web-react/src/app/entity/dataset/shared/DatasetStatsSummary.tsx
@@ -7,6 +7,8 @@ import { ANTD_GRAY } from '../../shared/constants';
import { toLocalDateTimeString, toRelativeTimeString } from '../../../shared/time/timeUtils';
import { StatsSummary } from '../../shared/components/styled/StatsSummary';
import { FormattedBytesStat } from './FormattedBytesStat';
+import { countFormatter, needsFormatting } from '../../../../utils/formatter';
+import ExpandingStat from './ExpandingStat';
const StatText = styled.span<{ color: string }>`
color: ${(props) => props.color};
@@ -25,6 +27,7 @@ type Props = {
uniqueUserCountLast30Days?: number | null;
lastUpdatedMs?: number | null;
color?: string;
+ mode?: 'normal' | 'tooltip-content';
};
export const DatasetStatsSummary = ({
@@ -36,20 +39,33 @@ export const DatasetStatsSummary = ({
uniqueUserCountLast30Days,
lastUpdatedMs,
color,
+ mode = 'normal',
}: Props) => {
- const displayedColor = color !== undefined ? color : ANTD_GRAY[7];
+ const isTooltipMode = mode === 'tooltip-content';
+ const displayedColor = isTooltipMode ? '' : color ?? ANTD_GRAY[7];
const statsViews = [
!!rowCount && (
-
-
- {formatNumberWithoutAbbreviation(rowCount)} rows
- {!!columnCount && (
- <>
- , {formatNumberWithoutAbbreviation(columnCount)} columns
- >
+ (
+
+
+ {isExpanded ? formatNumberWithoutAbbreviation(rowCount) : countFormatter(rowCount)} rows
+ {!!columnCount && (
+ <>
+ ,{' '}
+
+ {isExpanded
+ ? formatNumberWithoutAbbreviation(columnCount)
+ : countFormatter(columnCount)}
+ {' '}
+ columns
+ >
+ )}
+
)}
-
+ />
),
!!sizeInBytes && (
diff --git a/datahub-web-react/src/app/entity/dataset/shared/ExpandingStat.tsx b/datahub-web-react/src/app/entity/dataset/shared/ExpandingStat.tsx
new file mode 100644
index 0000000000..8101a696bf
--- /dev/null
+++ b/datahub-web-react/src/app/entity/dataset/shared/ExpandingStat.tsx
@@ -0,0 +1,48 @@
+import React, { ReactNode, useEffect, useRef, useState } from 'react';
+import styled from 'styled-components';
+
+const ExpandingStatContainer = styled.span<{ disabled: boolean; expanded: boolean; width: string }>`
+ overflow: hidden;
+ white-space: nowrap;
+ width: ${(props) => props.width};
+ transition: width 250ms ease;
+`;
+
+const ExpandingStat = ({
+ disabled = false,
+ render,
+}: {
+ disabled?: boolean;
+ render: (isExpanded: boolean) => ReactNode;
+}) => {
+ const contentRef = useRef(null);
+ const [width, setWidth] = useState('inherit');
+ const [isExpanded, setIsExpanded] = useState(false);
+
+ useEffect(() => {
+ if (!contentRef.current) return;
+ setWidth(`${contentRef.current.offsetWidth}px`);
+ }, [isExpanded]);
+
+ const onMouseEnter = () => {
+ if (!disabled) setIsExpanded(true);
+ };
+
+ const onMouseLeave = () => {
+ if (!disabled) setIsExpanded(false);
+ };
+
+ return (
+
+ {render(isExpanded)}
+
+ );
+};
+
+export default ExpandingStat;
diff --git a/datahub-web-react/src/app/entity/shared/components/styled/StatsSummary.tsx b/datahub-web-react/src/app/entity/shared/components/styled/StatsSummary.tsx
index 8146fa62bc..a0fe5ef031 100644
--- a/datahub-web-react/src/app/entity/shared/components/styled/StatsSummary.tsx
+++ b/datahub-web-react/src/app/entity/shared/components/styled/StatsSummary.tsx
@@ -8,15 +8,15 @@ type Props = {
const StatsContainer = styled.div`
margin-top: 8px;
+ display: flex;
+ align-items: center;
`;
const StatDivider = styled.div`
- display: inline-block;
padding-left: 10px;
margin-right: 10px;
border-right: 1px solid ${ANTD_GRAY[4]};
height: 21px;
- vertical-align: text-top;
`;
export const StatsSummary = ({ stats }: Props) => {
@@ -25,10 +25,10 @@ export const StatsSummary = ({ stats }: Props) => {
{stats && stats.length > 0 && (
{stats.map((statView, index) => (
-
+ <>
{statView}
{index < stats.length - 1 && }
-
+ >
))}
)}
diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Dataset/StatsSidebarSection.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Dataset/StatsSidebarSection.tsx
index a1c60fe00e..dfde26412a 100644
--- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Dataset/StatsSidebarSection.tsx
+++ b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Dataset/StatsSidebarSection.tsx
@@ -8,7 +8,7 @@ import { ANTD_GRAY } from '../../../../constants';
import { useBaseEntity, useRouteToTab } from '../../../../EntityContext';
import { SidebarHeader } from '../SidebarHeader';
import { InfoItem } from '../../../../components/styled/InfoItem';
-import { countSeparator } from '../../../../../../../utils/formatter/index';
+import { formatNumberWithoutAbbreviation } from '../../../../../../shared/formatNumber';
const HeaderInfoBody = styled(Typography.Text)`
font-size: 16px;
@@ -83,7 +83,7 @@ export const SidebarStatsSection = () => {
onClick={() => routeToTab({ tabName: 'Queries' })}
width={INFO_ITEM_WIDTH_PX}
>
- {countSeparator(latestProfile?.rowCount)}
+ {formatNumberWithoutAbbreviation(latestProfile?.rowCount)}
) : null}
{latestProfile?.columnCount ? (
diff --git a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Stats/snapshot/TableStats.tsx b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Stats/snapshot/TableStats.tsx
index 62e5c7a627..eb39b9f420 100644
--- a/datahub-web-react/src/app/entity/shared/tabs/Dataset/Stats/snapshot/TableStats.tsx
+++ b/datahub-web-react/src/app/entity/shared/tabs/Dataset/Stats/snapshot/TableStats.tsx
@@ -4,8 +4,9 @@ import styled from 'styled-components';
import { CorpUser, Maybe, UserUsageCounts } from '../../../../../../../types.generated';
import { InfoItem } from '../../../../components/styled/InfoItem';
import { ANTD_GRAY } from '../../../../constants';
-import { countFormatter, countSeparator } from '../../../../../../../utils/formatter/index';
+import { countFormatter } from '../../../../../../../utils/formatter/index';
import { ExpandedActorGroup } from '../../../../components/styled/ExpandedActorGroup';
+import { formatNumberWithoutAbbreviation } from '../../../../../../shared/formatNumber';
type Props = {
rowCount?: number;
@@ -57,7 +58,7 @@ export default function TableStats({
{rowCount && (
-
+
{countFormatter(rowCount)}
diff --git a/datahub-web-react/src/app/search/autoComplete/AutoCompleteItem.tsx b/datahub-web-react/src/app/search/autoComplete/AutoCompleteItem.tsx
index 29cc549df0..c97d171b4c 100644
--- a/datahub-web-react/src/app/search/autoComplete/AutoCompleteItem.tsx
+++ b/datahub-web-react/src/app/search/autoComplete/AutoCompleteItem.tsx
@@ -39,7 +39,7 @@ export default function AutoCompleteItem({ query, entity }: Props) {
return (
}
placement="top"
diff --git a/datahub-web-react/src/app/search/autoComplete/AutoCompleteTooltipContent.tsx b/datahub-web-react/src/app/search/autoComplete/AutoCompleteTooltipContent.tsx
index 7a0e104cf1..dfe32c7805 100644
--- a/datahub-web-react/src/app/search/autoComplete/AutoCompleteTooltipContent.tsx
+++ b/datahub-web-react/src/app/search/autoComplete/AutoCompleteTooltipContent.tsx
@@ -53,7 +53,7 @@ export default function AutoCompleteTooltipContent({ entity }: Props) {
}
queryCountLast30Days={(entity as Dataset).statsSummary?.queryCountLast30Days}
uniqueUserCountLast30Days={(entity as Dataset).statsSummary?.uniqueUserCountLast30Days}
- color="" // need to pass in empty color so that tooltip decides the color here
+ mode="tooltip-content"
/>
)}
diff --git a/datahub-web-react/src/utils/formatter/index.ts b/datahub-web-react/src/utils/formatter/index.ts
index 270293960f..85919611e2 100644
--- a/datahub-web-react/src/utils/formatter/index.ts
+++ b/datahub-web-react/src/utils/formatter/index.ts
@@ -1,20 +1,31 @@
-const intlFormat = (num) => {
- return new Intl.NumberFormat().format(Math.round(num * 10) / 10);
-};
+type NumMapType = Record<'billion' | 'million' | 'thousand', { value: number; symbol: string }>;
-export const countFormatter: (num: number) => string = (num: number) => {
- if (num >= 1000000000) {
- return `${intlFormat(num / 1000000000)}B`;
- }
- if (num >= 1000000) {
- return `${intlFormat(num / 1000000)}M`;
- }
+const NumMap: NumMapType = {
+ billion: {
+ value: 1000000000,
+ symbol: 'B',
+ },
+ million: {
+ value: 1000000,
+ symbol: 'M',
+ },
+ thousand: {
+ value: 1000,
+ symbol: 'K',
+ },
+} as const;
- if (num >= 1000) return `${intlFormat(num / 1000)}K`;
+const isBillions = (num: number) => num >= NumMap.billion.value;
+const isMillions = (num: number) => num >= NumMap.million.value;
+const isThousands = (num: number) => num >= NumMap.thousand.value;
+const intlFormat = (num: number) => new Intl.NumberFormat().format(Math.round(num * 10) / 10);
+
+export const needsFormatting = (num: number) => isThousands(num);
+
+export const countFormatter = (num: number) => {
+ if (isBillions(num)) return `${intlFormat(num / NumMap.billion.value)}${NumMap.billion.symbol}`;
+ if (isMillions(num)) return `${intlFormat(num / NumMap.million.value)}${NumMap.million.symbol}`;
+ if (isThousands(num)) return `${intlFormat(num / NumMap.thousand.value)}${NumMap.thousand.symbol}`;
return intlFormat(num);
};
-
-export const countSeparator = (num) => {
- return num.toLocaleString();
-};