Migrates Label component from Bootstrap to AntD. (#12774)
This commit is contained in:
parent
388edbf7b2
commit
2adfb85597
|
|
@ -104,7 +104,7 @@ describe('VizType control', () => {
|
|||
numScripts = nodes.length;
|
||||
});
|
||||
|
||||
cy.get('.Control .label').contains('Table').click();
|
||||
cy.get('[data-test="visualization-type"]').contains('Table').click();
|
||||
|
||||
cy.get('[role="button"]').contains('Line Chart').click();
|
||||
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ describe('Visualization > Table', () => {
|
|||
cy.verifySliceContainer('table');
|
||||
expect(response?.body.result[0].data.length).to.eq(limit);
|
||||
});
|
||||
cy.get('span.label-danger').contains('10 rows');
|
||||
cy.get('[data-test="row-count-label"]').contains('10 rows');
|
||||
});
|
||||
|
||||
it('Test table with columns and row limit', () => {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
*/
|
||||
import React from 'react';
|
||||
import { render, sleep, waitFor } from 'spec/helpers/testing-library';
|
||||
import Timer from 'src/components/Timer';
|
||||
import Timer, { TimerProps } from 'src/components/Timer';
|
||||
import { now } from 'src/modules/dates';
|
||||
|
||||
function parseTime(text?: string | null) {
|
||||
|
|
@ -29,7 +29,7 @@ function parseTime(text?: string | null) {
|
|||
}
|
||||
|
||||
describe('Timer', () => {
|
||||
const mockProps = {
|
||||
const mockProps: TimerProps = {
|
||||
startTime: now(),
|
||||
endTime: undefined,
|
||||
isRunning: true,
|
||||
|
|
@ -41,7 +41,6 @@ describe('Timer', () => {
|
|||
const node = screen.getByRole('timer');
|
||||
let text = node.textContent || '';
|
||||
expect(node).toBeInTheDocument();
|
||||
expect(node).toHaveClass('label-warning');
|
||||
expect(node).toHaveTextContent('00:00:00.00');
|
||||
// should start running
|
||||
await waitFor(() => {
|
||||
|
|
|
|||
|
|
@ -45,6 +45,6 @@ describe('RowCountLabel', () => {
|
|||
limit: 100,
|
||||
};
|
||||
const wrapper = shallow(<RowCountLabel {...props} />);
|
||||
expect(wrapper.find(Label).first().props().bsStyle).toBe('danger');
|
||||
expect(wrapper.find(Label).first().props().type).toBe('danger');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
import React from 'react';
|
||||
import { styledMount as mount } from 'spec/helpers/theming';
|
||||
import Security from 'src/profile/components/Security';
|
||||
|
||||
import Label from 'src/components/Label';
|
||||
import { user, userNoPerms } from './fixtures';
|
||||
|
||||
describe('Security', () => {
|
||||
|
|
@ -31,19 +31,19 @@ describe('Security', () => {
|
|||
});
|
||||
it('renders 2 role labels', () => {
|
||||
const wrapper = mount(<Security {...mockedProps} />);
|
||||
expect(wrapper.find('.roles').find('.label')).toHaveLength(2);
|
||||
expect(wrapper.find('.roles').find(Label)).toHaveLength(2);
|
||||
});
|
||||
it('renders 2 datasource labels', () => {
|
||||
const wrapper = mount(<Security {...mockedProps} />);
|
||||
expect(wrapper.find('.datasources').find('.label')).toHaveLength(2);
|
||||
expect(wrapper.find('.datasources').find(Label)).toHaveLength(2);
|
||||
});
|
||||
it('renders 3 database labels', () => {
|
||||
const wrapper = mount(<Security {...mockedProps} />);
|
||||
expect(wrapper.find('.databases').find('.label')).toHaveLength(3);
|
||||
expect(wrapper.find('.databases').find(Label)).toHaveLength(3);
|
||||
});
|
||||
it('renders no permission label when empty', () => {
|
||||
const wrapper = mount(<Security user={userNoPerms} />);
|
||||
expect(wrapper.find('.datasources').find('.label')).not.toExist();
|
||||
expect(wrapper.find('.databases').find('.label')).not.toExist();
|
||||
expect(wrapper.find('.datasources').find(Label)).not.toExist();
|
||||
expect(wrapper.find('.databases').find(Label)).not.toExist();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -20,16 +20,16 @@ import React from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import Label from 'src/components/Label';
|
||||
|
||||
import { STATE_BSSTYLE_MAP } from '../constants';
|
||||
import { STATE_TYPE_MAP } from '../constants';
|
||||
|
||||
const propTypes = {
|
||||
query: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default function QueryStateLabel({ query }) {
|
||||
const bsStyle = STATE_BSSTYLE_MAP[query.state];
|
||||
const type = STATE_TYPE_MAP[query.state];
|
||||
return (
|
||||
<Label className="m-r-3" bsStyle={bsStyle}>
|
||||
<Label className="m-r-3" type={type}>
|
||||
{query.state}
|
||||
</Label>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ const QueryTable = props => {
|
|||
<ModalTrigger
|
||||
className="ResultsModal"
|
||||
triggerNode={
|
||||
<Label bsStyle="info" className="pointer">
|
||||
<Label type="info" className="pointer">
|
||||
{t('View results')}
|
||||
</Label>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ import QueryHistory from './QueryHistory';
|
|||
import ResultSet from './ResultSet';
|
||||
import {
|
||||
STATUS_OPTIONS,
|
||||
STATE_BSSTYLE_MAP,
|
||||
STATE_TYPE_MAP,
|
||||
LOCALSTORAGE_MAX_QUERY_AGE_MS,
|
||||
} from '../constants';
|
||||
|
||||
|
|
@ -97,10 +97,7 @@ export class SouthPane extends React.PureComponent {
|
|||
render() {
|
||||
if (this.props.offline) {
|
||||
return (
|
||||
<Label
|
||||
className="m-r-3"
|
||||
bsStyle={STATE_BSSTYLE_MAP[STATUS_OPTIONS.offline]}
|
||||
>
|
||||
<Label className="m-r-3" type={STATE_TYPE_MAP[STATUS_OPTIONS.offline]}>
|
||||
{STATUS_OPTIONS.offline}
|
||||
</Label>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ import ShareSqlLabQuery from './ShareSqlLabQuery';
|
|||
import SqlEditorLeftBar from './SqlEditorLeftBar';
|
||||
import AceEditorWrapper from './AceEditorWrapper';
|
||||
import {
|
||||
STATE_BSSTYLE_MAP,
|
||||
STATE_TYPE_MAP,
|
||||
SQL_EDITOR_GUTTER_HEIGHT,
|
||||
SQL_EDITOR_GUTTER_MARGIN,
|
||||
SQL_TOOLBAR_HEIGHT,
|
||||
|
|
@ -575,7 +575,7 @@ class SqlEditor extends React.PureComponent {
|
|||
this.props.latestQuery.rows,
|
||||
)}
|
||||
>
|
||||
<Label bsStyle="warning">LIMIT</Label>
|
||||
<Label type="warning">LIMIT</Label>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
|
@ -670,7 +670,7 @@ class SqlEditor extends React.PureComponent {
|
|||
<Timer
|
||||
startTime={this.props.latestQuery.startDttm}
|
||||
endTime={this.props.latestQuery.endDttm}
|
||||
state={STATE_BSSTYLE_MAP[this.props.latestQuery.state]}
|
||||
state={STATE_TYPE_MAP[this.props.latestQuery.state]}
|
||||
isRunning={this.props.latestQuery.state === 'running'}
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
export const STATE_BSSTYLE_MAP = {
|
||||
export const STATE_TYPE_MAP = {
|
||||
offline: 'danger',
|
||||
failed: 'danger',
|
||||
pending: 'info',
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ export default class AddSliceContainer extends React.PureComponent<
|
|||
name="select-vis-type"
|
||||
onChange={this.changeVisType}
|
||||
value={this.state.visType}
|
||||
labelBsStyle="primary"
|
||||
labelType="primary"
|
||||
/>
|
||||
</div>
|
||||
<br />
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ export {
|
|||
Select,
|
||||
Skeleton,
|
||||
Switch,
|
||||
Tag,
|
||||
Tabs,
|
||||
Tooltip,
|
||||
Input as AntdInput,
|
||||
|
|
|
|||
|
|
@ -67,12 +67,12 @@ class CacheLabel extends React.PureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const labelStyle = this.state.hovered ? 'primary' : 'default';
|
||||
const labelType = this.state.hovered ? 'primary' : 'default';
|
||||
return (
|
||||
<TooltipWrapper tooltip={this.state.tooltipContent} label="cache-desc">
|
||||
<Label
|
||||
className={`${this.props.className}`}
|
||||
bsStyle={labelStyle}
|
||||
type={labelType}
|
||||
onClick={this.props.onClick}
|
||||
onMouseOver={this.mouseOver.bind(this)}
|
||||
onMouseOut={this.mouseOut.bind(this)}
|
||||
|
|
|
|||
|
|
@ -54,6 +54,11 @@ const DatabaseSelectorWrapper = styled.div`
|
|||
}
|
||||
`;
|
||||
|
||||
const DatabaseOption = styled.span`
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
interface DatabaseSelectorProps {
|
||||
dbId: number;
|
||||
formMode?: boolean;
|
||||
|
|
@ -184,9 +189,9 @@ export default function DatabaseSelector({
|
|||
|
||||
function renderDatabaseOption(db: any) {
|
||||
return (
|
||||
<span title={db.database_name}>
|
||||
<Label bsStyle="default">{db.backend}</Label> {db.database_name}
|
||||
</span>
|
||||
<DatabaseOption title={db.database_name}>
|
||||
<Label type="default">{db.backend}</Label> {db.database_name}
|
||||
</DatabaseOption>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,59 +18,52 @@
|
|||
*/
|
||||
import React from 'react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { withKnobs, select, boolean, text } from '@storybook/addon-knobs';
|
||||
import Label from './index';
|
||||
import Label, { Type } from './index';
|
||||
|
||||
export default {
|
||||
title: 'Label',
|
||||
component: Label,
|
||||
decorators: [withKnobs],
|
||||
excludeStories: /.*Knob$/,
|
||||
excludeStories: 'options',
|
||||
};
|
||||
|
||||
export const bsStyleKnob = {
|
||||
label: 'Types',
|
||||
options: {
|
||||
default: 'default',
|
||||
info: 'info',
|
||||
success: 'success',
|
||||
warning: 'warning',
|
||||
danger: 'danger',
|
||||
secondary: 'secondary',
|
||||
primary: 'primary',
|
||||
},
|
||||
defaultValue: 'default',
|
||||
};
|
||||
export const options = [
|
||||
'default',
|
||||
'info',
|
||||
'success',
|
||||
'warning',
|
||||
'danger',
|
||||
'primary',
|
||||
'secondary',
|
||||
];
|
||||
|
||||
export const LabelGallery = () => (
|
||||
<>
|
||||
<h4>Non-interactive</h4>
|
||||
{Object.values(bsStyleKnob.options).map(opt => (
|
||||
<Label key={opt} bsStyle={opt}>
|
||||
{Object.values(options).map((opt: Type) => (
|
||||
<Label key={opt} type={opt}>
|
||||
{`style: "${opt}"`}
|
||||
</Label>
|
||||
))}
|
||||
<br />
|
||||
<h4>Interactive</h4>
|
||||
{Object.values(bsStyleKnob.options).map(opt => (
|
||||
<Label key={opt} bsStyle={opt} onClick={action('clicked')}>
|
||||
{Object.values(options).map((opt: Type) => (
|
||||
<Label key={opt} type={opt} onClick={action('clicked')}>
|
||||
{`style: "${opt}"`}
|
||||
</Label>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
|
||||
export const InteractiveLabel = () => (
|
||||
<Label
|
||||
bsStyle={select(
|
||||
bsStyleKnob.label,
|
||||
bsStyleKnob.options,
|
||||
bsStyleKnob.defaultValue,
|
||||
)}
|
||||
onClick={
|
||||
boolean('Has onClick action', false) ? action('clicked') : undefined
|
||||
}
|
||||
>
|
||||
{text('Label', 'Label!')}
|
||||
</Label>
|
||||
);
|
||||
export const InteractiveLabel = (args: any) => {
|
||||
const { hasOnClick, label, ...rest } = args;
|
||||
return (
|
||||
<Label onClick={hasOnClick ? action('clicked') : undefined} {...rest}>
|
||||
{label}
|
||||
</Label>
|
||||
);
|
||||
};
|
||||
|
||||
InteractiveLabel.args = {
|
||||
hasOnClick: true,
|
||||
label: 'Example',
|
||||
};
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import React from 'react';
|
|||
import { ReactWrapper } from 'enzyme';
|
||||
import { styledMount as mount } from 'spec/helpers/theming';
|
||||
import Label from '.';
|
||||
import { LabelGallery, bsStyleKnob } from './Label.stories';
|
||||
import { LabelGallery, options } from './Label.stories';
|
||||
|
||||
describe('Label', () => {
|
||||
let wrapper: ReactWrapper;
|
||||
|
|
@ -34,23 +34,13 @@ describe('Label', () => {
|
|||
it('works with an onClick handler', () => {
|
||||
const mockAction = jest.fn();
|
||||
wrapper = mount(<Label onClick={mockAction} />);
|
||||
wrapper.find('.label').simulate('click');
|
||||
wrapper.find(Label).simulate('click');
|
||||
expect(mockAction).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
// test stories from the storybook!
|
||||
it('renders all the sorybook gallery variants', () => {
|
||||
it('renders all the storybook gallery variants', () => {
|
||||
wrapper = mount(<LabelGallery />);
|
||||
Object.values(bsStyleKnob.options).forEach(opt => {
|
||||
expect(wrapper.find(`.label-${opt}`).at(0).text()).toEqual(
|
||||
`style: "${opt}"`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// test things NOT in the storybook!
|
||||
it('renders custom label styles without melting', () => {
|
||||
wrapper = mount(<Label bsStyle="foobar" />);
|
||||
expect(wrapper.find('Label.label-foobar')).toHaveLength(1);
|
||||
expect(wrapper.find(Label).length).toEqual(options.length * 2);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -17,149 +17,98 @@
|
|||
* under the License.
|
||||
*/
|
||||
import React, { CSSProperties } from 'react';
|
||||
import { Label as BootstrapLabel } from 'react-bootstrap';
|
||||
import { styled } from '@superset-ui/core';
|
||||
import cx from 'classnames';
|
||||
import { Tag } from 'src/common/components';
|
||||
import { useTheme } from '@superset-ui/core';
|
||||
|
||||
export type OnClickHandler = React.MouseEventHandler<BootstrapLabel>;
|
||||
export type OnClickHandler = React.MouseEventHandler<HTMLElement>;
|
||||
|
||||
export type Type =
|
||||
| 'success'
|
||||
| 'warning'
|
||||
| 'danger'
|
||||
| 'info'
|
||||
| 'default'
|
||||
| 'primary'
|
||||
| 'secondary';
|
||||
|
||||
export interface LabelProps {
|
||||
key?: string;
|
||||
className?: string;
|
||||
id?: string;
|
||||
tooltip?: string;
|
||||
placement?: string;
|
||||
onClick?: OnClickHandler;
|
||||
bsStyle?: string;
|
||||
type?: Type;
|
||||
style?: CSSProperties;
|
||||
children?: React.ReactNode;
|
||||
role?: string;
|
||||
}
|
||||
|
||||
const SupersetLabel = styled(BootstrapLabel)`
|
||||
/* un-bunch them! */
|
||||
margin-right: ${({ theme }) => theme.gridUnit}px;
|
||||
max-width: 100%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
vertical-align: middle;
|
||||
|
||||
&:first-of-type {
|
||||
margin-left: 0;
|
||||
}
|
||||
&:last-of-type {
|
||||
margin-right: 0;
|
||||
}
|
||||
display: inline-block;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
cursor: ${({ onClick }) => (onClick ? 'pointer' : 'default')};
|
||||
transition: background-color ${({ theme }) => theme.transitionTiming}s;
|
||||
&.label-warning {
|
||||
background-color: ${({ theme }) => theme.colors.warning.base};
|
||||
border-color: ${({ theme, onClick }) =>
|
||||
onClick ? theme.colors.warning.dark1 : 'transparent'};
|
||||
&:hover {
|
||||
background-color: ${({ theme, onClick }) =>
|
||||
onClick ? theme.colors.warning.dark1 : theme.colors.warning.base};
|
||||
border-color: ${({ theme, onClick }) =>
|
||||
onClick ? theme.colors.warning.dark2 : 'transparent'};
|
||||
}
|
||||
}
|
||||
&.label-danger {
|
||||
background-color: ${({ theme }) => theme.colors.error.base};
|
||||
border-color: ${({ theme, onClick }) =>
|
||||
onClick ? theme.colors.error.dark1 : 'transparent'};
|
||||
&:hover {
|
||||
background-color: ${({ theme, onClick }) =>
|
||||
onClick ? theme.colors.error.dark1 : theme.colors.error.base};
|
||||
border-color: ${({ theme, onClick }) =>
|
||||
onClick ? theme.colors.error.dark2 : 'transparent'};
|
||||
}
|
||||
}
|
||||
&.label-success {
|
||||
background-color: ${({ theme }) => theme.colors.success.base};
|
||||
border-color: ${({ theme, onClick }) =>
|
||||
onClick ? theme.colors.success.dark1 : 'transparent'};
|
||||
&:hover {
|
||||
background-color: ${({ theme, onClick }) =>
|
||||
onClick ? theme.colors.success.dark1 : theme.colors.success.base};
|
||||
border-color: ${({ theme, onClick }) =>
|
||||
onClick ? theme.colors.success.dark2 : 'transparent'};
|
||||
}
|
||||
}
|
||||
&.label-default {
|
||||
background-color: ${({ theme }) => theme.colors.grayscale.light3};
|
||||
color: ${({ theme }) => theme.colors.grayscale.dark1};
|
||||
border-color: ${({ theme, onClick }) =>
|
||||
onClick ? theme.colors.grayscale.light2 : 'transparent'};
|
||||
&:hover {
|
||||
background-color: ${({ theme, onClick }) =>
|
||||
onClick ? theme.colors.primary.light2 : theme.colors.grayscale.light3};
|
||||
border-color: ${({ theme, onClick }) =>
|
||||
onClick ? theme.colors.primary.light1 : 'transparent'};
|
||||
}
|
||||
}
|
||||
&.label-info {
|
||||
background-color: ${({ theme }) => theme.colors.info};
|
||||
border-color: ${({ theme, onClick }) =>
|
||||
onClick ? theme.colors.info.dark1 : 'transparent'};
|
||||
&:hover {
|
||||
background-color: ${({ theme, onClick }) =>
|
||||
onClick ? theme.colors.info.dark1 : theme.colors.info.base};
|
||||
border-color: ${({ theme, onClick }) =>
|
||||
onClick ? theme.colors.info.dark2 : 'transparent'};
|
||||
}
|
||||
}
|
||||
&.label-primary {
|
||||
background-color: ${({ theme }) => theme.colors.primary.base};
|
||||
border-color: ${({ theme, onClick }) =>
|
||||
onClick ? theme.colors.primary.dark1 : 'transparent'};
|
||||
&:hover {
|
||||
background-color: ${({ theme, onClick }) =>
|
||||
onClick ? theme.colors.primary.dark2 : theme.colors.primary.base};
|
||||
border-color: ${({ theme, onClick }) =>
|
||||
onClick
|
||||
? theme.colors.primary.dark2
|
||||
: 'transparent'}; /* would be nice if we had a darker color, but that's the floor! */
|
||||
}
|
||||
}
|
||||
/* note this is NOT a supported bootstrap label Style... this overrides default */
|
||||
&.label-secondary {
|
||||
background-color: ${({ theme }) => theme.colors.secondary.base};
|
||||
color: ${({ theme }) => theme.colors.grayscale.light4};
|
||||
border-color: ${({ theme, onClick }) =>
|
||||
onClick ? theme.colors.secondary.dark1 : 'transparent'};
|
||||
&:hover {
|
||||
background-color: ${({ theme, onClick }) =>
|
||||
onClick ? theme.colors.secondary.dark1 : theme.colors.secondary.base};
|
||||
border-color: ${({ theme, onClick }) =>
|
||||
onClick ? theme.colors.secondary.dark2 : 'transparent'};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default function Label(props: LabelProps) {
|
||||
const officialBootstrapStyles = [
|
||||
'success',
|
||||
'warning',
|
||||
'danger',
|
||||
'info',
|
||||
'default',
|
||||
'primary',
|
||||
];
|
||||
const labelProps = {
|
||||
...props,
|
||||
placement: props.placement || 'top',
|
||||
bsStyle: officialBootstrapStyles.includes(props.bsStyle || '')
|
||||
? props.bsStyle
|
||||
: 'default',
|
||||
className: cx(props.className, {
|
||||
[`label-${props.bsStyle}`]: !officialBootstrapStyles.includes(
|
||||
props.bsStyle || '',
|
||||
),
|
||||
}),
|
||||
};
|
||||
return <SupersetLabel {...labelProps}>{props.children}</SupersetLabel>;
|
||||
const theme = useTheme();
|
||||
const { colors, transitionTiming } = theme;
|
||||
const { type, onClick, children, ...rest } = props;
|
||||
const {
|
||||
primary,
|
||||
secondary,
|
||||
grayscale,
|
||||
success,
|
||||
warning,
|
||||
error,
|
||||
info,
|
||||
} = colors;
|
||||
|
||||
let backgroundColor = grayscale.light3;
|
||||
let backgroundColorHover = onClick ? primary.light2 : grayscale.light3;
|
||||
let borderColor = onClick ? grayscale.light2 : 'transparent';
|
||||
let borderColorHover = onClick ? primary.light1 : 'transparent';
|
||||
let color = grayscale.dark1;
|
||||
|
||||
if (type && type !== 'default') {
|
||||
color = grayscale.light4;
|
||||
|
||||
let baseColor;
|
||||
if (type === 'success') {
|
||||
baseColor = success;
|
||||
} else if (type === 'warning') {
|
||||
baseColor = warning;
|
||||
} else if (type === 'danger') {
|
||||
baseColor = error;
|
||||
} else if (type === 'info') {
|
||||
baseColor = info;
|
||||
} else if (type === 'secondary') {
|
||||
baseColor = secondary;
|
||||
} else {
|
||||
baseColor = primary;
|
||||
}
|
||||
|
||||
backgroundColor = baseColor.base;
|
||||
backgroundColorHover = onClick ? baseColor.dark1 : baseColor.base;
|
||||
borderColor = onClick ? baseColor.dark1 : 'transparent';
|
||||
borderColorHover = onClick ? baseColor.dark2 : 'transparent';
|
||||
}
|
||||
|
||||
return (
|
||||
<Tag
|
||||
css={{
|
||||
transition: `background-color ${transitionTiming}s`,
|
||||
whiteSpace: 'nowrap',
|
||||
cursor: onClick ? 'pointer' : 'default',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
backgroundColor,
|
||||
borderColor,
|
||||
borderRadius: 21,
|
||||
padding: '0.35em 0.8em',
|
||||
lineHeight: 1,
|
||||
color,
|
||||
'&:hover': {
|
||||
backgroundColor: backgroundColorHover,
|
||||
borderColor: borderColorHover,
|
||||
opacity: 1,
|
||||
},
|
||||
}}
|
||||
onClick={onClick}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,19 +18,18 @@
|
|||
*/
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { styled } from '@superset-ui/core';
|
||||
import Label from 'src/components/Label';
|
||||
import Label, { Type } from 'src/components/Label';
|
||||
|
||||
import { now, fDuration } from 'src/modules/dates';
|
||||
|
||||
interface TimerProps {
|
||||
export interface TimerProps {
|
||||
endTime?: number;
|
||||
isRunning: boolean;
|
||||
startTime?: number;
|
||||
status?: string;
|
||||
status?: Type;
|
||||
}
|
||||
|
||||
const TimerLabel = styled(Label)`
|
||||
line-height: 13px;
|
||||
text-align: left;
|
||||
width: 91px;
|
||||
`;
|
||||
|
|
@ -69,7 +68,7 @@ export default function Timer({
|
|||
}, [endTime, isRunning, startTime]);
|
||||
|
||||
return (
|
||||
<TimerLabel bsStyle={status} role="timer">
|
||||
<TimerLabel type={status} role="timer">
|
||||
{clockStr}
|
||||
</TimerLabel>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ const defaultProps = {
|
|||
|
||||
export default function RowCountLabel({ rowcount, limit, suffix, loading }) {
|
||||
const limitReached = rowcount === limit;
|
||||
const bsStyle =
|
||||
const type =
|
||||
limitReached || (rowcount === 0 && !loading) ? 'danger' : 'default';
|
||||
const formattedRowCount = getNumberFormatter()(rowcount);
|
||||
const tooltip = (
|
||||
|
|
@ -48,7 +48,7 @@ export default function RowCountLabel({ rowcount, limit, suffix, loading }) {
|
|||
);
|
||||
return (
|
||||
<TooltipWrapper label="tt-rowcount" tooltip={tooltip}>
|
||||
<Label bsStyle={bsStyle}>
|
||||
<Label type={type} data-test="row-count-label">
|
||||
{loading ? 'Loading...' : `${formattedRowCount} ${suffix}`}
|
||||
</Label>
|
||||
</TooltipWrapper>
|
||||
|
|
|
|||
|
|
@ -34,12 +34,12 @@ const propTypes = {
|
|||
name: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func,
|
||||
value: PropTypes.string.isRequired,
|
||||
labelBsStyle: PropTypes.string,
|
||||
labelType: PropTypes.string,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
onChange: () => {},
|
||||
labelBsStyle: 'default',
|
||||
labelType: 'default',
|
||||
};
|
||||
|
||||
const registry = getChartMetadataRegistry();
|
||||
|
|
@ -162,7 +162,7 @@ const VizTypeControl = props => {
|
|||
);
|
||||
};
|
||||
|
||||
const { value, labelBsStyle } = props;
|
||||
const { value, labelType } = props;
|
||||
const filterString = filter.toLowerCase();
|
||||
|
||||
const filteredTypes = DEFAULT_ORDER.filter(type => registry.has(type))
|
||||
|
|
@ -201,7 +201,11 @@ const VizTypeControl = props => {
|
|||
title={t('Click to change visualization type')}
|
||||
>
|
||||
<>
|
||||
<Label onClick={toggleModal} bsStyle={labelBsStyle}>
|
||||
<Label
|
||||
onClick={toggleModal}
|
||||
type={labelType}
|
||||
data-test="visualization-type"
|
||||
>
|
||||
{registry.has(value) ? registry.get(value).name : `${value}`}
|
||||
</Label>
|
||||
<VizSupportValidation vizType={value} />
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ export default function ChartCard({
|
|||
description={t('Last modified %s', chart.changed_on_delta_humanized)}
|
||||
coverLeft={<FacePile users={chart.owners || []} />}
|
||||
coverRight={
|
||||
<Label bsStyle="secondary">{chart.datasource_name_text}</Label>
|
||||
<Label type="secondary">{chart.datasource_name_text}</Label>
|
||||
}
|
||||
actions={
|
||||
<ListViewCard.Actions
|
||||
|
|
|
|||
Loading…
Reference in New Issue