chore: Migrate .less styles to Emotion (#22474)

This commit is contained in:
Kamil Gabryjelski
2023-01-19 09:17:10 +01:00
committed by GitHub
parent 5026da50e1
commit 39c96d0568
61 changed files with 1665 additions and 2414 deletions

View File

@@ -18,6 +18,8 @@
*/
import React, { useState, useEffect, useRef } from 'react';
import { useDispatch } from 'react-redux';
import { css, styled } from '@superset-ui/core';
import { usePrevious } from 'src/hooks/usePrevious';
import { areArraysShallowEqual } from 'src/reduxUtils';
import sqlKeywords from 'src/SqlLab/utils/sqlKeywords';
@@ -57,6 +59,28 @@ type AceEditorWrapperProps = {
hotkeys: HotKey[];
};
const StyledAceEditor = styled(AceEditor)`
${({ theme }) => css`
&& {
// double class is better than !important
border: 1px solid ${theme.colors.grayscale.light2};
font-feature-settings: 'liga' off, 'calt' off;
// Fira Code causes problem with Ace under Firefox
font-family: 'Menlo', 'Consolas', 'Courier New', 'Ubuntu Mono',
'source-code-pro', 'Lucida Console', monospace;
&.ace_autocomplete {
// Use !important because Ace Editor applies extra CSS at the last second
// when opening the autocomplete.
width: ${theme.gridUnit * 130}px !important;
}
.ace_scroller {
background-color: ${theme.colors.grayscale.light4};
}
}
`}
`;
const AceEditorWrapper = ({
autocomplete,
onBlur = () => {},
@@ -258,7 +282,7 @@ const AceEditorWrapper = ({
};
return (
<AceEditor
<StyledAceEditor
keywords={words}
onLoad={onEditorLoad}
onBlur={onBlurSql}

View File

@@ -20,7 +20,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { t } from '@superset-ui/core';
import { css, styled, t } from '@superset-ui/core';
import throttle from 'lodash/throttle';
import ToastContainer from 'src/components/MessageToasts/ToastContainer';
import {
@@ -32,6 +32,69 @@ import * as Actions from 'src/SqlLab/actions/sqlLab';
import TabbedSqlEditors from '../TabbedSqlEditors';
import QueryAutoRefresh from '../QueryAutoRefresh';
const SqlLabStyles = styled.div`
${({ theme }) => css`
&.SqlLab {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
padding: 0 ${theme.gridUnit * 2}px;
pre {
padding: 0 !important;
margin: 0;
border: none;
font-size: ${theme.typography.sizes.s}px;
background: transparent !important;
}
.north-pane {
display: flex;
flex-direction: column;
}
.ace_editor {
flex-grow: 1;
}
.ace_content {
height: 100%;
}
.ant-tabs-content-holder {
/* This is needed for Safari */
height: 100%;
}
.ant-tabs-content {
height: 100%;
position: relative;
background-color: ${theme.colors.grayscale.light5};
overflow-x: auto;
overflow-y: auto;
> .ant-tabs-tabpane {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
}
.ResultsModal .ant-modal-body {
min-height: ${theme.gridUnit * 140}px;
}
.ant-modal-body {
overflow: auto;
}
}
`};
`;
class App extends React.PureComponent {
constructor(props) {
super(props);
@@ -99,7 +162,7 @@ class App extends React.PureComponent {
return window.location.replace('/superset/sqllab/history/');
}
return (
<div className="App SqlLab">
<SqlLabStyles className="App SqlLab">
<QueryAutoRefresh
queries={queries}
refreshQueries={actions?.refreshQueries}
@@ -107,7 +170,7 @@ class App extends React.PureComponent {
/>
<TabbedSqlEditors />
<ToastContainer />
</div>
</SqlLabStyles>
);
}
}

View File

@@ -18,7 +18,7 @@
*/
import React, { useMemo } from 'react';
import { useSelector } from 'react-redux';
import { t } from '@superset-ui/core';
import { css, styled, t } from '@superset-ui/core';
import Alert from 'src/components/Alert';
import TableView from 'src/components/TableView';
@@ -36,6 +36,12 @@ export interface EstimateQueryCostButtonProps {
disabled?: boolean;
}
const CostEstimateModalStyles = styled.div`
${({ theme }) => css`
font-size: ${theme.typography.sizes.s};
`}
`;
const EstimateQueryCostButton = ({
getEstimate,
queryEditorId,
@@ -76,13 +82,14 @@ const EstimateQueryCostButton = ({
}
if (queryCostEstimate?.completed) {
return (
<TableView
columns={columns}
data={tableData}
withPagination={false}
emptyWrapperType={EmptyWrapperType.Small}
className="cost-estimate"
/>
<CostEstimateModalStyles>
<TableView
columns={columns}
data={tableData}
withPagination={false}
emptyWrapperType={EmptyWrapperType.Small}
/>
</CostEstimateModalStyles>
);
}
return <Loading position="normal" />;

View File

@@ -17,8 +17,7 @@
* under the License.
*/
import React from 'react';
import { shallow } from 'enzyme';
import { styledMount as mount } from 'spec/helpers/theming';
import Label from 'src/components/Label';
import QueryStateLabel from 'src/SqlLab/components/QueryStateLabel';
@@ -34,7 +33,7 @@ describe('SavedQuery', () => {
);
});
it('has an Overlay and a Popover', () => {
const wrapper = shallow(<QueryStateLabel {...mockedProps} />);
const wrapper = mount(<QueryStateLabel {...mockedProps} />);
expect(wrapper.find(Label)).toExist();
});
});

View File

@@ -19,16 +19,18 @@
import React from 'react';
import Label from 'src/components/Label';
import { STATE_TYPE_MAP } from 'src/SqlLab/constants';
import { Query } from '@superset-ui/core';
import { styled, Query } from '@superset-ui/core';
interface QueryStateLabelProps {
query: Query;
}
const StyledLabel = styled(Label)`
margin-right: ${({ theme }) => theme.gridUnit}px;
`;
export default function QueryStateLabel({ query }: QueryStateLabelProps) {
return (
<Label className="m-r-3" type={STATE_TYPE_MAP[query.state]}>
{query.state}
</Label>
<StyledLabel type={STATE_TYPE_MAP[query.state]}>{query.state}</StyledLabel>
);
}

View File

@@ -22,7 +22,13 @@ import ButtonGroup from 'src/components/ButtonGroup';
import Alert from 'src/components/Alert';
import Button from 'src/components/Button';
import shortid from 'shortid';
import { QueryResponse, QueryState, styled, t } from '@superset-ui/core';
import {
QueryResponse,
QueryState,
styled,
t,
useTheme,
} from '@superset-ui/core';
import { usePrevious } from 'src/hooks/usePrevious';
import ErrorMessageWithStackTrace from 'src/components/ErrorMessage/ErrorMessageWithStackTrace';
import {
@@ -133,6 +139,7 @@ const ResultSet = ({
user,
defaultQueryLimit,
}: ResultSetProps) => {
const theme = useTheme();
const [searchText, setSearchText] = useState('');
const [cachedData, setCachedData] = useState<Record<string, unknown>[]>([]);
const [showSaveDatasetModal, setShowSaveDatasetModal] = useState(false);
@@ -449,7 +456,7 @@ const ResultSet = ({
<ButtonGroup>
<Button
buttonSize="small"
className="m-r-5"
css={{ marginRight: theme.gridUnit }}
onClick={() => popSelectStar(tempSchema, tempTable)}
>
{t('Query in a new tab')}

View File

@@ -23,7 +23,7 @@ import { CSSTransition } from 'react-transition-group';
import { useDispatch, useSelector } from 'react-redux';
import PropTypes from 'prop-types';
import Split from 'react-split';
import { t, styled, useTheme } from '@superset-ui/core';
import { css, t, styled, useTheme } from '@superset-ui/core';
import debounce from 'lodash/debounce';
import throttle from 'lodash/throttle';
import Modal from 'src/components/Modal';
@@ -132,6 +132,62 @@ const StyledSidebar = styled.div`
hide ? 'transparent' : theme.colors.grayscale.light2};
`;
const StyledSqlEditor = styled.div`
${({ theme }) => css`
display: flex;
flex-direction: row;
height: 100%;
.schemaPane {
transition: transform ${theme.transitionTiming}s ease-in-out;
}
.queryPane {
flex: 1 1 auto;
padding: ${theme.gridUnit * 2}px;
overflow-y: auto;
overflow-x: scroll;
}
.schemaPane-enter-done,
.schemaPane-exit {
transform: translateX(0);
z-index: 7;
}
.schemaPane-exit-active {
transform: translateX(-120%);
}
.schemaPane-enter-active {
transform: translateX(0);
max-width: ${theme.gridUnit * 75}px;
}
.schemaPane-enter,
.schemaPane-exit-done {
max-width: 0;
transform: translateX(-120%);
overflow: hidden;
}
.schemaPane-exit-done + .queryPane {
margin-left: 0;
}
.gutter {
border-top: 1px solid ${theme.colors.grayscale.light2};
border-bottom: 1px solid ${theme.colors.grayscale.light2};
width: 3%;
margin: ${theme.gridUnit}px 47%;
}
.gutter.gutter-vertical {
cursor: row-resize;
}
`}
`;
const propTypes = {
tables: PropTypes.array.isRequired,
queryEditor: PropTypes.object.isRequired,
@@ -636,7 +692,7 @@ const SqlEditor = ({
? 'schemaPane-exit-done'
: 'schemaPane-enter-done';
return (
<div ref={sqlEditorRef} className="SqlEditor">
<StyledSqlEditor ref={sqlEditorRef} className="SqlEditor">
<CSSTransition classNames="schemaPane" in={!hideLeftBar} timeout={300}>
<ResizableSidebar
id={`sqllab:${queryEditor.id}`}
@@ -704,7 +760,7 @@ const SqlEditor = ({
<span>{t('Name')}</span>
<Input placeholder={createModalPlaceHolder} onChange={ctasChanged} />
</Modal>
</div>
</StyledSqlEditor>
);
};

View File

@@ -89,12 +89,25 @@ const collapseStyles = (theme: SupersetTheme) => css`
.ant-collapse-arrow {
top: ${theme.gridUnit * 2}px !important;
color: ${theme.colors.primary.dark1} !important;
&: hover {
&:hover {
color: ${theme.colors.primary.dark2} !important;
}
}
`;
const LeftBarStyles = styled.div`
${({ theme }) => css`
height: 100%;
display: flex;
flex-direction: column;
.divider {
border-bottom: 1px solid ${theme.colors.grayscale.light4};
margin: ${theme.gridUnit * 4}px 0;
}
`}
`;
const SqlEditorLeftBar = ({
database,
queryEditorId,
@@ -228,7 +241,7 @@ const SqlEditorLeftBar = ({
}, []);
return (
<div data-test="sql-editor-left-bar" className="SqlEditorLeftBar">
<LeftBarStyles data-test="sql-editor-left-bar">
<TableSelectorMultiple
onEmptyResults={onEmptyResults}
emptyState={emptyStateComponent(emptyResultsWithSearch)}
@@ -276,7 +289,7 @@ const SqlEditorLeftBar = ({
<i className="fa fa-bomb" /> {t('Reset state')}
</Button>
)}
</div>
</LeftBarStyles>
);
};

View File

@@ -41,6 +41,12 @@ const TabTitle = styled.span`
text-transform: none;
`;
const IconContainer = styled.div`
display: inline-block;
width: ${({ theme }) => theme.gridUnit * 8}px;
text-align: center;
`;
interface Props {
queryEditor: QueryEditor;
}
@@ -91,9 +97,9 @@ const SqlEditorTabHeader: React.FC<Props> = ({ queryEditor }) => {
onClick={() => actions.removeQueryEditor(qe)}
data-test="close-tab-menu-option"
>
<div className="icon-container">
<IconContainer>
<i className="fa fa-close" />
</div>
</IconContainer>
{t('Close tab')}
</Menu.Item>
<Menu.Item
@@ -101,9 +107,9 @@ const SqlEditorTabHeader: React.FC<Props> = ({ queryEditor }) => {
onClick={renameTab}
data-test="rename-tab-menu-option"
>
<div className="icon-container">
<IconContainer>
<i className="fa fa-i-cursor" />
</div>
</IconContainer>
{t('Rename tab')}
</Menu.Item>
<Menu.Item
@@ -111,9 +117,9 @@ const SqlEditorTabHeader: React.FC<Props> = ({ queryEditor }) => {
onClick={() => actions.toggleLeftBar(qe)}
data-test="toggle-menu-option"
>
<div className="icon-container">
<IconContainer>
<i className="fa fa-cogs" />
</div>
</IconContainer>
{qe.hideLeftBar ? t('Expand tool bar') : t('Hide tool bar')}
</Menu.Item>
<Menu.Item
@@ -121,9 +127,9 @@ const SqlEditorTabHeader: React.FC<Props> = ({ queryEditor }) => {
onClick={() => actions.removeAllOtherQueryEditors(qe)}
data-test="close-all-other-menu-option"
>
<div className="icon-container">
<IconContainer>
<i className="fa fa-times-circle-o" />
</div>
</IconContainer>
{t('Close all other tabs')}
</Menu.Item>
<Menu.Item
@@ -131,9 +137,9 @@ const SqlEditorTabHeader: React.FC<Props> = ({ queryEditor }) => {
onClick={() => actions.cloneQueryToNewTab(qe, false)}
data-test="clone-tab-menu-option"
>
<div className="icon-container">
<IconContainer>
<i className="fa fa-files-o" />
</div>
</IconContainer>
{t('Duplicate tab')}
</Menu.Item>
</Menu>

View File

@@ -17,13 +17,42 @@
* under the License.
*/
import React from 'react';
import { QueryState, styled } from '@superset-ui/core';
import { css, QueryState, styled } from '@superset-ui/core';
import Icons, { IconType } from 'src/components/Icons';
const IconContainer = styled.span`
position: absolute;
top: -7px;
left: 0px;
top: -6px;
left: 1px;
`;
const Circle = styled.div`
${({ theme }) => css`
border-radius: 50%;
width: ${theme.gridUnit * 3}px;
height: ${theme.gridUnit * 3}px;
display: inline-block;
background-color: ${theme.colors.grayscale.light2};
text-align: center;
vertical-align: middle;
font-size: ${theme.typography.sizes.m}px;
font-weight: ${theme.typography.weights.bold};
color: ${theme.colors.grayscale.light5};
position: relative;
&.running {
background-color: ${theme.colors.info.base};
}
&.success {
background-color: ${theme.colors.success.base};
}
&.failed {
background-color: ${theme.colors.error.base};
}
`}
`;
interface TabStatusIconProps {
@@ -38,12 +67,12 @@ const STATE_ICONS: Record<string, React.FC<IconType>> = {
export default function TabStatusIcon({ tabState }: TabStatusIconProps) {
const StatusIcon = STATE_ICONS[tabState];
return (
<div className={`circle ${tabState}`}>
<Circle className={`circle ${tabState}`}>
{StatusIcon && (
<IconContainer>
<StatusIcon iconSize="xs" />
</IconContainer>
)}
</div>
</Circle>
);
}

View File

@@ -212,9 +212,9 @@ describe('TabbedSqlEditors', () => {
});
it('should disable new tab when offline', () => {
wrapper = getWrapper();
expect(wrapper.find(EditableTabs).props().hideAdd).toBe(false);
expect(wrapper.find('#a11y-query-editor-tabs').props().hideAdd).toBe(false);
wrapper.setProps({ offline: true });
expect(wrapper.find(EditableTabs).props().hideAdd).toBe(true);
expect(wrapper.find('#a11y-query-editor-tabs').props().hideAdd).toBe(true);
});
it('should have an empty state when query editors is empty', () => {
wrapper = getWrapper();

View File

@@ -54,6 +54,12 @@ const defaultProps = {
scheduleQueryWarning: null,
};
const StyledEditableTabs = styled(EditableTabs)`
height: 100%;
display: flex;
flex-direction: column;
`;
const StyledTab = styled.span`
line-height: 24px;
`;
@@ -303,7 +309,7 @@ class TabbedSqlEditors extends React.PureComponent {
);
return (
<EditableTabs
<StyledEditableTabs
destroyInactiveTabPane
activeKey={this.props.tabHistory[this.props.tabHistory.length - 1]}
id="a11y-query-editor-tabs"
@@ -331,7 +337,7 @@ class TabbedSqlEditors extends React.PureComponent {
>
{editors}
{noQueryEditors && emptyTabState}
</EditableTabs>
</StyledEditableTabs>
);
}
}

View File

@@ -21,7 +21,7 @@ import { useDispatch } from 'react-redux';
import Collapse from 'src/components/Collapse';
import Card from 'src/components/Card';
import ButtonGroup from 'src/components/ButtonGroup';
import { t, styled } from '@superset-ui/core';
import { css, t, styled } from '@superset-ui/core';
import { debounce } from 'lodash';
import { removeDataPreview, removeTables } from 'src/SqlLab/actions/sqlLab';
@@ -61,7 +61,7 @@ export interface TableElementProps {
const StyledSpan = styled.span`
color: ${({ theme }) => theme.colors.primary.dark1};
&: hover {
&:hover {
color: ${({ theme }) => theme.colors.primary.dark2};
}
cursor: pointer;
@@ -72,6 +72,39 @@ const Fade = styled.div`
opacity: ${(props: { hovered: boolean }) => (props.hovered ? 1 : 0)};
`;
const StyledCollapsePanel = styled(Collapse.Panel)`
${({ theme }) => css`
& {
.ws-el-controls {
margin-right: ${-theme.gridUnit}px;
display: flex;
}
.header-container {
display: flex;
flex: 1;
align-items: center;
width: 100%;
.table-name {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: ${theme.typography.sizes.l}px;
flex: 1;
}
.header-right-side {
margin-left: auto;
display: flex;
align-items: center;
margin-right: ${theme.gridUnit * 8}px;
}
}
}
`}
`;
const TableElement = ({ table, ...props }: TableElementProps) => {
const dispatch = useDispatch();
@@ -287,7 +320,7 @@ const TableElement = ({ table, ...props }: TableElementProps) => {
};
return (
<Collapse.Panel
<StyledCollapsePanel
{...props}
key={table.id}
header={renderHeader()}
@@ -295,7 +328,7 @@ const TableElement = ({ table, ...props }: TableElementProps) => {
forceRender
>
{renderBody()}
</Collapse.Panel>
</StyledCollapsePanel>
);
};