mirror of
https://github.com/apache/superset.git
synced 2024-09-06 22:07:34 -04:00
refactor: Fix anchor-is-valid lint warnings (#12010)
* Fix anchor-is-valid lint warnings * Change IconTooltip to use named exports
This commit is contained in:
parent
e2f676445b
commit
8682c6fc1c
@ -86,7 +86,7 @@ describe('ChangeDatasourceModal', () => {
|
||||
|
||||
it('renders confirmation message', async () => {
|
||||
act(() => {
|
||||
wrapper.find('.datasource-link').at(0).props().onClick();
|
||||
wrapper.find('[data-test="datasource-link"]').at(0).props().onClick();
|
||||
});
|
||||
await waitForComponentToPaint(wrapper);
|
||||
|
||||
@ -95,7 +95,7 @@ describe('ChangeDatasourceModal', () => {
|
||||
|
||||
it('changes the datasource', async () => {
|
||||
act(() => {
|
||||
wrapper.find('.datasource-link').at(0).props().onClick();
|
||||
wrapper.find('[data-test="datasource-link"]').at(0).props().onClick();
|
||||
});
|
||||
await waitForComponentToPaint(wrapper);
|
||||
|
||||
|
@ -18,22 +18,23 @@
|
||||
*/
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { Tooltip } from 'src/common/components/Tooltip';
|
||||
import { IconTooltip } from 'src/components/IconTooltip';
|
||||
|
||||
import Link from 'src/components/Link';
|
||||
|
||||
describe('Link', () => {
|
||||
describe('IconTooltip', () => {
|
||||
const mockedProps = {
|
||||
tooltip: 'This is a tooltip',
|
||||
href: 'https://www.airbnb.com',
|
||||
};
|
||||
it('renders', () => {
|
||||
expect(React.isValidElement(<Link>TEST</Link>)).toBe(true);
|
||||
expect(React.isValidElement(<IconTooltip>TEST</IconTooltip>)).toBe(true);
|
||||
});
|
||||
it('renders with props', () => {
|
||||
expect(React.isValidElement(<Link {...mockedProps}>TEST</Link>)).toBe(true);
|
||||
expect(
|
||||
React.isValidElement(<IconTooltip {...mockedProps}>TEST</IconTooltip>),
|
||||
).toBe(true);
|
||||
});
|
||||
it('renders an anchor tag', () => {
|
||||
const wrapper = shallow(<Link {...mockedProps}>TEST</Link>);
|
||||
expect(wrapper.find('a')).toExist();
|
||||
it('renders a tooltip', () => {
|
||||
const wrapper = shallow(<IconTooltip {...mockedProps}>TEST</IconTooltip>);
|
||||
expect(wrapper.find(Tooltip)).toExist();
|
||||
});
|
||||
});
|
@ -22,7 +22,7 @@ import { Provider } from 'react-redux';
|
||||
import configureStore from 'redux-mock-store';
|
||||
import { supersetTheme, ThemeProvider } from '@superset-ui/core';
|
||||
|
||||
import Link from 'src/components/Link';
|
||||
import { IconTooltip } from 'src/components/IconTooltip';
|
||||
import Fade from 'src/common/components/Fade';
|
||||
import TableElement from 'src/SqlLab/components/TableElement';
|
||||
import ColumnElement from 'src/SqlLab/components/ColumnElement';
|
||||
@ -43,9 +43,9 @@ describe('TableElement', () => {
|
||||
it('renders with props', () => {
|
||||
expect(React.isValidElement(<TableElement {...mockedProps} />)).toBe(true);
|
||||
});
|
||||
it('has 2 Link elements', () => {
|
||||
it('has 2 IconTooltip elements', () => {
|
||||
const wrapper = shallow(<TableElement {...mockedProps} />);
|
||||
expect(wrapper.find(Link)).toHaveLength(2);
|
||||
expect(wrapper.find(IconTooltip)).toHaveLength(2);
|
||||
});
|
||||
it('has 14 columns', () => {
|
||||
const wrapper = shallow(<TableElement {...mockedProps} />);
|
||||
@ -95,7 +95,7 @@ describe('TableElement', () => {
|
||||
},
|
||||
);
|
||||
expect(mockedActions.collapseTable.called).toBe(false);
|
||||
wrapper.find('.table-name').simulate('click');
|
||||
wrapper.find('[data-test="collapse"]').hostNodes().simulate('click');
|
||||
expect(mockedActions.collapseTable.called).toBe(true);
|
||||
});
|
||||
it('removes the table', () => {
|
||||
|
@ -27,7 +27,7 @@ import { t } from '@superset-ui/core';
|
||||
import TableView from 'src/components/TableView';
|
||||
import Button from 'src/components/Button';
|
||||
import { fDuration } from 'src/modules/dates';
|
||||
import Link from '../../components/Link';
|
||||
import { IconTooltip } from '../../components/IconTooltip';
|
||||
import ResultSet from './ResultSet';
|
||||
import ModalTrigger from '../../components/ModalTrigger';
|
||||
import HighlightedSql from './HighlightedSql';
|
||||
@ -175,9 +175,9 @@ const QueryTable = props => {
|
||||
let errorTooltip;
|
||||
if (q.errorMessage) {
|
||||
errorTooltip = (
|
||||
<Link tooltip={q.errorMessage}>
|
||||
<IconTooltip tooltip={q.errorMessage}>
|
||||
<i className="fa fa-exclamation-circle text-danger" />
|
||||
</Link>
|
||||
</IconTooltip>
|
||||
);
|
||||
}
|
||||
q.state = (
|
||||
@ -188,22 +188,22 @@ const QueryTable = props => {
|
||||
);
|
||||
q.actions = (
|
||||
<div>
|
||||
<Link
|
||||
className="fa fa-pencil m-r-3"
|
||||
<IconTooltip
|
||||
className="fa fa-pencil m-r-3 pointer"
|
||||
onClick={() => restoreSql(query)}
|
||||
tooltip={t(
|
||||
'Overwrite text in the editor with a query on this table',
|
||||
)}
|
||||
placement="top"
|
||||
/>
|
||||
<Link
|
||||
className="fa fa-plus-circle m-r-3"
|
||||
<IconTooltip
|
||||
className="fa fa-plus-circle m-r-3 pointer"
|
||||
onClick={() => openQueryInNewTab(query)}
|
||||
tooltip={t('Run query in a new tab')}
|
||||
placement="top"
|
||||
/>
|
||||
<Link
|
||||
className="fa fa-trash m-r-3"
|
||||
<IconTooltip
|
||||
className="fa fa-trash m-r-3 pointer"
|
||||
tooltip={t('Remove query from log')}
|
||||
onClick={() => removeQuery(query)}
|
||||
/>
|
||||
|
@ -21,7 +21,7 @@ import SyntaxHighlighter from 'react-syntax-highlighter/dist/cjs/light';
|
||||
import sql from 'react-syntax-highlighter/dist/cjs/languages/hljs/sql';
|
||||
import github from 'react-syntax-highlighter/dist/cjs/styles/hljs/github';
|
||||
|
||||
import Link from '../../components/Link';
|
||||
import { IconTooltip } from '../../components/IconTooltip';
|
||||
import ModalTrigger from '../../components/ModalTrigger';
|
||||
|
||||
SyntaxHighlighter.registerLanguage('sql', sql);
|
||||
@ -41,10 +41,9 @@ export default function ShowSQL({
|
||||
<ModalTrigger
|
||||
modalTitle={title}
|
||||
triggerNode={
|
||||
<Link
|
||||
<IconTooltip
|
||||
className="fa fa-eye pull-left m-l-2"
|
||||
tooltip={tooltipText}
|
||||
href="#"
|
||||
/>
|
||||
}
|
||||
modalBody={
|
||||
|
@ -20,12 +20,12 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { ButtonGroup, Collapse, Well } from 'react-bootstrap';
|
||||
import shortid from 'shortid';
|
||||
import { t } from '@superset-ui/core';
|
||||
import { t, styled } from '@superset-ui/core';
|
||||
|
||||
import Fade from 'src/common/components/Fade';
|
||||
import { Tooltip } from 'src/common/components/Tooltip';
|
||||
import CopyToClipboard from '../../components/CopyToClipboard';
|
||||
import Link from '../../components/Link';
|
||||
import { IconTooltip } from '../../components/IconTooltip';
|
||||
import ColumnElement from './ColumnElement';
|
||||
import ShowSQL from './ShowSQL';
|
||||
import ModalTrigger from '../../components/ModalTrigger';
|
||||
@ -43,6 +43,14 @@ const defaultProps = {
|
||||
timeout: 500,
|
||||
};
|
||||
|
||||
const StyledSpan = styled.span`
|
||||
color: ${({ theme }) => theme.colors.primary.dark1};
|
||||
&: hover {
|
||||
color: ${({ theme }) => theme.colors.primary.dark2};
|
||||
}
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
||||
class TableElement extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@ -145,7 +153,7 @@ class TableElement extends React.PureComponent {
|
||||
<pre key={i}>{JSON.stringify(ix, null, ' ')}</pre>
|
||||
))}
|
||||
triggerNode={
|
||||
<Link
|
||||
<IconTooltip
|
||||
className="fa fa-key pull-left m-l-2"
|
||||
tooltip={t('View keys & indexes (%s)', table.indexes.length)}
|
||||
/>
|
||||
@ -156,10 +164,10 @@ class TableElement extends React.PureComponent {
|
||||
return (
|
||||
<ButtonGroup className="ws-el-controls">
|
||||
{keyLink}
|
||||
<Link
|
||||
<IconTooltip
|
||||
className={
|
||||
`fa fa-sort-${!this.state.sortColumns ? 'alpha' : 'numeric'}-asc ` +
|
||||
'pull-left sort-cols m-l-2'
|
||||
'pull-left sort-cols m-l-2 pointer'
|
||||
}
|
||||
onClick={this.toggleSortColumns}
|
||||
tooltip={
|
||||
@ -167,14 +175,13 @@ class TableElement extends React.PureComponent {
|
||||
? t('Sort columns alphabetically')
|
||||
: t('Original table column order')
|
||||
}
|
||||
href="#"
|
||||
/>
|
||||
{table.selectStar && (
|
||||
<CopyToClipboard
|
||||
copyNode={
|
||||
<a aria-label="Copy">
|
||||
<IconTooltip aria-label="Copy">
|
||||
<i aria-hidden className="fa fa-clipboard pull-left m-l-2" />
|
||||
</a>
|
||||
</IconTooltip>
|
||||
}
|
||||
text={table.selectStar}
|
||||
shouldShowText={false}
|
||||
@ -188,11 +195,10 @@ class TableElement extends React.PureComponent {
|
||||
title={t('CREATE VIEW statement')}
|
||||
/>
|
||||
)}
|
||||
<Link
|
||||
className="fa fa-times table-remove pull-left m-l-2"
|
||||
<IconTooltip
|
||||
className="fa fa-times table-remove pull-left m-l-2 pointer"
|
||||
onClick={this.removeTable}
|
||||
tooltip={t('Remove table preview')}
|
||||
href="#"
|
||||
/>
|
||||
</ButtonGroup>
|
||||
);
|
||||
@ -209,15 +215,15 @@ class TableElement extends React.PureComponent {
|
||||
title={table.name}
|
||||
trigger={['hover']}
|
||||
>
|
||||
<a
|
||||
href="#"
|
||||
<StyledSpan
|
||||
data-test="collapse"
|
||||
className="table-name"
|
||||
onClick={e => {
|
||||
this.toggleTable(e);
|
||||
}}
|
||||
>
|
||||
<strong>{table.name}</strong>
|
||||
</a>
|
||||
</StyledSpan>
|
||||
</Tooltip>
|
||||
|
||||
<div className="pull-right header-right-side">
|
||||
|
@ -114,9 +114,14 @@ export default function ErrorAlert({
|
||||
<strong>{title}</strong>
|
||||
</LeftSideContent>
|
||||
{!isExpandable && (
|
||||
<a href="#" className="link" onClick={() => setIsModalOpen(true)}>
|
||||
<span
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
className="link"
|
||||
onClick={() => setIsModalOpen(true)}
|
||||
>
|
||||
{t('See More')}
|
||||
</a>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{isExpandable ? (
|
||||
@ -125,25 +130,27 @@ export default function ErrorAlert({
|
||||
{body && (
|
||||
<>
|
||||
{!isBodyExpanded && (
|
||||
<a
|
||||
href="#"
|
||||
<span
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
className="link"
|
||||
onClick={() => setIsBodyExpanded(true)}
|
||||
>
|
||||
{t('See More')}
|
||||
</a>
|
||||
</span>
|
||||
)}
|
||||
{isBodyExpanded && (
|
||||
<>
|
||||
<br />
|
||||
{body}
|
||||
<a
|
||||
href="#"
|
||||
<span
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
className="link"
|
||||
onClick={() => setIsBodyExpanded(false)}
|
||||
>
|
||||
{t('See Less')}
|
||||
</a>
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
|
@ -18,11 +18,11 @@
|
||||
*/
|
||||
import React, { ReactNode } from 'react';
|
||||
import { Tooltip } from 'src/common/components/Tooltip';
|
||||
import { styled } from '@superset-ui/core';
|
||||
|
||||
interface Props {
|
||||
children?: ReactNode;
|
||||
className?: string;
|
||||
href?: string;
|
||||
onClick?: () => void;
|
||||
placement?:
|
||||
| 'bottom'
|
||||
@ -41,24 +41,29 @@ interface Props {
|
||||
tooltip?: string | null;
|
||||
}
|
||||
|
||||
const Link = ({
|
||||
const StyledSpan = styled.span`
|
||||
color: ${({ theme }) => theme.colors.primary.dark1};
|
||||
&: hover {
|
||||
color: ${({ theme }) => theme.colors.primary.dark2};
|
||||
}
|
||||
`;
|
||||
|
||||
const IconTooltip = ({
|
||||
children = null,
|
||||
className = '',
|
||||
href = '#',
|
||||
onClick = () => undefined,
|
||||
placement = 'top',
|
||||
style = {},
|
||||
tooltip = null,
|
||||
}: Props) => {
|
||||
const link = (
|
||||
<a
|
||||
href={href}
|
||||
const iconTooltip = (
|
||||
<StyledSpan
|
||||
onClick={onClick}
|
||||
style={style}
|
||||
className={`Link ${className}`}
|
||||
className={`IconTooltip ${className}`}
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
</StyledSpan>
|
||||
);
|
||||
if (tooltip) {
|
||||
return (
|
||||
@ -69,11 +74,11 @@ const Link = ({
|
||||
mouseEnterDelay={0.3}
|
||||
mouseLeaveDelay={0.15}
|
||||
>
|
||||
{link}
|
||||
{iconTooltip}
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
return link;
|
||||
return iconTooltip;
|
||||
};
|
||||
|
||||
export default Link;
|
||||
export { IconTooltip };
|
@ -265,9 +265,9 @@ class SliceHeaderControls extends React.PureComponent {
|
||||
triggerNode.closest(SCREENSHOT_NODE_SELECTOR)
|
||||
}
|
||||
>
|
||||
<a id={`slice_${slice.slice_id}-controls`} role="button">
|
||||
<span id={`slice_${slice.slice_id}-controls`} role="button">
|
||||
<VerticalDotsTrigger />
|
||||
</a>
|
||||
</span>
|
||||
</NoAnimationDropdown>
|
||||
);
|
||||
}
|
||||
|
@ -29,13 +29,13 @@ const propTypes = {
|
||||
|
||||
export default function FilterFieldItem({ label, isSelected }) {
|
||||
return (
|
||||
<a
|
||||
<span
|
||||
className={cx('filter-field-item filter-container', {
|
||||
'is-selected': isSelected,
|
||||
})}
|
||||
>
|
||||
<FormLabel htmlFor={label}>{label}</FormLabel>
|
||||
</a>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ function traverse({ currentNode = {}, selectedChartId }) {
|
||||
return {
|
||||
...currentNode,
|
||||
label: (
|
||||
<a
|
||||
<span
|
||||
className={cx(`filter-scope-type ${type.toLowerCase()}`, {
|
||||
'selected-filter': selectedChartId === value,
|
||||
})}
|
||||
@ -46,7 +46,7 @@ function traverse({ currentNode = {}, selectedChartId }) {
|
||||
</span>
|
||||
)}
|
||||
{label}
|
||||
</a>
|
||||
</span>
|
||||
),
|
||||
children: updatedChildren,
|
||||
};
|
||||
@ -54,13 +54,13 @@ function traverse({ currentNode = {}, selectedChartId }) {
|
||||
return {
|
||||
...currentNode,
|
||||
label: (
|
||||
<a
|
||||
<span
|
||||
className={cx(`filter-scope-type ${type.toLowerCase()}`, {
|
||||
'selected-filter': selectedChartId === value,
|
||||
})}
|
||||
>
|
||||
{label}
|
||||
</a>
|
||||
</span>
|
||||
),
|
||||
};
|
||||
}
|
||||
|
@ -48,6 +48,14 @@ const StyledForm = styled(Form)`
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const StyledSpan = styled.span`
|
||||
cursor: pointer;
|
||||
color: ${({ theme }) => theme.colors.primary.dark1};
|
||||
&: hover {
|
||||
color: ${({ theme }) => theme.colors.primary.dark2};
|
||||
}
|
||||
`;
|
||||
|
||||
const FilterTabs = styled(LineEditableTabs)`
|
||||
// extra selector specificity:
|
||||
&.ant-tabs-card > .ant-tabs-nav .ant-tabs-tab {
|
||||
@ -473,13 +481,13 @@ export function FilterConfigModal({
|
||||
: getFilterTitle(id)}
|
||||
</div>
|
||||
{removedFilters[id] && (
|
||||
<a
|
||||
<StyledSpan
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => restoreFilter(id)}
|
||||
>
|
||||
{t('Undo?')}
|
||||
</a>
|
||||
</StyledSpan>
|
||||
)}
|
||||
</FilterTabTitle>
|
||||
}
|
||||
|
@ -67,6 +67,14 @@ const ConfirmModalStyled = styled.div`
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledSpan = styled.span`
|
||||
cursor: pointer;
|
||||
color: ${({ theme }) => theme.colors.primary.dark1};
|
||||
&: hover {
|
||||
color: ${({ theme }) => theme.colors.primary.dark2};
|
||||
}
|
||||
`;
|
||||
|
||||
const TABLE_COLUMNS = [
|
||||
'name',
|
||||
'type',
|
||||
@ -191,13 +199,14 @@ const ChangeDatasourceModal: FunctionComponent<ChangeDatasourceModalProps> = ({
|
||||
connection: ds.database.database_name,
|
||||
schema: ds.schema,
|
||||
name: (
|
||||
<a
|
||||
href="#"
|
||||
<StyledSpan
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
data-test="datasource-link"
|
||||
onClick={() => selectDatasource({ type: 'table', ...ds })}
|
||||
className="datasource-link"
|
||||
>
|
||||
{ds.table_name}
|
||||
</a>
|
||||
</StyledSpan>
|
||||
),
|
||||
type: ds.kind,
|
||||
}));
|
||||
|
@ -790,12 +790,12 @@ class DatasourceEditor extends React.PureComponent {
|
||||
</Fieldset>
|
||||
{this.allowEditSource && (
|
||||
<EditLockContainer>
|
||||
<a href="#" onClick={this.onChangeEditMode}>
|
||||
<span role="button" tabIndex={0} onClick={this.onChangeEditMode}>
|
||||
<Icon
|
||||
color={supersetTheme.colors.grayscale.base}
|
||||
name={this.state.isEditMode ? 'lock-unlocked' : 'lock-locked'}
|
||||
/>
|
||||
</a>
|
||||
</span>
|
||||
{!this.state.isEditMode && (
|
||||
<div>{t('Click the lock to make changes.')}</div>
|
||||
)}
|
||||
|
@ -79,7 +79,7 @@ export default function ExploreActionButtons({
|
||||
)}
|
||||
|
||||
{latestQueryFormData && (
|
||||
<a
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={doExportChart}
|
||||
@ -89,10 +89,10 @@ export default function ExploreActionButtons({
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<i className="fa fa-file-code-o" /> .json
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
{latestQueryFormData && (
|
||||
<a
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={doExportCSV}
|
||||
@ -102,7 +102,7 @@ export default function ExploreActionButtons({
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<i className="fa fa-file-text-o" /> .csv
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
<ConnectedDisplayQueryButton
|
||||
chartHeight={chartHeight}
|
||||
|
Loading…
Reference in New Issue
Block a user