Skip to content

Commit

Permalink
feat: smart tooltip in datasourcepanel (#18080)
Browse files Browse the repository at this point in the history
  • Loading branch information
zhaoyongjie authored Feb 7, 2022
1 parent 299635c commit aa21a96
Show file tree
Hide file tree
Showing 9 changed files with 318 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,18 @@
* specific language governing permissions and limitations
* under the License.
*/
import React from 'react';
import React, { useEffect, useState, ReactNode } from 'react';
import { styled } from '@superset-ui/core';
import { Tooltip } from './Tooltip';
import { ColumnTypeLabel } from './ColumnTypeLabel';
import InfoTooltipWithTrigger from './InfoTooltipWithTrigger';
import CertifiedIconWithTooltip from './CertifiedIconWithTooltip';
import { ColumnMeta } from '../types';
import { getColumnLabelText, getColumnTooltipNode } from './labelUtils';

export type ColumnOptionProps = {
column: ColumnMeta;
showType?: boolean;
showTooltip?: boolean;
labelRef?: React.RefObject<any>;
};

Expand All @@ -41,11 +41,15 @@ export function ColumnOption({
column,
labelRef,
showType = false,
showTooltip = true,
}: ColumnOptionProps) {
const { expression, column_name, type_generic } = column;
const hasExpression = expression && expression !== column_name;
const type = hasExpression ? 'expression' : type_generic;
const [tooltipText, setTooltipText] = useState<ReactNode>(column.column_name);

useEffect(() => {
setTooltipText(getColumnTooltipNode(column, labelRef));
}, [labelRef, column]);

return (
<StyleOverrides>
Expand All @@ -57,25 +61,17 @@ export function ColumnOption({
details={column.certification_details}
/>
)}
{showTooltip ? (
<Tooltip
id="metric-name-tooltip"
title={column.verbose_name || column.column_name}
trigger={['hover']}
placement="top"
>
<span
className="m-r-5 option-label column-option-label"
ref={labelRef}
>
{column.verbose_name || column.column_name}
</span>
</Tooltip>
) : (
<Tooltip
id="metric-name-tooltip"
title={tooltipText}
trigger={['hover']}
placement="top"
>
<span className="m-r-5 option-label column-option-label" ref={labelRef}>
{column.verbose_name || column.column_name}
{getColumnLabelText(column)}
</span>
)}
</Tooltip>

{column.description && (
<InfoTooltipWithTrigger
className="m-r-5 text-muted"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@
* specific language governing permissions and limitations
* under the License.
*/
import React from 'react';
import React, { useEffect, useState, ReactNode } from 'react';
import { styled, Metric, SafeMarkdown } from '@superset-ui/core';
import InfoTooltipWithTrigger from './InfoTooltipWithTrigger';
import { ColumnTypeLabel } from './ColumnTypeLabel';
import CertifiedIconWithTooltip from './CertifiedIconWithTooltip';
import Tooltip from './Tooltip';
import { getMetricTooltipNode } from './labelUtils';

const FlexRowContainer = styled.div`
align-items: center;
Expand All @@ -37,7 +38,6 @@ export interface MetricOptionProps {
openInNewWindow?: boolean;
showFormula?: boolean;
showType?: boolean;
showTooltip?: boolean;
url?: string;
labelRef?: React.RefObject<any>;
}
Expand All @@ -48,7 +48,6 @@ export function MetricOption({
openInNewWindow = false,
showFormula = true,
showType = false,
showTooltip = true,
url = '',
}: MetricOptionProps) {
const verbose = metric.verbose_name || metric.metric_name || metric.label;
Expand All @@ -62,6 +61,12 @@ export function MetricOption({

const warningMarkdown = metric.warning_markdown || metric.warning_text;

const [tooltipText, setTooltipText] = useState<ReactNode>(metric.metric_name);

useEffect(() => {
setTooltipText(getMetricTooltipNode(metric, labelRef));
}, [labelRef, metric]);

return (
<FlexRowContainer className="metric-option">
{showType && <ColumnTypeLabel type="expression" />}
Expand All @@ -72,22 +77,16 @@ export function MetricOption({
details={metric.certification_details}
/>
)}
{showTooltip ? (
<Tooltip
id="metric-name-tooltip"
title={verbose}
trigger={['hover']}
placement="top"
>
<span className="option-label metric-option-label" ref={labelRef}>
{link}
</span>
</Tooltip>
) : (
<Tooltip
id="metric-name-tooltip"
title={tooltipText}
trigger={['hover']}
placement="top"
>
<span className="option-label metric-option-label" ref={labelRef}>
{link}
</span>
)}
</Tooltip>
{metric.description && (
<InfoTooltipWithTrigger
className="text-muted"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import React, { ReactNode } from 'react';

import { t } from '@superset-ui/core';
import { ColumnMeta, Metric } from '@superset-ui/chart-controls';

export const isLabelTruncated = (labelRef?: React.RefObject<any>): boolean =>
!!(
labelRef &&
labelRef.current &&
labelRef.current.scrollWidth > labelRef.current.clientWidth
);

export const getColumnLabelText = (column: ColumnMeta): string =>
column.verbose_name || column.column_name;

export const getColumnTooltipNode = (
column: ColumnMeta,
labelRef?: React.RefObject<any>,
): ReactNode => {
// don't show tooltip if it hasn't verbose_name and hasn't truncated
if (!column.verbose_name && !isLabelTruncated(labelRef)) {
return null;
}

if (column.verbose_name) {
return (
<>
<div>{t('column name: %s', column.column_name)}</div>
<div>{t('verbose name: %s', column.verbose_name)}</div>
</>
);
}

// show column name in tooltip when column truncated
return t('column name: %s', column.column_name);
};

type MetricType = Omit<Metric, 'id'> & { label?: string };

export const getMetricTooltipNode = (
metric: MetricType,
labelRef?: React.RefObject<any>,
): ReactNode => {
// don't show tooltip if it hasn't verbose_name, label and hasn't truncated
if (!metric.verbose_name && !metric.label && !isLabelTruncated(labelRef)) {
return null;
}

if (metric.verbose_name) {
return (
<>
<div>{t('metric name: %s', metric.metric_name)}</div>
<div>{t('verbose name: %s', metric.verbose_name)}</div>
</>
);
}

if (isLabelTruncated(labelRef) && metric.label) {
return t('label name: %s', metric.label);
}

return t('metric name: %s', metric.metric_name);
};
Loading

0 comments on commit aa21a96

Please sign in to comment.