chore: fix explore pills (#19866)

* chore: fix explore pills

* fix tests

* address comments

* add test and remove redundant div

* switch to dark text
This commit is contained in:
Ville Brofeldt 2022-04-28 10:28:47 +03:00 committed by GitHub
parent e4fca89217
commit 3d2fec9604
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 133 additions and 97 deletions

View File

@ -122,12 +122,12 @@ describe('Test datatable', () => {
});
it('Data Pane opens and loads results', () => {
cy.contains('Results').click();
cy.get('[data-test="row-count-label"]').contains('26 rows retrieved');
cy.get('[data-test="row-count-label"]').contains('26 rows');
cy.get('.ant-empty-description').should('not.exist');
});
it('Datapane loads view samples', () => {
cy.contains('Samples').click();
cy.get('[data-test="row-count-label"]').contains('1k rows retrieved');
cy.get('[data-test="row-count-label"]').contains('1k rows');
cy.get('.ant-empty-description').should('not.exist');
});
});

View File

@ -19,7 +19,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { isEqual, isEmpty } from 'lodash';
import { t } from '@superset-ui/core';
import { styled, t } from '@superset-ui/core';
import { sanitizeFormData } from 'src/explore/exploreUtils/formData';
import getControlsForVizType from 'src/utils/getControlsForVizType';
import { safeStringify } from 'src/utils/safeStringify';
@ -32,6 +32,18 @@ const propTypes = {
currentFormData: PropTypes.object.isRequired,
};
const StyledLabel = styled.span`
${({ theme }) => `
font-size: ${theme.typography.sizes.s}px;
color: ${theme.colors.grayscale.dark1};
background-color: ${theme.colors.alert.base};
&: hover {
background-color: ${theme.colors.alert.dark1};
}
`}
`;
function alterForComparison(value) {
// Considering `[]`, `{}`, `null` and `undefined` as identical
// for this purpose
@ -183,9 +195,7 @@ export default class AlteredSliceTag extends React.Component {
renderTriggerNode() {
return (
<Tooltip id="difference-tooltip" title={t('Click to see difference')}>
<span className="label label-warning" style={{ fontSize: '12px' }}>
{t('Altered')}
</span>
<StyledLabel className="label">{t('Altered')}</StyledLabel>
</Tooltip>
);
}

View File

@ -48,7 +48,7 @@ const CacheLabel: React.FC<CacheLabelProps> = ({
onMouseOver={() => setHovered(true)}
onMouseOut={() => setHovered(false)}
>
{t('cached')} <i className="fa fa-refresh" />
{t('Cached')} <i className="fa fa-refresh" />
</Label>
</Tooltip>
);

View File

@ -26,8 +26,9 @@ export default {
excludeStories: 'options',
};
export const options = [
export const options: Type[] = [
'default',
'alert',
'info',
'success',
'warning',

View File

@ -23,6 +23,7 @@ import { useTheme } from '@superset-ui/core';
export type OnClickHandler = React.MouseEventHandler<HTMLElement>;
export type Type =
| 'alert'
| 'success'
| 'warning'
| 'danger'
@ -44,9 +45,17 @@ export interface LabelProps extends React.HTMLAttributes<HTMLSpanElement> {
export default function Label(props: LabelProps) {
const theme = useTheme();
const { colors, transitionTiming } = theme;
const { type, onClick, children, ...rest } = props;
const { primary, secondary, grayscale, success, warning, error, info } =
colors;
const { type = 'default', onClick, children, ...rest } = props;
const {
alert,
primary,
secondary,
grayscale,
success,
warning,
error,
info,
} = colors;
let backgroundColor = grayscale.light3;
let backgroundColorHover = onClick ? primary.light2 : grayscale.light3;
@ -54,11 +63,14 @@ export default function Label(props: LabelProps) {
let borderColorHover = onClick ? primary.light1 : 'transparent';
let color = grayscale.dark1;
if (type && type !== 'default') {
if (type !== 'default') {
color = grayscale.light4;
let baseColor;
if (type === 'success') {
if (type === 'alert') {
color = grayscale.dark1;
baseColor = alert;
} else if (type === 'success') {
baseColor = success;
} else if (type === 'warning') {
baseColor = warning;

View File

@ -20,9 +20,14 @@ import React from 'react';
import { render, screen } from 'spec/helpers/testing-library';
import { RowCount } from '.';
test('Render a RowCount', () => {
test('Render a RowCount with a single row', () => {
render(<RowCount data={[{}]} loading={false} />);
expect(screen.getByText('1 row')).toBeInTheDocument();
});
test('Render a RowCount with multiple rows', () => {
render(<RowCount data={[{}, {}, {}]} loading={false} />);
expect(screen.getByText('3 rows retrieved')).toBeInTheDocument();
expect(screen.getByText('3 rows')).toBeInTheDocument();
});
test('Render a RowCount on loading', () => {

View File

@ -127,13 +127,7 @@ export const RowCount = ({
}: {
data?: Record<string, any>[];
loading: boolean;
}) => (
<RowCountLabel
rowcount={data?.length ?? 0}
loading={loading}
suffix={t('rows retrieved')}
/>
);
}) => <RowCountLabel rowcount={data?.length ?? 0} loading={loading} />;
enum FormatPickerValue {
Formatted,

View File

@ -103,7 +103,7 @@ describe('DataTablesPane', () => {
useRedux: true,
});
userEvent.click(screen.getByText('Results'));
expect(await screen.findByText('0 rows retrieved')).toBeVisible();
expect(await screen.findByText('0 rows')).toBeVisible();
expect(await screen.findByLabelText('Collapse data panel')).toBeVisible();
localStorage.clear();
});
@ -114,7 +114,7 @@ describe('DataTablesPane', () => {
useRedux: true,
});
userEvent.click(screen.getByText('Samples'));
expect(await screen.findByText('0 rows retrieved')).toBeVisible();
expect(await screen.findByText('0 rows')).toBeVisible();
expect(await screen.findByLabelText('Collapse data panel')).toBeVisible();
});
@ -158,7 +158,7 @@ describe('DataTablesPane', () => {
},
);
userEvent.click(screen.getByText('Results'));
expect(await screen.findByText('1 rows retrieved')).toBeVisible();
expect(await screen.findByText('1 row')).toBeVisible();
userEvent.click(screen.getByLabelText('Copy'));
expect(copyToClipboardSpy).toHaveBeenCalledWith(
@ -210,7 +210,7 @@ describe('DataTablesPane', () => {
},
);
userEvent.click(screen.getByText('Results'));
expect(await screen.findByText('2 rows retrieved')).toBeVisible();
expect(await screen.findByText('2 rows')).toBeVisible();
expect(screen.getByText('Action')).toBeVisible();
expect(screen.getByText('Horror')).toBeVisible();

View File

@ -17,17 +17,21 @@
* under the License.
*/
import React from 'react';
import RowCountLabel from '.';
import RowCountLabel, { RowCountLabelProps } from '.';
export default {
title: 'RowCountLabel',
component: RowCountLabel,
};
const options = {
const options: { [key in string]: RowCountLabelProps } = {
loading: {
loading: true,
},
single: {
rowcount: 1,
limit: 100,
},
full: {
rowcount: 100,
limit: 100,
@ -36,10 +40,6 @@ const options = {
rowcount: 50,
limit: 100,
},
suffix: {
rowcount: 1,
suffix: 'suffix',
},
};
export const RowCountLabelGallery = () => (
@ -51,7 +51,6 @@ export const RowCountLabelGallery = () => (
loading={options[name].loading}
rowcount={options[name].rowcount}
limit={options[name].limit}
suffix={options[name].suffix}
/>
</>
))}

View File

@ -1,50 +0,0 @@
/**
* 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 from 'react';
import { shallow } from 'enzyme';
import Label from 'src/components/Label';
import { Tooltip } from 'src/components/Tooltip';
import RowCountLabel from '.';
describe('RowCountLabel', () => {
const defaultProps = {
rowcount: 51,
limit: 100,
};
it('is valid', () => {
expect(React.isValidElement(<RowCountLabel {...defaultProps} />)).toBe(
true,
);
});
it('renders a Label and a Tooltip', () => {
const wrapper = shallow(<RowCountLabel {...defaultProps} />);
expect(wrapper.find(Label)).toExist();
expect(wrapper.find(Tooltip)).toExist();
});
it('renders a danger when limit is reached', () => {
const props = {
rowcount: 100,
limit: 100,
};
const wrapper = shallow(<RowCountLabel {...props} />);
expect(wrapper.find(Label).first().props().type).toBe('danger');
});
});

View File

@ -0,0 +1,65 @@
/**
* 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 from 'react';
import { render, screen } from 'spec/helpers/testing-library';
import userEvent from '@testing-library/user-event';
import RowCountLabel from '.';
test('RowCountLabel renders singular result', () => {
render(<RowCountLabel rowcount={1} limit={100} />);
const expectedText = '1 row';
expect(screen.getByText(expectedText)).toBeInTheDocument();
userEvent.hover(screen.getByText(expectedText));
expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
});
test('RowCountLabel renders plural result', () => {
render(<RowCountLabel rowcount={2} limit={100} />);
const expectedText = '2 rows';
expect(screen.getByText(expectedText)).toBeInTheDocument();
userEvent.hover(screen.getByText(expectedText));
expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
});
test('RowCountLabel renders formatted result', () => {
render(<RowCountLabel rowcount={1000} limit={10000} />);
const expectedText = '1k rows';
expect(screen.getByText(expectedText)).toBeInTheDocument();
userEvent.hover(screen.getByText(expectedText));
expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
});
test('RowCountLabel renders limit with danger and tooltip', async () => {
render(<RowCountLabel rowcount={100} limit={100} />);
const expectedText = '100 rows';
expect(screen.getByText(expectedText)).toBeInTheDocument();
userEvent.hover(screen.getByText(expectedText));
const tooltip = await screen.findByRole('tooltip');
expect(tooltip).toHaveTextContent('Limit reached');
expect(tooltip).toHaveStyle('background: rgba(0, 0, 0, 0.902);');
});
test('RowCountLabel renders loading', () => {
render(<RowCountLabel loading />);
const expectedText = 'Loading...';
expect(screen.getByText(expectedText)).toBeInTheDocument();
userEvent.hover(screen.getByText(expectedText));
expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
});

View File

@ -17,36 +17,36 @@
* under the License.
*/
import React from 'react';
import { getNumberFormatter, t } from '@superset-ui/core';
import { getNumberFormatter, t, tn } from '@superset-ui/core';
import Label from 'src/components/Label';
import { Tooltip } from 'src/components/Tooltip';
type RowCountLabelProps = {
rowcount: number;
rowcount?: number;
limit?: number;
suffix?: string;
loading?: boolean;
};
export default function RowCountLabel(props: RowCountLabelProps) {
const { rowcount = 0, limit, suffix = t('rows'), loading } = props;
const { rowcount = 0, limit, loading } = props;
const limitReached = rowcount === limit;
const type =
limitReached || (rowcount === 0 && !loading) ? 'danger' : 'default';
const formattedRowCount = getNumberFormatter()(rowcount);
const tooltip = (
<span>
{limitReached && <div>{t('Limit reached')}</div>}
{loading ? 'Loading' : rowcount}
</span>
const label = (
<Label type={type} data-test="row-count-label">
{loading
? t('Loading...')
: tn('%s row', '%s rows', rowcount, formattedRowCount)}
</Label>
);
return (
<Tooltip id="tt-rowcount-tooltip" title={tooltip}>
<Label type={type} data-test="row-count-label">
{loading ? 'Loading...' : `${formattedRowCount} ${suffix}`}
</Label>
return limitReached ? (
<Tooltip id="tt-rowcount-tooltip" title={<span>{t('Limit reached')}</span>}>
{label}
</Tooltip>
) : (
label
);
}