mirror of
https://github.com/apache/superset.git
synced 2024-09-18 19:49:37 -04:00
feat(dashboard): Chart title click redirects to Explore (#20111)
This commit is contained in:
parent
d7e3ac306f
commit
b746e6f844
@ -18,7 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
import React, { useEffect, useState, useRef } from 'react';
|
import React, { useEffect, useState, useRef } from 'react';
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
import { styled, t } from '@superset-ui/core';
|
import { css, styled, t } from '@superset-ui/core';
|
||||||
import { Tooltip } from 'src/components/Tooltip';
|
import { Tooltip } from 'src/components/Tooltip';
|
||||||
import CertifiedBadge from '../CertifiedBadge';
|
import CertifiedBadge from '../CertifiedBadge';
|
||||||
|
|
||||||
@ -37,6 +37,7 @@ export interface EditableTitleProps {
|
|||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
certifiedBy?: string;
|
certifiedBy?: string;
|
||||||
certificationDetails?: string;
|
certificationDetails?: string;
|
||||||
|
onClickTitle?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StyledCertifiedBadge = styled(CertifiedBadge)`
|
const StyledCertifiedBadge = styled(CertifiedBadge)`
|
||||||
@ -57,6 +58,7 @@ export default function EditableTitle({
|
|||||||
placeholder = '',
|
placeholder = '',
|
||||||
certifiedBy,
|
certifiedBy,
|
||||||
certificationDetails,
|
certificationDetails,
|
||||||
|
onClickTitle,
|
||||||
// rest is related to title tooltip
|
// rest is related to title tooltip
|
||||||
...rest
|
...rest
|
||||||
}: EditableTitleProps) {
|
}: EditableTitleProps) {
|
||||||
@ -216,7 +218,23 @@ export default function EditableTitle({
|
|||||||
}
|
}
|
||||||
if (!canEdit) {
|
if (!canEdit) {
|
||||||
// don't actually want an input in this case
|
// don't actually want an input in this case
|
||||||
titleComponent = <span data-test="editable-title-input">{value}</span>;
|
titleComponent = onClickTitle ? (
|
||||||
|
<span
|
||||||
|
role="button"
|
||||||
|
onClick={onClickTitle}
|
||||||
|
tabIndex={0}
|
||||||
|
data-test="editable-title-input"
|
||||||
|
css={css`
|
||||||
|
:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
{value}
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<span data-test="editable-title-input">{value}</span>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
|
@ -100,7 +100,7 @@ jest.mock('src/dashboard/components/FiltersBadge', () => ({
|
|||||||
),
|
),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const createProps = () => ({
|
const createProps = (overrides: any = {}) => ({
|
||||||
filters: {}, // is in typing but not being used
|
filters: {}, // is in typing but not being used
|
||||||
editMode: false,
|
editMode: false,
|
||||||
annotationQuery: { param01: 'annotationQuery' } as any,
|
annotationQuery: { param01: 'annotationQuery' } as any,
|
||||||
@ -159,6 +159,7 @@ const createProps = () => ({
|
|||||||
formData: { slice_id: 1, datasource: '58__table' },
|
formData: { slice_id: 1, datasource: '58__table' },
|
||||||
width: 100,
|
width: 100,
|
||||||
height: 100,
|
height: 100,
|
||||||
|
...overrides,
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Should render', () => {
|
test('Should render', () => {
|
||||||
@ -264,6 +265,48 @@ test('Should render title', () => {
|
|||||||
expect(screen.getByText('Vaccine Candidates per Phase')).toBeInTheDocument();
|
expect(screen.getByText('Vaccine Candidates per Phase')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Should render click to edit prompt and run onExploreChart on click', async () => {
|
||||||
|
const props = createProps();
|
||||||
|
render(<SliceHeader {...props} />, { useRedux: true });
|
||||||
|
userEvent.hover(screen.getByText('Vaccine Candidates per Phase'));
|
||||||
|
expect(
|
||||||
|
await screen.findByText(
|
||||||
|
'Click to edit Vaccine Candidates per Phase in a new tab',
|
||||||
|
),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
|
||||||
|
userEvent.click(screen.getByText('Vaccine Candidates per Phase'));
|
||||||
|
expect(props.onExploreChart).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should not render click to edit prompt and run onExploreChart on click if supersetCanExplore=false', () => {
|
||||||
|
const props = createProps({ supersetCanExplore: false });
|
||||||
|
render(<SliceHeader {...props} />, { useRedux: true });
|
||||||
|
userEvent.hover(screen.getByText('Vaccine Candidates per Phase'));
|
||||||
|
expect(
|
||||||
|
screen.queryByText(
|
||||||
|
'Click to edit Vaccine Candidates per Phase in a new tab',
|
||||||
|
),
|
||||||
|
).not.toBeInTheDocument();
|
||||||
|
|
||||||
|
userEvent.click(screen.getByText('Vaccine Candidates per Phase'));
|
||||||
|
expect(props.onExploreChart).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should not render click to edit prompt and run onExploreChart on click if in edit mode', () => {
|
||||||
|
const props = createProps({ editMode: true });
|
||||||
|
render(<SliceHeader {...props} />, { useRedux: true });
|
||||||
|
userEvent.hover(screen.getByText('Vaccine Candidates per Phase'));
|
||||||
|
expect(
|
||||||
|
screen.queryByText(
|
||||||
|
'Click to edit Vaccine Candidates per Phase in a new tab',
|
||||||
|
),
|
||||||
|
).not.toBeInTheDocument();
|
||||||
|
|
||||||
|
userEvent.click(screen.getByText('Vaccine Candidates per Phase'));
|
||||||
|
expect(props.onExploreChart).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
test('Should render "annotationsLoading"', () => {
|
test('Should render "annotationsLoading"', () => {
|
||||||
const props = createProps();
|
const props = createProps();
|
||||||
render(<SliceHeader {...props} />, { useRedux: true });
|
render(<SliceHeader {...props} />, { useRedux: true });
|
||||||
|
@ -104,9 +104,18 @@ const SliceHeader: FC<SliceHeaderProps> = ({
|
|||||||
[crossFilterValue],
|
[crossFilterValue],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleClickTitle =
|
||||||
|
!editMode && supersetCanExplore ? onExploreChart : undefined;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const headerElement = headerRef.current;
|
const headerElement = headerRef.current;
|
||||||
if (
|
if (handleClickTitle) {
|
||||||
|
setHeaderTooltip(
|
||||||
|
sliceName
|
||||||
|
? t('Click to edit %s in a new tab', sliceName)
|
||||||
|
: t('Click to edit chart in a new tab'),
|
||||||
|
);
|
||||||
|
} else if (
|
||||||
headerElement &&
|
headerElement &&
|
||||||
(headerElement.scrollWidth > headerElement.offsetWidth ||
|
(headerElement.scrollWidth > headerElement.offsetWidth ||
|
||||||
headerElement.scrollHeight > headerElement.offsetHeight)
|
headerElement.scrollHeight > headerElement.offsetHeight)
|
||||||
@ -115,7 +124,7 @@ const SliceHeader: FC<SliceHeaderProps> = ({
|
|||||||
} else {
|
} else {
|
||||||
setHeaderTooltip(null);
|
setHeaderTooltip(null);
|
||||||
}
|
}
|
||||||
}, [sliceName, width, height]);
|
}, [sliceName, width, height, handleClickTitle]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="chart-header" data-test="slice-header" ref={innerRef}>
|
<div className="chart-header" data-test="slice-header" ref={innerRef}>
|
||||||
@ -132,6 +141,7 @@ const SliceHeader: FC<SliceHeaderProps> = ({
|
|||||||
emptyText=""
|
emptyText=""
|
||||||
onSaveTitle={updateSliceName}
|
onSaveTitle={updateSliceName}
|
||||||
showTooltip={false}
|
showTooltip={false}
|
||||||
|
onClickTitle={handleClickTitle}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
{!!Object.values(annotationQuery).length && (
|
{!!Object.values(annotationQuery).length && (
|
||||||
|
Loading…
Reference in New Issue
Block a user