style: Pass at propagating (and enhancing) Button component throughout Superset (#10649)
* getting rid of weird focus/active outline ring
* Buttons... buttons _everywhere_
* linting
* Nixing views/CRUD/dataset/Button component
* fixing 2 typing errors
* fixing more TS errors
* prefer src path for include
* one more real button, one less CSS class
* one more "button" to "Button"
* Published Status is now a proper clickable Label
* nixing the CRUD button again
* touching up stories, with SupersetButton story
* SIP-34 button colors
* adding polished package to mix colors
* updating button colors to match Superset theme
* abstracting away from bootstrap-specific props (might pivot libraries soon!)
* more abstraction from bsStyle/bsSize props
* exchanging styles for a prop
* linting
* restoring feature flag to stock
* using src alias
* last <button> replacement
* this classname would never be applied
* more linting action
* fixing unsupported bsSize 'medium', and cta typing error
* more cta action
* unnecessary styles
* errant bsSize prop
* cleanup
* tweaks to make new New button work
* Linting
* fixing a couple tests
* fixing theme based test failure
* margin tweak for NEW button
* another fixed test
* another fixed test
* fixing two more tests
* fixing last broken tests.
* always be linting
* Adding tertiary/dashed buttons
* cleaning up QueryAndSave buttons
* fixing "link" button styles
* fixing/updating link button styles
* cta buttons on Modal component
* linting.
* exporting button story knobs, making ALL knobs safe for export.
* capitalizing a file... no big whoop
* Basic button tests
* renaming button - temporarily
* renaming file to fix capitalization issue
* passing theme through to a difficult popover.
* fixin' a newly busted unit test
* lint fixin'
* oops, shouldn't have changed this prop!
* adding a dive() to themedShallow, and fixing a cypress/jest test
* addressing lint stuff
* touching up stories, with SupersetButton story
* SIP-34 button colors
* updating button colors to match Superset theme
* abstracting away from bootstrap-specific props (might pivot libraries soon!)
* linting
* restoring feature flag to stock
* cleanup
* Linting
* renaming button - temporarily
* renaming file to fix capitalization issue
* oops, shouldn't have changed this prop!
* adding a dive() to themedShallow, and fixing a cypress/jest test
* addressing lint stuff
* nixing new modal button
* Fixing another popover/button issue that should break cypress
* lint ✨
* passing classNames through to new button (should fix some tests)
* cleaning unused classes, making cypress tests use data attrs
* fixin' the test
* fixing another class-based test with data-test attr
* no longer passing theme as prop to buttons in popovers... themeprovider is better
* outline/border tweaks!
This commit is contained in:
parent
33fa9ebff1
commit
9fe30ab71e
|
|
@ -40,7 +40,7 @@ describe('AdhocFilters', () => {
|
||||||
cy.get('button').contains('Save').click();
|
cy.get('button').contains('Save').click();
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.get('button.query').click();
|
cy.get('button[data-test="run-query-button"]').click();
|
||||||
cy.verifySliceSuccess({
|
cy.verifySliceSuccess({
|
||||||
waitAlias: '@postJson',
|
waitAlias: '@postJson',
|
||||||
chartSelector: 'svg',
|
chartSelector: 'svg',
|
||||||
|
|
@ -63,7 +63,7 @@ describe('AdhocFilters', () => {
|
||||||
cy.get('button').contains('Save').click();
|
cy.get('button').contains('Save').click();
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.get('button.query').click();
|
cy.get('button[data-test="run-query-button"]').click();
|
||||||
cy.verifySliceSuccess({
|
cy.verifySliceSuccess({
|
||||||
waitAlias: '@postJson',
|
waitAlias: '@postJson',
|
||||||
chartSelector: 'svg',
|
chartSelector: 'svg',
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ describe('AdhocMetrics', () => {
|
||||||
|
|
||||||
cy.get('.metrics-select .metric-option').contains(metricName);
|
cy.get('.metrics-select .metric-option').contains(metricName);
|
||||||
|
|
||||||
cy.get('button.query').click();
|
cy.get('button[data-test="run-query-button"]').click();
|
||||||
cy.verifySliceSuccess({
|
cy.verifySliceSuccess({
|
||||||
waitAlias: '@postJson',
|
waitAlias: '@postJson',
|
||||||
querySubstring: `${metric} AS "${metricName}"`, // SQL statement
|
querySubstring: `${metric} AS "${metricName}"`, // SQL statement
|
||||||
|
|
@ -77,7 +77,7 @@ describe('AdhocMetrics', () => {
|
||||||
.type('/COUNT(DISTINCT name)', { force: true });
|
.type('/COUNT(DISTINCT name)', { force: true });
|
||||||
cy.get('#metrics-edit-popover').find('button').contains('Save').click();
|
cy.get('#metrics-edit-popover').find('button').contains('Save').click();
|
||||||
|
|
||||||
cy.get('button.query').click();
|
cy.get('button[data-test="run-query-button"]').click();
|
||||||
|
|
||||||
const metric = 'SUM(num)/COUNT(DISTINCT name)';
|
const metric = 'SUM(num)/COUNT(DISTINCT name)';
|
||||||
cy.verifySliceSuccess({
|
cy.verifySliceSuccess({
|
||||||
|
|
@ -103,7 +103,7 @@ describe('AdhocMetrics', () => {
|
||||||
cy.get('button').contains('Save').click();
|
cy.get('button').contains('Save').click();
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.get('button.query').click();
|
cy.get('button[data-test="run-query-button"]').click();
|
||||||
|
|
||||||
const metric = 'SUM(num)';
|
const metric = 'SUM(num)';
|
||||||
cy.verifySliceSuccess({
|
cy.verifySliceSuccess({
|
||||||
|
|
@ -124,7 +124,7 @@ describe('AdhocMetrics', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const metric = 'AVG(sum_boys)';
|
const metric = 'AVG(sum_boys)';
|
||||||
cy.get('button.query').click();
|
cy.get('button[data-test="run-query-button"]').click();
|
||||||
cy.verifySliceSuccess({
|
cy.verifySliceSuccess({
|
||||||
waitAlias: '@postJson',
|
waitAlias: '@postJson',
|
||||||
querySubstring: `${metric} AS "${metric}"`,
|
querySubstring: `${metric} AS "${metric}"`,
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ describe('Advanced analytics', () => {
|
||||||
.find('.Select__multi-value__label')
|
.find('.Select__multi-value__label')
|
||||||
.contains('364 days');
|
.contains('364 days');
|
||||||
|
|
||||||
cy.get('button.query').click();
|
cy.get('button[data-test="run-query-button"]').click();
|
||||||
cy.wait('@postJson');
|
cy.wait('@postJson');
|
||||||
cy.reload();
|
cy.reload();
|
||||||
cy.verifySliceSuccess({
|
cy.verifySliceSuccess({
|
||||||
|
|
@ -90,7 +90,7 @@ describe('Annotations', () => {
|
||||||
cy.get('button').contains('OK').click();
|
cy.get('button').contains('OK').click();
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.get('button.query').click();
|
cy.get('button[data-test="run-query-button"]').click();
|
||||||
cy.verifySliceSuccess({
|
cy.verifySliceSuccess({
|
||||||
waitAlias: '@postJson',
|
waitAlias: '@postJson',
|
||||||
chartSelector: 'svg',
|
chartSelector: 'svg',
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ describe('Groupby control', () => {
|
||||||
cy.get('.Select__control').click();
|
cy.get('.Select__control').click();
|
||||||
cy.get('input[type=text]').type('state{enter}');
|
cy.get('input[type=text]').type('state{enter}');
|
||||||
});
|
});
|
||||||
cy.get('button.query').click();
|
cy.get('button[data-test="run-query-button"]').click();
|
||||||
cy.verifySliceSuccess({ waitAlias: '@postJson', chartSelector: 'svg' });
|
cy.verifySliceSuccess({ waitAlias: '@postJson', chartSelector: 'svg' });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -34830,16 +34830,14 @@
|
||||||
"version": "3.6.5",
|
"version": "3.6.5",
|
||||||
"resolved": "https://registry.npmjs.org/polished/-/polished-3.6.5.tgz",
|
"resolved": "https://registry.npmjs.org/polished/-/polished-3.6.5.tgz",
|
||||||
"integrity": "sha512-VwhC9MlhW7O5dg/z7k32dabcAFW1VI2+7fSe8cE/kXcfL7mVdoa5UxciYGW2sJU78ldDLT6+ROEKIZKFNTnUXQ==",
|
"integrity": "sha512-VwhC9MlhW7O5dg/z7k32dabcAFW1VI2+7fSe8cE/kXcfL7mVdoa5UxciYGW2sJU78ldDLT6+ROEKIZKFNTnUXQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/runtime": "^7.9.2"
|
"@babel/runtime": "^7.9.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": {
|
"@babel/runtime": {
|
||||||
"version": "7.10.5",
|
"version": "7.11.2",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.10.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz",
|
||||||
"integrity": "sha512-otddXKhdNn7d0ptoFRHtMLa8LqDxLYwTjB4nYgM1yy5N6gU/MUf8zqyyLltCH3yAVitBzmwK4us+DD0l/MauAg==",
|
"integrity": "sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"regenerator-runtime": "^0.13.4"
|
"regenerator-runtime": "^0.13.4"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,7 @@
|
||||||
"mousetrap": "^1.6.1",
|
"mousetrap": "^1.6.1",
|
||||||
"mustache": "^2.2.1",
|
"mustache": "^2.2.1",
|
||||||
"omnibar": "^2.1.1",
|
"omnibar": "^2.1.1",
|
||||||
|
"polished": "^3.6.5",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
"re-resizable": "^4.3.1",
|
"re-resizable": "^4.3.1",
|
||||||
"react": "^16.13.1",
|
"react": "^16.13.1",
|
||||||
|
|
|
||||||
|
|
@ -51,5 +51,5 @@ export function styledShallow(
|
||||||
theme: supersetTheme,
|
theme: supersetTheme,
|
||||||
...options?.wrappingComponentProps,
|
...options?.wrappingComponentProps,
|
||||||
},
|
},
|
||||||
});
|
}).dive();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow, ShallowWrapper } from 'enzyme';
|
import { shallow, ShallowWrapper } from 'enzyme';
|
||||||
import { Button } from 'react-bootstrap';
|
import Button from 'src/components/Button';
|
||||||
import Select from 'src/components/Select';
|
import Select from 'src/components/Select';
|
||||||
import AddSliceContainer, {
|
import AddSliceContainer, {
|
||||||
AddSliceContainerProps,
|
AddSliceContainerProps,
|
||||||
|
|
@ -58,9 +58,9 @@ describe('AddSliceContainer', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders a disabled button if no datasource is selected', () => {
|
it('renders a disabled button if no datasource is selected', () => {
|
||||||
expect(
|
expect(wrapper.find(Button).dive().find({ disabled: true })).toHaveLength(
|
||||||
wrapper.find(Button).dive().find('.btn[disabled=true]'),
|
1,
|
||||||
).toHaveLength(1);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders an enabled button if datasource is selected', () => {
|
it('renders an enabled button if datasource is selected', () => {
|
||||||
|
|
@ -70,9 +70,9 @@ describe('AddSliceContainer', () => {
|
||||||
datasourceId: datasourceValue.split('__')[0],
|
datasourceId: datasourceValue.split('__')[0],
|
||||||
datasourceType: datasourceValue.split('__')[1],
|
datasourceType: datasourceValue.split('__')[1],
|
||||||
});
|
});
|
||||||
expect(
|
expect(wrapper.find(Button).dive().find({ disabled: true })).toHaveLength(
|
||||||
wrapper.find(Button).dive().find('.btn[disabled=false]'),
|
0,
|
||||||
).toHaveLength(1);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('formats explore url', () => {
|
it('formats explore url', () => {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { mount } from 'enzyme';
|
import { mount } from 'enzyme';
|
||||||
import { Button } from 'react-bootstrap';
|
import Button from 'src/components/Button';
|
||||||
import { supersetTheme, ThemeProvider } from '@superset-ui/style';
|
import { supersetTheme, ThemeProvider } from '@superset-ui/style';
|
||||||
import ConfirmStatusChange from 'src/components/ConfirmStatusChange';
|
import ConfirmStatusChange from 'src/components/ConfirmStatusChange';
|
||||||
import Modal from 'src/components/Modal';
|
import Modal from 'src/components/Modal';
|
||||||
|
|
@ -33,7 +33,7 @@ describe('ConfirmStatusChange', () => {
|
||||||
<ConfirmStatusChange {...mockedProps}>
|
<ConfirmStatusChange {...mockedProps}>
|
||||||
{confirm => (
|
{confirm => (
|
||||||
<>
|
<>
|
||||||
<button id="btn1" onClick={confirm} />
|
<Button id="btn1" onClick={confirm} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</ConfirmStatusChange>,
|
</ConfirmStatusChange>,
|
||||||
|
|
@ -44,7 +44,7 @@ describe('ConfirmStatusChange', () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
it('opens a confirm modal', () => {
|
it('opens a confirm modal', () => {
|
||||||
wrapper.find('#btn1').props().onClick('foo');
|
wrapper.find('#btn1').first().props().onClick('foo');
|
||||||
|
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
*/
|
*/
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { mount } from 'enzyme';
|
import { styledMount as mount } from 'spec/helpers/theming';
|
||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
|
|
||||||
import DashboardComponent from 'src/dashboard/containers/DashboardComponent';
|
import DashboardComponent from 'src/dashboard/containers/DashboardComponent';
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,10 @@ describe('DatasourceModal', () => {
|
||||||
|
|
||||||
it('saves on confirm', async () => {
|
it('saves on confirm', async () => {
|
||||||
act(() => {
|
act(() => {
|
||||||
wrapper.find('[className="m-r-5"]').props().onClick();
|
wrapper
|
||||||
|
.find('button[data-test="datasource-modal-save"]')
|
||||||
|
.props()
|
||||||
|
.onClick();
|
||||||
});
|
});
|
||||||
await waitForComponentToPaint(wrapper);
|
await waitForComponentToPaint(wrapper);
|
||||||
act(() => {
|
act(() => {
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from 'enzyme';
|
||||||
import { Button, Popover, Tab, Tabs } from 'react-bootstrap';
|
import { Popover, Tab, Tabs } from 'react-bootstrap';
|
||||||
|
import Button from 'src/components/Button';
|
||||||
|
|
||||||
import AdhocFilter, {
|
import AdhocFilter, {
|
||||||
EXPRESSION_TYPES,
|
EXPRESSION_TYPES,
|
||||||
|
|
@ -117,9 +118,9 @@ describe('AdhocFilterEditPopover', () => {
|
||||||
|
|
||||||
it('highlights save if changes are present', () => {
|
it('highlights save if changes are present', () => {
|
||||||
const { wrapper } = setup();
|
const { wrapper } = setup();
|
||||||
expect(wrapper.find(Button).find({ bsStyle: 'primary' })).not.toExist();
|
expect(wrapper.find(Button).find({ buttonStyle: 'primary' })).not.toExist();
|
||||||
wrapper.instance().onAdhocFilterChange(sqlAdhocFilter);
|
wrapper.instance().onAdhocFilterChange(sqlAdhocFilter);
|
||||||
expect(wrapper.find(Button).find({ bsStyle: 'primary' })).toExist();
|
expect(wrapper.find(Button).find({ buttonStyle: 'primary' })).toExist();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('will initiate a drag when clicked', () => {
|
it('will initiate a drag when clicked', () => {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
/* eslint-disable no-unused-expressions */
|
/* eslint-disable no-unused-expressions */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
import { shallow } from 'enzyme';
|
import { styledShallow as shallow } from 'spec/helpers/theming';
|
||||||
import { OverlayTrigger } from 'react-bootstrap';
|
import { OverlayTrigger } from 'react-bootstrap';
|
||||||
|
|
||||||
import Label from 'src/components/Label';
|
import Label from 'src/components/Label';
|
||||||
|
|
@ -46,7 +46,7 @@ function setup(overrides) {
|
||||||
datasource: {},
|
datasource: {},
|
||||||
...overrides,
|
...overrides,
|
||||||
};
|
};
|
||||||
const wrapper = shallow(<AdhocFilterOption {...props} />);
|
const wrapper = shallow(<AdhocFilterOption {...props} />).dive();
|
||||||
return { wrapper };
|
return { wrapper };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from 'enzyme';
|
||||||
import { Button, FormGroup, Popover } from 'react-bootstrap';
|
import { FormGroup, Popover } from 'react-bootstrap';
|
||||||
|
import Button from 'src/components/Button';
|
||||||
|
|
||||||
import AdhocMetric, { EXPRESSION_TYPES } from 'src/explore/AdhocMetric';
|
import AdhocMetric, { EXPRESSION_TYPES } from 'src/explore/AdhocMetric';
|
||||||
import AdhocMetricEditPopover from 'src/explore/components/AdhocMetricEditPopover';
|
import AdhocMetricEditPopover from 'src/explore/components/AdhocMetricEditPopover';
|
||||||
|
|
@ -117,9 +118,9 @@ describe('AdhocMetricEditPopover', () => {
|
||||||
|
|
||||||
it('highlights save if changes are present', () => {
|
it('highlights save if changes are present', () => {
|
||||||
const { wrapper } = setup();
|
const { wrapper } = setup();
|
||||||
expect(wrapper.find(Button).find({ bsStyle: 'primary' })).not.toExist();
|
expect(wrapper.find(Button).find({ buttonStyle: 'primary' })).not.toExist();
|
||||||
wrapper.instance().onColumnChange({ column: columns[1] });
|
wrapper.instance().onColumnChange({ column: columns[1] });
|
||||||
expect(wrapper.find(Button).find({ bsStyle: 'primary' })).toExist();
|
expect(wrapper.find(Button).find({ buttonStyle: 'primary' })).toExist();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('will initiate a drag when clicked', () => {
|
it('will initiate a drag when clicked', () => {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
/* eslint-disable no-unused-expressions */
|
/* eslint-disable no-unused-expressions */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
import { shallow } from 'enzyme';
|
import { styledShallow as shallow } from 'spec/helpers/theming';
|
||||||
import { OverlayTrigger } from 'react-bootstrap';
|
import { OverlayTrigger } from 'react-bootstrap';
|
||||||
|
|
||||||
import Label from 'src/components/Label';
|
import Label from 'src/components/Label';
|
||||||
|
|
@ -46,7 +46,7 @@ function setup(overrides) {
|
||||||
columns,
|
columns,
|
||||||
...overrides,
|
...overrides,
|
||||||
};
|
};
|
||||||
const wrapper = shallow(<AdhocMetricOption {...props} />);
|
const wrapper = shallow(<AdhocMetricOption {...props} />).dive();
|
||||||
return { wrapper, onMetricEdit };
|
return { wrapper, onMetricEdit };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
import { styledMount as mount } from 'spec/helpers/theming';
|
import { styledMount as mount } from 'spec/helpers/theming';
|
||||||
import { Button } from 'react-bootstrap';
|
import Button from 'src/components/Button';
|
||||||
|
|
||||||
import Label from 'src/components/Label';
|
import Label from 'src/components/Label';
|
||||||
import DateFilterControl from 'src/explore/components/controls/DateFilterControl';
|
import DateFilterControl from 'src/explore/components/controls/DateFilterControl';
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ describe('QueryAndSaveButtons', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('calls onQuery when query button is clicked', () => {
|
it('calls onQuery when query button is clicked', () => {
|
||||||
const queryButton = wrapper.find('.query');
|
const queryButton = wrapper.find('[data-test="run-query-button"]');
|
||||||
queryButton.simulate('click');
|
queryButton.simulate('click');
|
||||||
expect(defaultProps.onQuery.called).toBe(true);
|
expect(defaultProps.onQuery.called).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,10 @@ import configureStore from 'redux-mock-store';
|
||||||
import thunk from 'redux-thunk';
|
import thunk from 'redux-thunk';
|
||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
|
|
||||||
import { shallow, mount } from 'enzyme';
|
import { shallow } from 'enzyme';
|
||||||
import { FormControl, Modal, Button, Radio } from 'react-bootstrap';
|
import { styledMount as mount } from 'spec/helpers/theming';
|
||||||
|
import { FormControl, Modal, Radio } from 'react-bootstrap';
|
||||||
|
import Button from 'src/components/Button';
|
||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
import fetchMock from 'fetch-mock';
|
import fetchMock from 'fetch-mock';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Button } from 'react-bootstrap';
|
import Button from 'src/components/Button';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from 'enzyme';
|
||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ describe('SouthPane', () => {
|
||||||
const getWrapper = () =>
|
const getWrapper = () =>
|
||||||
shallow(<SouthPaneContainer {...mockedProps} />, {
|
shallow(<SouthPaneContainer {...mockedProps} />, {
|
||||||
context: { store },
|
context: { store },
|
||||||
}).dive();
|
});
|
||||||
|
|
||||||
let wrapper;
|
let wrapper;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
import React, { ReactNode } from 'react';
|
import React, { ReactNode } from 'react';
|
||||||
import shortid from 'shortid';
|
import shortid from 'shortid';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
import Button from '../components/Button';
|
import Button from 'src/components/Button';
|
||||||
import Fieldset from './Fieldset';
|
import Fieldset from './Fieldset';
|
||||||
import { recurseReactClone } from './utils';
|
import { recurseReactClone } from './utils';
|
||||||
import './crud.less';
|
import './crud.less';
|
||||||
|
|
@ -167,7 +167,7 @@ export default class CRUDCollection extends React.PureComponent<
|
||||||
{allowDeletes && !allowAddItem && <th className="tiny-cell" />}
|
{allowDeletes && !allowAddItem && <th className="tiny-cell" />}
|
||||||
{allowAddItem && (
|
{allowAddItem && (
|
||||||
<th>
|
<th>
|
||||||
<Button bsStyle="primary" onClick={this.onAddItem}>
|
<Button buttonStyle="primary" onClick={this.onAddItem}>
|
||||||
<i className="fa fa-plus" /> {t('Add Item')}
|
<i className="fa fa-plus" /> {t('Add Item')}
|
||||||
</Button>
|
</Button>
|
||||||
</th>
|
</th>
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import { Table } from 'reactable-arc';
|
||||||
import { Alert } from 'react-bootstrap';
|
import { Alert } from 'react-bootstrap';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
|
|
||||||
import Button from '../../components/Button';
|
import Button from 'src/components/Button';
|
||||||
import Loading from '../../components/Loading';
|
import Loading from '../../components/Loading';
|
||||||
import ModalTrigger from '../../components/ModalTrigger';
|
import ModalTrigger from '../../components/ModalTrigger';
|
||||||
|
|
||||||
|
|
@ -85,8 +85,8 @@ class EstimateQueryCostButton extends React.PureComponent {
|
||||||
modalBody={this.renderModalBody()}
|
modalBody={this.renderModalBody()}
|
||||||
triggerNode={
|
triggerNode={
|
||||||
<Button
|
<Button
|
||||||
bsStyle="warning"
|
buttonStyle="warning"
|
||||||
bsSize="small"
|
buttonSize="small"
|
||||||
onClick={this.onClick}
|
onClick={this.onClick}
|
||||||
key="query-estimate-btn"
|
key="query-estimate-btn"
|
||||||
tooltip={tooltip}
|
tooltip={tooltip}
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,9 @@ import Dialog from 'react-bootstrap-dialog';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
|
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
|
||||||
|
|
||||||
|
import Button from 'src/components/Button';
|
||||||
import { exploreChart } from '../../explore/exploreUtils';
|
import { exploreChart } from '../../explore/exploreUtils';
|
||||||
import * as actions from '../actions/sqlLab';
|
import * as actions from '../actions/sqlLab';
|
||||||
import Button from '../../components/Button';
|
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
actions: PropTypes.object.isRequired,
|
actions: PropTypes.object.isRequired,
|
||||||
|
|
@ -89,7 +89,7 @@ class ExploreCtasResultsButton extends React.PureComponent {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
bsSize="small"
|
buttonSize="small"
|
||||||
onClick={this.onClick}
|
onClick={this.onClick}
|
||||||
tooltip={t('Explore the result set in the data exploration view')}
|
tooltip={t('Explore the result set in the data exploration view')}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,11 @@ import { Alert } from 'react-bootstrap';
|
||||||
import Dialog from 'react-bootstrap-dialog';
|
import Dialog from 'react-bootstrap-dialog';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
|
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
|
||||||
|
|
||||||
import shortid from 'shortid';
|
import shortid from 'shortid';
|
||||||
|
|
||||||
|
import Button from 'src/components/Button';
|
||||||
import { exploreChart } from '../../explore/exploreUtils';
|
import { exploreChart } from '../../explore/exploreUtils';
|
||||||
import * as actions from '../actions/sqlLab';
|
import * as actions from '../actions/sqlLab';
|
||||||
import Button from '../../components/Button';
|
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
actions: PropTypes.object.isRequired,
|
actions: PropTypes.object.isRequired,
|
||||||
|
|
@ -213,7 +213,7 @@ class ExploreResultsButton extends React.PureComponent {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
bsSize="small"
|
buttonSize="small"
|
||||||
onClick={this.onClick}
|
onClick={this.onClick}
|
||||||
disabled={!allowsSubquery}
|
disabled={!allowsSubquery}
|
||||||
tooltip={t('Explore the result set in the data exploration view')}
|
tooltip={t('Explore the result set in the data exploration view')}
|
||||||
|
|
|
||||||
|
|
@ -17,13 +17,8 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {
|
import { FormGroup, FormControl, Overlay, Popover } from 'react-bootstrap';
|
||||||
Button,
|
import Button from 'src/components/Button';
|
||||||
FormGroup,
|
|
||||||
FormControl,
|
|
||||||
Overlay,
|
|
||||||
Popover,
|
|
||||||
} from 'react-bootstrap';
|
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
import styled from '@superset-ui/style';
|
import styled from '@superset-ui/style';
|
||||||
|
|
||||||
|
|
@ -119,8 +114,8 @@ export default class LimitControl extends React.PureComponent<
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<div className="clearfix">
|
<div className="clearfix">
|
||||||
<Button
|
<Button
|
||||||
bsSize="small"
|
buttonSize="small"
|
||||||
bsStyle="primary"
|
buttonStyle="primary"
|
||||||
className="float-right ok m-l-5"
|
className="float-right ok m-l-5"
|
||||||
disabled={!isValid}
|
disabled={!isValid}
|
||||||
onClick={this.submitAndClose}
|
onClick={this.submitAndClose}
|
||||||
|
|
@ -128,7 +123,7 @@ export default class LimitControl extends React.PureComponent<
|
||||||
{t('Ok')}
|
{t('Ok')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
bsSize="small"
|
buttonSize="small"
|
||||||
className="float-right reset"
|
className="float-right reset"
|
||||||
onClick={this.setValueAndClose.bind(
|
onClick={this.setValueAndClose.bind(
|
||||||
this,
|
this,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Button } from 'react-bootstrap';
|
import Button from 'src/components/Button';
|
||||||
import Select from 'src/components/Select';
|
import Select from 'src/components/Select';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
import { SupersetClient } from '@superset-ui/connection';
|
import { SupersetClient } from '@superset-ui/connection';
|
||||||
|
|
@ -273,8 +273,8 @@ class QuerySearch extends React.PureComponent {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
bsSize="small"
|
buttonSize="small"
|
||||||
bsStyle="success"
|
buttonStyle="success"
|
||||||
onClick={this.refreshQueries}
|
onClick={this.refreshQueries}
|
||||||
>
|
>
|
||||||
{t('Search')}
|
{t('Search')}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import { ProgressBar, Well } from 'react-bootstrap';
|
||||||
import Label from 'src/components/Label';
|
import Label from 'src/components/Label';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
|
|
||||||
|
import Button from 'src/components/Button';
|
||||||
import Link from '../../components/Link';
|
import Link from '../../components/Link';
|
||||||
import ResultSet from './ResultSet';
|
import ResultSet from './ResultSet';
|
||||||
import ModalTrigger from '../../components/ModalTrigger';
|
import ModalTrigger from '../../components/ModalTrigger';
|
||||||
|
|
@ -99,31 +100,34 @@ class QueryTable extends React.PureComponent {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
q.user = (
|
q.user = (
|
||||||
<button
|
<Button
|
||||||
className="btn btn-link btn-xs"
|
buttonSize="small"
|
||||||
|
buttonStyle="link"
|
||||||
onClick={this.props.onUserClicked.bind(this, q.userId)}
|
onClick={this.props.onUserClicked.bind(this, q.userId)}
|
||||||
>
|
>
|
||||||
{q.user}
|
{q.user}
|
||||||
</button>
|
</Button>
|
||||||
);
|
);
|
||||||
q.db = (
|
q.db = (
|
||||||
<button
|
<Button
|
||||||
className="btn btn-link btn-xs"
|
buttonSize="small"
|
||||||
|
buttonStyle="link"
|
||||||
onClick={this.props.onDbClicked.bind(this, q.dbId)}
|
onClick={this.props.onDbClicked.bind(this, q.dbId)}
|
||||||
>
|
>
|
||||||
{q.db}
|
{q.db}
|
||||||
</button>
|
</Button>
|
||||||
);
|
);
|
||||||
q.started = moment(q.startDttm).format('HH:mm:ss');
|
q.started = moment(q.startDttm).format('HH:mm:ss');
|
||||||
q.querylink = (
|
q.querylink = (
|
||||||
<div style={{ width: '100px' }}>
|
<div style={{ width: '100px' }}>
|
||||||
<button
|
<Button
|
||||||
className="btn btn-link btn-xs"
|
buttonSize="small"
|
||||||
|
buttonStyle="link"
|
||||||
onClick={this.openQuery.bind(this, q.queryId)}
|
onClick={this.openQuery.bind(this, q.queryId)}
|
||||||
>
|
>
|
||||||
<i className="fa fa-external-link m-r-3" />
|
<i className="fa fa-external-link m-r-3" />
|
||||||
{t('Edit')}
|
{t('Edit')}
|
||||||
</button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
q.sql = (
|
q.sql = (
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import React, { CSSProperties } from 'react';
|
import React, { CSSProperties } from 'react';
|
||||||
import { Alert, Button, ButtonGroup, ProgressBar } from 'react-bootstrap';
|
import { Alert, ButtonGroup, ProgressBar } from 'react-bootstrap';
|
||||||
|
import Button from 'src/components/Button';
|
||||||
import shortid from 'shortid';
|
import shortid from 'shortid';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
|
|
||||||
|
|
@ -166,7 +167,7 @@ export default class ResultSet extends React.PureComponent<
|
||||||
)}
|
)}
|
||||||
{this.props.csv && (
|
{this.props.csv && (
|
||||||
<Button
|
<Button
|
||||||
bsSize="small"
|
buttonSize="small"
|
||||||
href={`/superset/csv/${this.props.query.id}`}
|
href={`/superset/csv/${this.props.query.id}`}
|
||||||
>
|
>
|
||||||
<i className="fa fa-file-text-o" /> {t('.CSV')}
|
<i className="fa fa-file-text-o" /> {t('.CSV')}
|
||||||
|
|
@ -177,7 +178,7 @@ export default class ResultSet extends React.PureComponent<
|
||||||
text={prepareCopyToClipboardTabularData(data)}
|
text={prepareCopyToClipboardTabularData(data)}
|
||||||
wrapped={false}
|
wrapped={false}
|
||||||
copyNode={
|
copyNode={
|
||||||
<Button bsSize="small">
|
<Button buttonSize="small">
|
||||||
<i className="fa fa-clipboard" /> {t('Clipboard')}
|
<i className="fa fa-clipboard" /> {t('Clipboard')}
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
|
|
@ -243,7 +244,7 @@ export default class ResultSet extends React.PureComponent<
|
||||||
] {t('was created')}
|
] {t('was created')}
|
||||||
<ButtonGroup>
|
<ButtonGroup>
|
||||||
<Button
|
<Button
|
||||||
bsSize="small"
|
buttonSize="small"
|
||||||
className="m-r-5"
|
className="m-r-5"
|
||||||
onClick={() => this.popSelectStar(tempSchema, tempTable)}
|
onClick={() => this.popSelectStar(tempSchema, tempTable)}
|
||||||
>
|
>
|
||||||
|
|
@ -296,9 +297,9 @@ export default class ResultSet extends React.PureComponent<
|
||||||
if (query.isDataPreview) {
|
if (query.isDataPreview) {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
bsSize="sm"
|
buttonSize="sm"
|
||||||
className="fetch"
|
className="fetch"
|
||||||
bsStyle="primary"
|
buttonStyle="primary"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
this.reFetchQueryResults({
|
this.reFetchQueryResults({
|
||||||
...query,
|
...query,
|
||||||
|
|
@ -312,9 +313,9 @@ export default class ResultSet extends React.PureComponent<
|
||||||
} else if (query.resultsKey) {
|
} else if (query.resultsKey) {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
bsSize="sm"
|
buttonSize="sm"
|
||||||
className="fetch"
|
className="fetch"
|
||||||
bsStyle="primary"
|
buttonStyle="primary"
|
||||||
onClick={() => this.fetchResults(query)}
|
onClick={() => this.fetchResults(query)}
|
||||||
>
|
>
|
||||||
{t('Refetch Results')}
|
{t('Refetch Results')}
|
||||||
|
|
@ -336,7 +337,7 @@ export default class ResultSet extends React.PureComponent<
|
||||||
if (query.trackingUrl) {
|
if (query.trackingUrl) {
|
||||||
trackingUrl = (
|
trackingUrl = (
|
||||||
<Button
|
<Button
|
||||||
bsSize="small"
|
buttonSize="small"
|
||||||
onClick={() => query.trackingUrl && window.open(query.trackingUrl)}
|
onClick={() => query.trackingUrl && window.open(query.trackingUrl)}
|
||||||
>
|
>
|
||||||
{t('Track Job')}
|
{t('Track Job')}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
|
|
||||||
import Button, { ButtonProps } from '../../components/Button';
|
import Button, { ButtonProps } from 'src/components/Button';
|
||||||
|
|
||||||
const NO_OP = () => undefined;
|
const NO_OP = () => undefined;
|
||||||
|
|
||||||
|
|
@ -32,9 +32,6 @@ interface Props {
|
||||||
stopQuery: () => void;
|
stopQuery: () => void;
|
||||||
sql: string;
|
sql: string;
|
||||||
}
|
}
|
||||||
const commonBtnStyle = {
|
|
||||||
width: '140px',
|
|
||||||
};
|
|
||||||
|
|
||||||
const RunQueryActionButton = ({
|
const RunQueryActionButton = ({
|
||||||
allowAsync = false,
|
allowAsync = false,
|
||||||
|
|
@ -51,15 +48,14 @@ const RunQueryActionButton = ({
|
||||||
!!queryState && ['running', 'pending'].indexOf(queryState) > -1;
|
!!queryState && ['running', 'pending'].indexOf(queryState) > -1;
|
||||||
|
|
||||||
const commonBtnProps: ButtonProps = {
|
const commonBtnProps: ButtonProps = {
|
||||||
bsSize: 'small',
|
buttonSize: 'small',
|
||||||
bsStyle: btnStyle,
|
buttonStyle: btnStyle,
|
||||||
disabled: !dbId,
|
disabled: !dbId,
|
||||||
style: commonBtnStyle,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (shouldShowStopBtn) {
|
if (shouldShowStopBtn) {
|
||||||
return (
|
return (
|
||||||
<Button {...commonBtnProps} onClick={stopQuery}>
|
<Button {...commonBtnProps} cta onClick={stopQuery}>
|
||||||
<i className="fa fa-stop" /> {t('Stop')}
|
<i className="fa fa-stop" /> {t('Stop')}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
|
@ -67,6 +63,7 @@ const RunQueryActionButton = ({
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
{...commonBtnProps}
|
{...commonBtnProps}
|
||||||
|
cta
|
||||||
onClick={() => runQuery(true)}
|
onClick={() => runQuery(true)}
|
||||||
key="run-async-btn"
|
key="run-async-btn"
|
||||||
tooltip={t('Run query asynchronously (Ctrl + ↵)')}
|
tooltip={t('Run query asynchronously (Ctrl + ↵)')}
|
||||||
|
|
@ -79,6 +76,7 @@ const RunQueryActionButton = ({
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
{...commonBtnProps}
|
{...commonBtnProps}
|
||||||
|
cta
|
||||||
onClick={() => runQuery(false)}
|
onClick={() => runQuery(false)}
|
||||||
key="run-btn"
|
key="run-btn"
|
||||||
tooltip={t('Run query synchronously (Ctrl + ↵)')}
|
tooltip={t('Run query synchronously (Ctrl + ↵)')}
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ class SaveQuery extends React.PureComponent {
|
||||||
<Col md={12}>
|
<Col md={12}>
|
||||||
{isSaved && (
|
{isSaved && (
|
||||||
<Button
|
<Button
|
||||||
bsStyle="primary"
|
buttonStyle="primary"
|
||||||
onClick={this.onUpdate}
|
onClick={this.onUpdate}
|
||||||
className="m-r-3"
|
className="m-r-3"
|
||||||
>
|
>
|
||||||
|
|
@ -143,7 +143,7 @@ class SaveQuery extends React.PureComponent {
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
<Button
|
<Button
|
||||||
bsStyle={isSaved ? undefined : 'primary'}
|
buttonStyle={isSaved ? undefined : 'primary'}
|
||||||
onClick={this.onSave}
|
onClick={this.onSave}
|
||||||
className="m-r-3"
|
className="m-r-3"
|
||||||
>
|
>
|
||||||
|
|
@ -169,7 +169,7 @@ class SaveQuery extends React.PureComponent {
|
||||||
backdrop="static"
|
backdrop="static"
|
||||||
triggerNode={
|
triggerNode={
|
||||||
<Button
|
<Button
|
||||||
bsSize="small"
|
buttonSize="small"
|
||||||
className="toggleSave"
|
className="toggleSave"
|
||||||
onClick={this.toggleSave}
|
onClick={this.toggleSave}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -192,7 +192,7 @@ class ScheduleQueryButton extends React.PureComponent {
|
||||||
modalBody={this.renderModalBody()}
|
modalBody={this.renderModalBody()}
|
||||||
triggerNode={
|
triggerNode={
|
||||||
<Button
|
<Button
|
||||||
bsSize="small"
|
buttonSize="small"
|
||||||
className="toggleSchedule"
|
className="toggleSchedule"
|
||||||
onClick={this.toggleSchedule}
|
onClick={this.toggleSchedule}
|
||||||
disabled={this.props.disabled}
|
disabled={this.props.disabled}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import { Popover, OverlayTrigger } from 'react-bootstrap';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags';
|
import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags';
|
||||||
|
|
||||||
import Button from '../../components/Button';
|
import Button from 'src/components/Button';
|
||||||
import CopyToClipboard from '../../components/CopyToClipboard';
|
import CopyToClipboard from '../../components/CopyToClipboard';
|
||||||
import { storeQuery } from '../../utils/common';
|
import { storeQuery } from '../../utils/common';
|
||||||
import getClientErrorObject from '../../utils/getClientErrorObject';
|
import getClientErrorObject from '../../utils/getClientErrorObject';
|
||||||
|
|
@ -110,7 +110,7 @@ class ShareSqlLabQuery extends React.Component {
|
||||||
shouldUpdatePosition
|
shouldUpdatePosition
|
||||||
overlay={this.renderPopover()}
|
overlay={this.renderPopover()}
|
||||||
>
|
>
|
||||||
<Button bsSize="small" className="toggleSave">
|
<Button buttonSize="small" className="toggleSave">
|
||||||
<i className="fa fa-share" /> {t('Share')}
|
<i className="fa fa-share" /> {t('Share')}
|
||||||
</Button>
|
</Button>
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
|
|
|
||||||
|
|
@ -398,7 +398,7 @@ class SqlEditor extends React.PureComponent {
|
||||||
<InputGroup.Button>
|
<InputGroup.Button>
|
||||||
{this.props.database.allow_ctas && (
|
{this.props.database.allow_ctas && (
|
||||||
<Button
|
<Button
|
||||||
bsSize="small"
|
buttonSize="small"
|
||||||
disabled={this.state.ctas.length === 0}
|
disabled={this.state.ctas.length === 0}
|
||||||
onClick={this.createTableAs.bind(this)}
|
onClick={this.createTableAs.bind(this)}
|
||||||
tooltip={ctasToolTip}
|
tooltip={ctasToolTip}
|
||||||
|
|
@ -408,7 +408,7 @@ class SqlEditor extends React.PureComponent {
|
||||||
)}
|
)}
|
||||||
{this.props.database.allow_cvas && (
|
{this.props.database.allow_cvas && (
|
||||||
<Button
|
<Button
|
||||||
bsSize="small"
|
buttonSize="small"
|
||||||
disabled={this.state.ctas.length === 0}
|
disabled={this.state.ctas.length === 0}
|
||||||
onClick={this.createViewAs.bind(this)}
|
onClick={this.createViewAs.bind(this)}
|
||||||
tooltip={cvasToolTip}
|
tooltip={cvasToolTip}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Button } from 'react-bootstrap';
|
import Button from 'src/components/Button';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
import TableElement from './TableElement';
|
import TableElement from './TableElement';
|
||||||
import TableSelector from '../../components/TableSelector';
|
import TableSelector from '../../components/TableSelector';
|
||||||
|
|
@ -140,7 +140,11 @@ export default class SqlEditorLeftBar extends React.PureComponent {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{shouldShowReset && (
|
{shouldShowReset && (
|
||||||
<Button bsSize="small" bsStyle="danger" onClick={this.resetState}>
|
<Button
|
||||||
|
buttonSize="small"
|
||||||
|
buttonStyle="danger"
|
||||||
|
onClick={this.resetState}
|
||||||
|
>
|
||||||
<i className="fa fa-bomb" /> {t('Reset State')}
|
<i className="fa fa-bomb" /> {t('Reset State')}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,8 @@ import 'brace/theme/textmate';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
|
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
|
||||||
|
|
||||||
|
import Button from 'src/components/Button';
|
||||||
import ModalTrigger from '../../components/ModalTrigger';
|
import ModalTrigger from '../../components/ModalTrigger';
|
||||||
import Button from '../../components/Button';
|
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
onChange: PropTypes.func,
|
onChange: PropTypes.func,
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Button, Panel } from 'react-bootstrap';
|
import { Panel } from 'react-bootstrap';
|
||||||
|
import Button from 'src/components/Button';
|
||||||
import Select from 'src/components/Select';
|
import Select from 'src/components/Select';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
|
|
||||||
|
|
@ -142,7 +143,7 @@ export default class AddSliceContainer extends React.PureComponent<
|
||||||
<br />
|
<br />
|
||||||
<hr />
|
<hr />
|
||||||
<Button
|
<Button
|
||||||
bsStyle="primary"
|
buttonStyle="primary"
|
||||||
disabled={this.isBtnDisabled()}
|
disabled={this.isBtnDisabled()}
|
||||||
onClick={this.gotoSlice}
|
onClick={this.gotoSlice}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import React from 'react';
|
||||||
import styled from '@superset-ui/style';
|
import styled from '@superset-ui/style';
|
||||||
import { Modal as BaseModal } from 'src/common/components';
|
import { Modal as BaseModal } from 'src/common/components';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
import Button from 'src/views/CRUD/data/dataset/Button';
|
import Button from 'src/components/Button';
|
||||||
|
|
||||||
interface ModalProps {
|
interface ModalProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
|
|
|
||||||
|
|
@ -25,13 +25,16 @@ export default {
|
||||||
title: 'Button',
|
title: 'Button',
|
||||||
component: Button,
|
component: Button,
|
||||||
decorators: [withKnobs],
|
decorators: [withKnobs],
|
||||||
|
excludeStories: /.*Knob$/,
|
||||||
};
|
};
|
||||||
|
|
||||||
const bsStyleKnob = {
|
export const buttonStyleKnob = {
|
||||||
label: 'Types',
|
label: 'Types',
|
||||||
options: {
|
options: {
|
||||||
Primary: 'primary',
|
Primary: 'primary',
|
||||||
Secondary: 'secondary',
|
Secondary: 'secondary',
|
||||||
|
Tertiary: 'tertiary',
|
||||||
|
Dashed: 'dashed',
|
||||||
Danger: 'danger',
|
Danger: 'danger',
|
||||||
Warning: 'warning',
|
Warning: 'warning',
|
||||||
Success: 'success',
|
Success: 'success',
|
||||||
|
|
@ -42,17 +45,18 @@ const bsStyleKnob = {
|
||||||
defaultValue: null,
|
defaultValue: null,
|
||||||
// groupId: 'ButtonType',
|
// groupId: 'ButtonType',
|
||||||
};
|
};
|
||||||
const bsSizeKnob = {
|
|
||||||
|
export const buttonSizeKnob = {
|
||||||
label: 'Sizes',
|
label: 'Sizes',
|
||||||
options: {
|
options: {
|
||||||
XS: 'xsmall',
|
XS: 'xsmall',
|
||||||
S: 'small',
|
S: 'small',
|
||||||
M: 'medium',
|
Default: null,
|
||||||
L: 'large',
|
L: 'large',
|
||||||
None: null,
|
|
||||||
},
|
},
|
||||||
defaultValue: null,
|
defaultValue: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO remove the use of these in the codebase where they're not necessary
|
// TODO remove the use of these in the codebase where they're not necessary
|
||||||
// const classKnob = {
|
// const classKnob = {
|
||||||
// label: 'Known Classes',
|
// label: 'Known Classes',
|
||||||
|
|
@ -62,7 +66,6 @@ const bsSizeKnob = {
|
||||||
// Reset: 'reset',
|
// Reset: 'reset',
|
||||||
// Fetch: 'fetch',
|
// Fetch: 'fetch',
|
||||||
// Query: 'query',
|
// Query: 'query',
|
||||||
// saveBtn: 'save-btn',
|
|
||||||
// MR3: 'm-r-3',
|
// MR3: 'm-r-3',
|
||||||
// cancelQuery: 'cancelQuery',
|
// cancelQuery: 'cancelQuery',
|
||||||
// toggleSave: 'toggleSave',
|
// toggleSave: 'toggleSave',
|
||||||
|
|
@ -101,43 +104,43 @@ const hrefKnob = {
|
||||||
|
|
||||||
export const ButtonGallery = () => (
|
export const ButtonGallery = () => (
|
||||||
<>
|
<>
|
||||||
{Object.values(bsSizeKnob.options)
|
{Object.entries(buttonSizeKnob.options).map(([name, size]) => (
|
||||||
.filter(a => a)
|
<div key={size}>
|
||||||
.map(size => (
|
<h4>{name}</h4>
|
||||||
<div>
|
{Object.values(buttonStyleKnob.options)
|
||||||
<h4>{size}</h4>
|
.filter(o => o)
|
||||||
{Object.values(bsStyleKnob.options)
|
.map(style => (
|
||||||
.filter(o => o)
|
<Button
|
||||||
.map(style => (
|
disabled={boolean('Disabled', false)}
|
||||||
<Button
|
cta={boolean('CTA', false)}
|
||||||
disabled={boolean('Disabled', false)}
|
buttonStyle={style}
|
||||||
bsStyle={style}
|
buttonSize={size}
|
||||||
bsSize={size}
|
onClick={action('clicked')}
|
||||||
onClick={action('clicked')}
|
key={`${style}_${size}`}
|
||||||
style={{ marginRight: 5 }}
|
>
|
||||||
>
|
{style}
|
||||||
{style}
|
</Button>
|
||||||
</Button>
|
))}
|
||||||
))}
|
</div>
|
||||||
</div>
|
))}
|
||||||
))}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const InteractiveButton = () => (
|
export const InteractiveButton = () => (
|
||||||
<Button
|
<Button
|
||||||
disabled={boolean('Disabled', false)}
|
disabled={boolean('Disabled', false)}
|
||||||
bsStyle={select(
|
cta={boolean('CTA', false)}
|
||||||
bsStyleKnob.label,
|
buttonStyle={select(
|
||||||
bsStyleKnob.options,
|
buttonStyleKnob.label,
|
||||||
bsStyleKnob.defaultValue,
|
buttonStyleKnob.options,
|
||||||
bsStyleKnob.groupId,
|
buttonStyleKnob.defaultValue,
|
||||||
|
buttonStyleKnob.groupId,
|
||||||
)}
|
)}
|
||||||
bsSize={select(
|
size={select(
|
||||||
bsSizeKnob.label,
|
buttonSizeKnob.label,
|
||||||
bsSizeKnob.options,
|
buttonSizeKnob.options,
|
||||||
bsSizeKnob.defaultValue,
|
buttonSizeKnob.defaultValue,
|
||||||
bsSizeKnob.groupId,
|
buttonSizeKnob.groupId,
|
||||||
)}
|
)}
|
||||||
onClick={action('clicked')}
|
onClick={action('clicked')}
|
||||||
type={select(
|
type={select(
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
/**
|
||||||
|
* 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 { ReactWrapper } from 'enzyme';
|
||||||
|
import { styledMount as mount } from 'spec/helpers/theming';
|
||||||
|
import Button from '.';
|
||||||
|
import {
|
||||||
|
ButtonGallery,
|
||||||
|
buttonSizeKnob,
|
||||||
|
buttonStyleKnob,
|
||||||
|
} from './Button.stories';
|
||||||
|
|
||||||
|
describe('Button', () => {
|
||||||
|
let wrapper: ReactWrapper;
|
||||||
|
|
||||||
|
// test the basic component
|
||||||
|
it('renders the base component', () => {
|
||||||
|
expect(React.isValidElement(<Button />)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('works with an onClick handler', () => {
|
||||||
|
const mockAction = jest.fn();
|
||||||
|
wrapper = mount(<Button onClick={mockAction} />);
|
||||||
|
wrapper.find('Button').first().simulate('click');
|
||||||
|
expect(mockAction).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not handle onClicks when disabled', () => {
|
||||||
|
const mockAction = jest.fn();
|
||||||
|
wrapper = mount(<Button onClick={mockAction} disabled />);
|
||||||
|
wrapper.find('Button').first().simulate('click');
|
||||||
|
expect(mockAction).toHaveBeenCalledTimes(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
// test stories from the storybook!
|
||||||
|
it('All the sorybook gallery variants mount', () => {
|
||||||
|
wrapper = mount(<ButtonGallery />);
|
||||||
|
|
||||||
|
const permutationCount =
|
||||||
|
Object.values(buttonStyleKnob.options).filter(o => o).length *
|
||||||
|
Object.values(buttonSizeKnob.options).length;
|
||||||
|
|
||||||
|
expect(wrapper.find(Button).length).toEqual(permutationCount);
|
||||||
|
});
|
||||||
|
|
||||||
|
// test things NOT in the storybook!
|
||||||
|
it('renders custom button styles without melting', () => {
|
||||||
|
wrapper = mount(<Button buttonStyle="foobar" />);
|
||||||
|
expect(wrapper.find('Button.btn-foobar')).toHaveLength(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -18,6 +18,8 @@
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { kebabCase } from 'lodash';
|
import { kebabCase } from 'lodash';
|
||||||
|
import { mix } from 'polished';
|
||||||
|
import cx from 'classnames';
|
||||||
import {
|
import {
|
||||||
Button as BootstrapButton,
|
Button as BootstrapButton,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
|
|
@ -40,52 +42,201 @@ export interface ButtonProps {
|
||||||
placement?: string;
|
placement?: string;
|
||||||
onClick?: OnClickHandler;
|
onClick?: OnClickHandler;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
bsStyle?: string;
|
buttonStyle?: string;
|
||||||
btnStyles?: string;
|
btnStyles?: string;
|
||||||
bsSize?: BootstrapButton.ButtonProps['bsSize'];
|
buttonSize?: BootstrapButton.ButtonProps['bsSize'];
|
||||||
style?: BootstrapButton.ButtonProps['style'];
|
style?: BootstrapButton.ButtonProps['style'];
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
dropdownItems?: DropdownItemProps[];
|
dropdownItems?: DropdownItemProps[];
|
||||||
|
href?: string; // React-Bootstrap creates a link when this is passed in.
|
||||||
|
target?: string; // React-Bootstrap creates a link when this is passed in.
|
||||||
|
type?: string; // React-Bootstrap supports this when rendering an HTML button element
|
||||||
|
cta?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BUTTON_WRAPPER_STYLE = { display: 'inline-block', cursor: 'not-allowed' };
|
const BUTTON_WRAPPER_STYLE = { display: 'inline-block', cursor: 'not-allowed' };
|
||||||
|
|
||||||
const SupersetButton = styled(BootstrapButton)`
|
const SupersetButton = styled(BootstrapButton)`
|
||||||
&.supersetButton {
|
&:focus,
|
||||||
border-radius: ${({ theme }) => theme.borderRadius}px;
|
&:active,
|
||||||
border: none;
|
&:focus:active {
|
||||||
color: ${({ theme }) => theme.colors.secondary.light5};
|
outline: none;
|
||||||
font-size: ${({ theme }) => theme.typography.sizes.s}px;
|
box-shadow: none;
|
||||||
font-weight: ${({ theme }) => theme.typography.weights.bold};
|
}
|
||||||
|
transition: all ${({ theme }) => theme.transitionTiming}s;
|
||||||
|
border-radius: ${({ theme }) => theme.borderRadius}px;
|
||||||
|
border: none;
|
||||||
|
font-size: ${({ theme }) => theme.typography.sizes.s}px;
|
||||||
|
font-weight: ${({ theme }) => theme.typography.weights.bold};
|
||||||
|
margin-left: ${({ theme }) => theme.gridUnit * 4}px;
|
||||||
|
&:first-of-type {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
padding: 0 ${({ theme }) => theme.gridUnit * 2}px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SIP 34 colors! */
|
||||||
|
&.btn {
|
||||||
|
border: 1px solid transparent; /* this just makes sure the height is the same as tertiary/dashed buttons */
|
||||||
|
&:hover,
|
||||||
|
&:active {
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
&-default,
|
||||||
|
&-secondary {
|
||||||
|
background-color: ${({ theme }) => theme.colors.primary.light4};
|
||||||
|
color: ${({ theme }) => theme.colors.primary.dark1};
|
||||||
|
&:hover {
|
||||||
|
background-color: ${({ theme }) =>
|
||||||
|
mix(0.1, theme.colors.grayscale.light5, theme.colors.primary.light4)};
|
||||||
|
color: ${({ theme }) => theme.colors.primary.dark1};
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
background-color: ${({ theme }) =>
|
||||||
|
mix(0.25, theme.colors.primary.base, theme.colors.primary.light4)};
|
||||||
|
color: ${({ theme }) => theme.colors.primary.dark1};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-tertiary,
|
||||||
|
&-dashed {
|
||||||
|
border-width: 1px;
|
||||||
|
border-style: solid;
|
||||||
|
background-color: ${({ theme }) => theme.colors.grayscale.light5};
|
||||||
|
color: ${({ theme }) => theme.colors.primary.dark1};
|
||||||
|
border-color: ${({ theme }) => theme.colors.primary.dark1};
|
||||||
|
&:hover {
|
||||||
|
background-color: ${({ theme }) => theme.colors.grayscale.light5};
|
||||||
|
color: ${({ theme }) => theme.colors.primary.dark1};
|
||||||
|
border-color: ${({ theme }) => theme.colors.primary.light1};
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
background-color: ${({ theme }) => theme.colors.grayscale.light5};
|
||||||
|
color: ${({ theme }) => theme.colors.primary.dark1};
|
||||||
|
border-color: ${({ theme }) => theme.colors.primary.dark1};
|
||||||
|
}
|
||||||
|
&[disabled],
|
||||||
|
&[disabled]:hover {
|
||||||
|
background-color: ${({ theme }) => theme.colors.grayscale.light5};
|
||||||
|
color: ${({ theme }) => theme.colors.grayscale.base};
|
||||||
|
border-color: ${({ theme }) => theme.colors.grayscale.light2};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-dashed {
|
||||||
|
border-style: dashed;
|
||||||
|
&:hover,
|
||||||
|
&:active {
|
||||||
|
border-style: dashed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-link {
|
||||||
|
background: none;
|
||||||
|
text-decoration: none;
|
||||||
|
color: ${({ theme }) => theme.colors.primary.dark1};
|
||||||
|
&:hover {
|
||||||
|
background: none;
|
||||||
|
color: ${({ theme }) => theme.colors.primary.base};
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
background: none;
|
||||||
|
color: ${({ theme }) => theme.colors.primary.dark1};
|
||||||
|
}
|
||||||
|
&[disabled],
|
||||||
|
&[disabled]:hover {
|
||||||
|
background: none;
|
||||||
|
color: ${({ theme }) => theme.colors.grayscale.base};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-primary {
|
||||||
|
background-color: ${({ theme }) => theme.colors.primary.dark1};
|
||||||
|
color: ${({ theme }) => theme.colors.grayscale.light5};
|
||||||
|
&:hover {
|
||||||
|
background-color: ${({ theme }) =>
|
||||||
|
mix(0.1, theme.colors.grayscale.light5, theme.colors.primary.dark1)};
|
||||||
|
color: ${({ theme }) => theme.colors.grayscale.light5};
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
background-color: ${({ theme }) =>
|
||||||
|
mix(0.2, theme.colors.grayscale.dark2, theme.colors.primary.dark1)};
|
||||||
|
color: ${({ theme }) => theme.colors.grayscale.light5};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-danger {
|
||||||
|
background-color: ${({ theme }) => theme.colors.error.base};
|
||||||
|
color: ${({ theme }) => theme.colors.grayscale.light5};
|
||||||
|
&:hover {
|
||||||
|
background-color: ${({ theme }) =>
|
||||||
|
mix(0.1, theme.colors.grayscale.light5, theme.colors.error.base)};
|
||||||
|
color: ${({ theme }) => theme.colors.grayscale.light5};
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
background-color: ${({ theme }) =>
|
||||||
|
mix(0.2, theme.colors.grayscale.dark2, theme.colors.error.base)};
|
||||||
|
color: ${({ theme }) => theme.colors.grayscale.light5};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-success {
|
||||||
|
background-color: ${({ theme }) => theme.colors.success.base};
|
||||||
|
color: ${({ theme }) => theme.colors.grayscale.light5};
|
||||||
|
&:hover {
|
||||||
|
background-color: ${({ theme }) =>
|
||||||
|
mix(0.1, theme.colors.grayscale.light5, theme.colors.success.base)};
|
||||||
|
color: ${({ theme }) => theme.colors.grayscale.light5};
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
background-color: ${({ theme }) =>
|
||||||
|
mix(0.2, theme.colors.grayscale.dark2, theme.colors.success.base)};
|
||||||
|
color: ${({ theme }) => theme.colors.grayscale.light5};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-warning {
|
||||||
|
background-color: ${({ theme }) => theme.colors.warning.base};
|
||||||
|
color: ${({ theme }) => theme.colors.grayscale.light5};
|
||||||
|
&:hover {
|
||||||
|
background-color: ${({ theme }) =>
|
||||||
|
mix(0.1, theme.colors.grayscale.light5, theme.colors.warning.base)};
|
||||||
|
color: ${({ theme }) => theme.colors.grayscale.light5};
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
background-color: ${({ theme }) =>
|
||||||
|
mix(0.2, theme.colors.grayscale.dark2, theme.colors.warning.base)};
|
||||||
|
color: ${({ theme }) => theme.colors.grayscale.light5};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-info {
|
||||||
|
background-color: ${({ theme }) => theme.colors.info.dark1};
|
||||||
|
color: ${({ theme }) => theme.colors.grayscale.light5};
|
||||||
|
&:hover {
|
||||||
|
background-color: ${({ theme }) =>
|
||||||
|
mix(0.1, theme.colors.grayscale.light5, theme.colors.info.dark1)};
|
||||||
|
color: ${({ theme }) => theme.colors.grayscale.light5};
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
background-color: ${({ theme }) =>
|
||||||
|
mix(0.2, theme.colors.grayscale.dark2, theme.colors.info.dark1)};
|
||||||
|
color: ${({ theme }) => theme.colors.grayscale.light5};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&[disabled],
|
||||||
|
&[disabled]:hover {
|
||||||
|
background-color: ${({ theme }) => theme.colors.grayscale.light2};
|
||||||
|
color: ${({ theme }) => theme.colors.grayscale.light1};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* big Call to Action buttons */
|
||||||
|
&.cta {
|
||||||
min-width: ${({ theme }) => theme.gridUnit * 36}px;
|
min-width: ${({ theme }) => theme.gridUnit * 36}px;
|
||||||
min-height: ${({ theme }) => theme.gridUnit * 8}px;
|
min-height: ${({ theme }) => theme.gridUnit * 8}px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
margin-left: ${({ theme }) => theme.gridUnit * 4}px;
|
|
||||||
&:first-of-type {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
i {
|
|
||||||
padding: 0 ${({ theme }) => theme.gridUnit * 2}px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.primary {
|
|
||||||
background-color: ${({ theme }) => theme.colors.primary.base};
|
|
||||||
}
|
|
||||||
&.secondary {
|
|
||||||
color: ${({ theme }) => theme.colors.primary.base};
|
|
||||||
background-color: ${({ theme }) => theme.colors.primary.light4};
|
|
||||||
}
|
|
||||||
&.danger {
|
|
||||||
background-color: ${({ theme }) => theme.colors.error.base};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default function Button(props: ButtonProps) {
|
export default function Button(props: ButtonProps) {
|
||||||
const buttonProps = {
|
const buttonProps = {
|
||||||
...props,
|
...props,
|
||||||
bsSize: props.bsSize || 'sm',
|
bsSize: props.buttonSize,
|
||||||
placement: props.placement || 'top',
|
placement: props.placement || 'top',
|
||||||
};
|
};
|
||||||
const tooltip = props.tooltip;
|
const tooltip = props.tooltip;
|
||||||
|
|
@ -100,17 +251,40 @@ export default function Button(props: ButtonProps) {
|
||||||
buttonProps.style = { pointerEvents: 'none' };
|
buttonProps.style = { pointerEvents: 'none' };
|
||||||
}
|
}
|
||||||
|
|
||||||
let button = (
|
const officialBootstrapStyles = [
|
||||||
<SupersetButton {...buttonProps}>{props.children}</SupersetButton>
|
'success',
|
||||||
);
|
'warning',
|
||||||
|
'danger',
|
||||||
|
'info',
|
||||||
|
'default',
|
||||||
|
'primary',
|
||||||
|
];
|
||||||
|
|
||||||
const whittledProps = { ...buttonProps };
|
const transformedProps = {
|
||||||
delete whittledProps.dropdownItems;
|
...buttonProps,
|
||||||
|
bsStyle: officialBootstrapStyles.includes(props.buttonStyle || '')
|
||||||
|
? props.buttonStyle
|
||||||
|
: 'default',
|
||||||
|
className: cx(props.className, {
|
||||||
|
cta: !!buttonProps.cta,
|
||||||
|
[`btn-${props.buttonStyle}`]: !officialBootstrapStyles.includes(
|
||||||
|
props.buttonStyle || '',
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
delete transformedProps.dropdownItems;
|
||||||
|
delete transformedProps.buttonSize;
|
||||||
|
delete transformedProps.buttonStyle;
|
||||||
|
delete transformedProps.cta;
|
||||||
|
|
||||||
|
let button = (
|
||||||
|
<SupersetButton {...transformedProps}>{props.children}</SupersetButton>
|
||||||
|
);
|
||||||
|
|
||||||
if (dropdownItems) {
|
if (dropdownItems) {
|
||||||
button = (
|
button = (
|
||||||
<div style={BUTTON_WRAPPER_STYLE}>
|
<div style={BUTTON_WRAPPER_STYLE}>
|
||||||
<SupersetButton {...whittledProps} data-toggle="dropdown">
|
<SupersetButton {...transformedProps} data-toggle="dropdown">
|
||||||
{props.children}
|
{props.children}
|
||||||
</SupersetButton>
|
</SupersetButton>
|
||||||
<ul className="dropdown-menu">
|
<ul className="dropdown-menu">
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import { Modal } from 'react-bootstrap';
|
||||||
import { styled, supersetTheme } from '@superset-ui/style';
|
import { styled, supersetTheme } from '@superset-ui/style';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
import { noOp } from 'src/utils/common';
|
import { noOp } from 'src/utils/common';
|
||||||
import Button from 'src/views/CRUD/data/dataset/Button';
|
import Button from 'src/components/Button';
|
||||||
|
|
||||||
import Icon from '../Icon';
|
import Icon from '../Icon';
|
||||||
import { ErrorLevel, ErrorSource } from './types';
|
import { ErrorLevel, ErrorSource } from './types';
|
||||||
|
|
@ -190,7 +190,11 @@ export default function ErrorAlert({
|
||||||
copyNode={<Button onClick={noOp}>{t('Copy Message')}</Button>}
|
copyNode={<Button onClick={noOp}>{t('Copy Message')}</Button>}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Button bsStyle="primary" onClick={() => setIsModalOpen(false)}>
|
<Button
|
||||||
|
cta
|
||||||
|
buttonStyle="primary"
|
||||||
|
onClick={() => setIsModalOpen(false)}
|
||||||
|
>
|
||||||
{t('Close')}
|
{t('Close')}
|
||||||
</Button>
|
</Button>
|
||||||
</Modal.Footer>
|
</Modal.Footer>
|
||||||
|
|
|
||||||
|
|
@ -39,12 +39,12 @@ export default function ExpandableList({ items, display = 3 }: Props) {
|
||||||
const showMoreAction = items.length > display;
|
const showMoreAction = items.length > display;
|
||||||
|
|
||||||
const lessAction = (
|
const lessAction = (
|
||||||
<Button bsStyle="link" bsSize="xsmall" onClick={toggleShowingAll}>
|
<Button buttonStyle="link" buttonSize="xsmall" onClick={toggleShowingAll}>
|
||||||
less
|
less
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
const moreAction = (
|
const moreAction = (
|
||||||
<Button bsStyle="link" bsSize="xsmall" onClick={toggleShowingAll}>
|
<Button buttonStyle="link" buttonSize="xsmall" onClick={toggleShowingAll}>
|
||||||
{items.length - itemsToDisplay.length} more
|
{items.length - itemsToDisplay.length} more
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ export default {
|
||||||
title: 'Label',
|
title: 'Label',
|
||||||
component: Label,
|
component: Label,
|
||||||
decorators: [withKnobs],
|
decorators: [withKnobs],
|
||||||
excludeStories: ['bsStyleKnob'],
|
excludeStories: /.*Knob$/,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const bsStyleKnob = {
|
export const bsStyleKnob = {
|
||||||
|
|
|
||||||
|
|
@ -311,11 +311,12 @@ function ListView<T extends object = any>({
|
||||||
<Button
|
<Button
|
||||||
data-test="bulk-select-action"
|
data-test="bulk-select-action"
|
||||||
key={action.key}
|
key={action.key}
|
||||||
className={cx('supersetButton', {
|
className={cx({
|
||||||
danger: action.type === 'danger',
|
danger: action.type === 'danger',
|
||||||
primary: action.type === 'primary',
|
primary: action.type === 'primary',
|
||||||
secondary: action.type === 'secondary',
|
secondary: action.type === 'secondary',
|
||||||
})}
|
})}
|
||||||
|
cta
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
action.onSelect(selectedFlatRows.map(r => r.original))
|
action.onSelect(selectedFlatRows.map(r => r.original))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,14 @@ const StyledHeader = styled.header`
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
border-bottom: 1px solid ${({ theme }) => theme.colors.grayscale.light2};
|
border-bottom: 1px solid ${({ theme }) => theme.colors.grayscale.light2};
|
||||||
}
|
}
|
||||||
|
.navbar-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
.dropdown:first-of-type {
|
||||||
|
/* this is the "+ NEW" button. Sweep this up when it's replaced */
|
||||||
|
margin-right: ${({ theme }) => theme.gridUnit * 2}px;
|
||||||
|
}
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function Menu({
|
export function Menu({
|
||||||
|
|
|
||||||
|
|
@ -17,15 +17,9 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from '@superset-ui/style';
|
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
import Button, { DropdownItemProps } from '../Button';
|
import Button, { DropdownItemProps } from '../Button';
|
||||||
|
|
||||||
const StyledButton = styled(Button)`
|
|
||||||
margin-top: 12px;
|
|
||||||
margin-right: 30px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const dropdownItems: DropdownItemProps[] = [
|
const dropdownItems: DropdownItemProps[] = [
|
||||||
{
|
{
|
||||||
label: t('SQL Query'),
|
label: t('SQL Query'),
|
||||||
|
|
@ -47,12 +41,9 @@ const dropdownItems: DropdownItemProps[] = [
|
||||||
export default function NewMenu() {
|
export default function NewMenu() {
|
||||||
return (
|
return (
|
||||||
<li className="dropdown">
|
<li className="dropdown">
|
||||||
<StyledButton
|
<Button buttonStyle="primary" dropdownItems={dropdownItems}>
|
||||||
className="dropdown-toggle btn btn-sm btn-primary"
|
|
||||||
dropdownItems={dropdownItems}
|
|
||||||
>
|
|
||||||
<i className="fa fa-plus" /> New
|
<i className="fa fa-plus" /> New
|
||||||
</StyledButton>
|
</Button>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,12 +26,8 @@ const StyledHeader = styled.header`
|
||||||
font-weight: ${({ theme }) => theme.typography.weights.bold};
|
font-weight: ${({ theme }) => theme.typography.weights.bold};
|
||||||
}
|
}
|
||||||
.navbar-right {
|
.navbar-right {
|
||||||
.supersetButton {
|
padding: 8px 0;
|
||||||
margin: ${({ theme }) =>
|
margin-right: 0;
|
||||||
`${theme.gridUnit * 2}px ${theme.gridUnit * 4}px ${
|
|
||||||
theme.gridUnit * 2
|
|
||||||
}px 0`};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.navbar-nav {
|
.navbar-nav {
|
||||||
li {
|
li {
|
||||||
|
|
@ -94,16 +90,18 @@ const SubMenu: React.FunctionComponent<SubMenuProps> = props => {
|
||||||
<Nav className="navbar-right">
|
<Nav className="navbar-right">
|
||||||
{props.secondaryButton && (
|
{props.secondaryButton && (
|
||||||
<Button
|
<Button
|
||||||
className="supersetButton secondary"
|
buttonStyle="secondary"
|
||||||
onClick={props.secondaryButton.onClick}
|
onClick={props.secondaryButton.onClick}
|
||||||
|
cta
|
||||||
>
|
>
|
||||||
{props.secondaryButton.name}
|
{props.secondaryButton.name}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{props.primaryButton && (
|
{props.primaryButton && (
|
||||||
<Button
|
<Button
|
||||||
className="supersetButton primary"
|
buttonStyle="primary"
|
||||||
onClick={props.primaryButton.onClick}
|
onClick={props.primaryButton.onClick}
|
||||||
|
cta
|
||||||
>
|
>
|
||||||
{props.primaryButton.name}
|
{props.primaryButton.name}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import React from 'react';
|
||||||
import styled from '@superset-ui/style';
|
import styled from '@superset-ui/style';
|
||||||
import { Modal as BaseModal } from 'react-bootstrap';
|
import { Modal as BaseModal } from 'react-bootstrap';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
import Button from 'src/views/CRUD/data/dataset/Button';
|
import Button from 'src/components/Button';
|
||||||
|
|
||||||
interface ModalProps {
|
interface ModalProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
|
|
@ -54,9 +54,6 @@ const StyledModal = styled(BaseModal)`
|
||||||
.modal-footer {
|
.modal-footer {
|
||||||
border-top: 1px solid ${({ theme }) => theme.colors.grayscale.light2};
|
border-top: 1px solid ${({ theme }) => theme.colors.grayscale.light2};
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
.btn + .btn {
|
|
||||||
margin-left: 8px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
@ -86,11 +83,14 @@ export default function Modal({
|
||||||
<BaseModal.Body>{children}</BaseModal.Body>
|
<BaseModal.Body>{children}</BaseModal.Body>
|
||||||
<BaseModal.Footer>
|
<BaseModal.Footer>
|
||||||
<span className="float-right">
|
<span className="float-right">
|
||||||
<Button onClick={onHide}>{t('Cancel')}</Button>
|
<Button onClick={onHide} cta>
|
||||||
|
{t('Cancel')}
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
bsStyle={primaryButtonType}
|
buttonStyle={primaryButtonType}
|
||||||
disabled={disablePrimaryButton}
|
disabled={disablePrimaryButton}
|
||||||
onClick={onHandledPrimaryAction}
|
onClick={onHandledPrimaryAction}
|
||||||
|
cta
|
||||||
>
|
>
|
||||||
{primaryButtonName}
|
{primaryButtonName}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,8 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Modal, MenuItem } from 'react-bootstrap';
|
import { Modal, MenuItem } from 'react-bootstrap';
|
||||||
import cx from 'classnames';
|
|
||||||
|
|
||||||
import Button from './Button';
|
import Button from 'src/components/Button';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
dialogClassName: PropTypes.string,
|
dialogClassName: PropTypes.string,
|
||||||
|
|
@ -96,9 +95,6 @@ export default class ModalTrigger extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const classNames = cx({
|
|
||||||
'btn btn-default btn-sm': this.props.isButton,
|
|
||||||
});
|
|
||||||
if (this.props.isButton) {
|
if (this.props.isButton) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -123,7 +119,7 @@ export default class ModalTrigger extends React.Component {
|
||||||
/* eslint-disable jsx-a11y/interactive-supports-focus */
|
/* eslint-disable jsx-a11y/interactive-supports-focus */
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<span className={classNames} onClick={this.open} role="button">
|
<span onClick={this.open} role="button">
|
||||||
{this.props.triggerNode}
|
{this.props.triggerNode}
|
||||||
</span>
|
</span>
|
||||||
{this.renderModal()}
|
{this.renderModal()}
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ class RefreshChartOverlay extends React.PureComponent<Props> {
|
||||||
<Button
|
<Button
|
||||||
className="refresh-btn"
|
className="refresh-btn"
|
||||||
onClick={this.props.onQuery}
|
onClick={this.props.onQuery}
|
||||||
bsStyle="primary"
|
buttonStyle="primary"
|
||||||
>
|
>
|
||||||
{t('Run Query')}
|
{t('Run Query')}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Button } from 'react-bootstrap';
|
import Button from 'src/components/Button';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
|
|
||||||
import ModalTrigger from '../../components/ModalTrigger';
|
import ModalTrigger from '../../components/ModalTrigger';
|
||||||
|
|
@ -66,7 +66,7 @@ export default class DeleteComponentModal extends React.PureComponent {
|
||||||
</div>
|
</div>
|
||||||
<div className="dashboard-modal-actions-container">
|
<div className="dashboard-modal-actions-container">
|
||||||
<Button onClick={this.close}>{t('Cancel')}</Button>
|
<Button onClick={this.close}>{t('Cancel')}</Button>
|
||||||
<Button bsStyle="primary" onClick={this.deleteTab}>
|
<Button buttonStyle="primary" onClick={this.deleteTab}>
|
||||||
{t('Delete')}
|
{t('Delete')}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,10 @@ import { CategoricalColorNamespace } from '@superset-ui/color';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
|
|
||||||
import Icon from 'src/components/Icon';
|
import Icon from 'src/components/Icon';
|
||||||
|
import Button from 'src/components/Button';
|
||||||
|
|
||||||
import HeaderActionsDropdown from './HeaderActionsDropdown';
|
import HeaderActionsDropdown from './HeaderActionsDropdown';
|
||||||
import EditableTitle from '../../components/EditableTitle';
|
import EditableTitle from '../../components/EditableTitle';
|
||||||
import Button from '../../components/Button';
|
|
||||||
import FaveStar from '../../components/FaveStar';
|
import FaveStar from '../../components/FaveStar';
|
||||||
import PublishedStatus from './PublishedStatus';
|
import PublishedStatus from './PublishedStatus';
|
||||||
import UndoRedoKeylisteners from './UndoRedoKeylisteners';
|
import UndoRedoKeylisteners from './UndoRedoKeylisteners';
|
||||||
|
|
@ -390,36 +390,40 @@ class Header extends React.PureComponent {
|
||||||
<>
|
<>
|
||||||
<ButtonGroup className="m-r-5">
|
<ButtonGroup className="m-r-5">
|
||||||
<Button
|
<Button
|
||||||
bsSize="small"
|
buttonSize="small"
|
||||||
onClick={onUndo}
|
onClick={onUndo}
|
||||||
disabled={undoLength < 1}
|
disabled={undoLength < 1}
|
||||||
bsStyle={this.state.emphasizeUndo ? 'primary' : undefined}
|
buttonStyle={
|
||||||
|
this.state.emphasizeUndo ? 'primary' : undefined
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<i title="Undo" className="undo-action fa fa-reply" />
|
<i title="Undo" className="undo-action fa fa-reply" />
|
||||||
|
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
bsSize="small"
|
buttonSize="small"
|
||||||
onClick={onRedo}
|
onClick={onRedo}
|
||||||
disabled={redoLength < 1}
|
disabled={redoLength < 1}
|
||||||
bsStyle={this.state.emphasizeRedo ? 'primary' : undefined}
|
buttonStyle={
|
||||||
|
this.state.emphasizeRedo ? 'primary' : undefined
|
||||||
|
}
|
||||||
>
|
>
|
||||||
|
|
||||||
<i title="Redo" className="redo-action fa fa-share" />
|
<i title="Redo" className="redo-action fa fa-share" />
|
||||||
</Button>
|
</Button>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
<Button
|
<Button
|
||||||
bsSize="small"
|
buttonSize="small"
|
||||||
className="m-r-5"
|
className="m-r-5"
|
||||||
onClick={this.constructor.discardChanges}
|
onClick={this.constructor.discardChanges}
|
||||||
bsStyle="default"
|
buttonStyle="default"
|
||||||
>
|
>
|
||||||
{t('Discard Changes')}
|
{t('Discard Changes')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
bsSize="small"
|
buttonSize="small"
|
||||||
disabled={!hasUnsavedChanges}
|
disabled={!hasUnsavedChanges}
|
||||||
bsStyle="primary"
|
buttonStyle="primary"
|
||||||
onClick={this.overwriteDashboard}
|
onClick={this.overwriteDashboard}
|
||||||
>
|
>
|
||||||
{t('Save')}
|
{t('Save')}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Row, Col, Button, Modal, FormControl } from 'react-bootstrap';
|
import { Row, Col, Modal, FormControl } from 'react-bootstrap';
|
||||||
|
import Button from 'src/components/Button';
|
||||||
import Dialog from 'react-bootstrap-dialog';
|
import Dialog from 'react-bootstrap-dialog';
|
||||||
import { AsyncSelect } from 'src/components/Select';
|
import { AsyncSelect } from 'src/components/Select';
|
||||||
import AceEditor from 'react-ace';
|
import AceEditor from 'react-ace';
|
||||||
|
|
@ -288,11 +289,7 @@ class PropertiesModal extends React.PureComponent {
|
||||||
<Row>
|
<Row>
|
||||||
<Col md={12}>
|
<Col md={12}>
|
||||||
<h3 style={{ marginTop: '1em' }}>
|
<h3 style={{ marginTop: '1em' }}>
|
||||||
<button
|
<Button buttonStyle="link" onClick={this.toggleAdvanced}>
|
||||||
type="button"
|
|
||||||
className="text-button"
|
|
||||||
onClick={this.toggleAdvanced}
|
|
||||||
>
|
|
||||||
<i
|
<i
|
||||||
className={`fa fa-angle-${
|
className={`fa fa-angle-${
|
||||||
isAdvancedOpen ? 'down' : 'right'
|
isAdvancedOpen ? 'down' : 'right'
|
||||||
|
|
@ -300,7 +297,7 @@ class PropertiesModal extends React.PureComponent {
|
||||||
style={{ minWidth: '1em' }}
|
style={{ minWidth: '1em' }}
|
||||||
/>
|
/>
|
||||||
{t('Advanced')}
|
{t('Advanced')}
|
||||||
</button>
|
</Button>
|
||||||
</h3>
|
</h3>
|
||||||
{isAdvancedOpen && (
|
{isAdvancedOpen && (
|
||||||
<>
|
<>
|
||||||
|
|
@ -332,14 +329,15 @@ class PropertiesModal extends React.PureComponent {
|
||||||
<span className="float-right">
|
<span className="float-right">
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
bsSize="sm"
|
buttonSize="sm"
|
||||||
bsStyle="primary"
|
buttonStyle="primary"
|
||||||
className="m-r-5"
|
className="m-r-5"
|
||||||
disabled={errors.length > 0}
|
disabled={errors.length > 0}
|
||||||
|
cta
|
||||||
>
|
>
|
||||||
{saveLabel}
|
{saveLabel}
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="button" bsSize="sm" onClick={onHide}>
|
<Button type="button" buttonSize="sm" onClick={onHide} cta>
|
||||||
{t('Cancel')}
|
{t('Cancel')}
|
||||||
</Button>
|
</Button>
|
||||||
<Dialog
|
<Dialog
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
import TooltipWrapper from '../../components/TooltipWrapper';
|
import TooltipWrapper from 'src/components/TooltipWrapper';
|
||||||
|
import Label from 'src/components/Label';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
dashboardId: PropTypes.number.isRequired,
|
dashboardId: PropTypes.number.isRequired,
|
||||||
|
|
@ -43,14 +44,6 @@ const publishedTooltip = t(
|
||||||
'This dashboard is published. Click to make it a draft.',
|
'This dashboard is published. Click to make it a draft.',
|
||||||
);
|
);
|
||||||
|
|
||||||
const divStyle = {
|
|
||||||
border: '1px dotted black',
|
|
||||||
backgroundColor: '#F9F9F9',
|
|
||||||
padding: '3px 7px 3px 7px',
|
|
||||||
fontFamily: 'Monospace',
|
|
||||||
fontSize: '16px',
|
|
||||||
};
|
|
||||||
|
|
||||||
export default class PublishedStatus extends React.Component {
|
export default class PublishedStatus extends React.Component {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.togglePublished = this.togglePublished.bind(this);
|
this.togglePublished = this.togglePublished.bind(this);
|
||||||
|
|
@ -71,14 +64,13 @@ export default class PublishedStatus extends React.Component {
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
tooltip={draftButtonTooltip}
|
tooltip={draftButtonTooltip}
|
||||||
>
|
>
|
||||||
<button
|
<Label
|
||||||
style={divStyle}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
this.togglePublished();
|
this.togglePublished();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Draft
|
Draft
|
||||||
</button>
|
</Label>
|
||||||
</TooltipWrapper>
|
</TooltipWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -88,7 +80,7 @@ export default class PublishedStatus extends React.Component {
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
tooltip={draftDivTooltip}
|
tooltip={draftDivTooltip}
|
||||||
>
|
>
|
||||||
<div style={divStyle}>Draft</div>
|
<Label>Draft</Label>
|
||||||
</TooltipWrapper>
|
</TooltipWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -101,14 +93,13 @@ export default class PublishedStatus extends React.Component {
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
tooltip={publishedTooltip}
|
tooltip={publishedTooltip}
|
||||||
>
|
>
|
||||||
<button
|
<Label
|
||||||
style={divStyle}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
this.togglePublished();
|
this.togglePublished();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Published
|
Published
|
||||||
</button>
|
</Label>
|
||||||
</TooltipWrapper>
|
</TooltipWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@ import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Select from 'src/components/Select';
|
import Select from 'src/components/Select';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
import { Alert, Button } from 'react-bootstrap';
|
import { Alert } from 'react-bootstrap';
|
||||||
|
import Button from 'src/components/Button';
|
||||||
|
|
||||||
import ModalTrigger from 'src/components/ModalTrigger';
|
import ModalTrigger from 'src/components/ModalTrigger';
|
||||||
import FormLabel from 'src/components/FormLabel';
|
import FormLabel from 'src/components/FormLabel';
|
||||||
|
|
@ -116,10 +117,10 @@ class RefreshIntervalModal extends React.PureComponent {
|
||||||
}
|
}
|
||||||
modalFooter={
|
modalFooter={
|
||||||
<>
|
<>
|
||||||
<Button bsStyle="primary" bsSize="sm" onClick={this.onSave}>
|
<Button buttonStyle="primary" buttonSize="sm" onClick={this.onSave}>
|
||||||
{editMode ? t('Save') : t('Save for this session')}
|
{editMode ? t('Save') : t('Save for this session')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={this.onCancel} bsSize="sm">
|
<Button onClick={this.onCancel} buttonSize="sm">
|
||||||
{t('Cancel')}
|
{t('Cancel')}
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@
|
||||||
/* eslint-env browser */
|
/* eslint-env browser */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Button, FormControl, FormGroup, Radio } from 'react-bootstrap';
|
import { FormControl, FormGroup, Radio } from 'react-bootstrap';
|
||||||
|
import Button from 'src/components/Button';
|
||||||
import { CategoricalColorNamespace } from '@superset-ui/color';
|
import { CategoricalColorNamespace } from '@superset-ui/color';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
|
|
||||||
|
|
@ -191,7 +192,7 @@ class SaveModal extends React.PureComponent {
|
||||||
}
|
}
|
||||||
modalFooter={
|
modalFooter={
|
||||||
<div>
|
<div>
|
||||||
<Button bsStyle="primary" onClick={this.saveDashboard}>
|
<Button buttonStyle="primary" onClick={this.saveDashboard}>
|
||||||
{t('Save')}
|
{t('Save')}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
import { Button } from 'react-bootstrap';
|
import Button from 'src/components/Button';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
|
|
||||||
import buildFilterScopeTreeEntry from '../../util/buildFilterScopeTreeEntry';
|
import buildFilterScopeTreeEntry from '../../util/buildFilterScopeTreeEntry';
|
||||||
|
|
@ -513,11 +513,11 @@ export default class FilterScopeSelector extends React.PureComponent {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="dashboard-modal-actions-container">
|
<div className="dashboard-modal-actions-container">
|
||||||
<Button bsSize="sm" onClick={this.onClose}>
|
<Button buttonSize="sm" onClick={this.onClose}>
|
||||||
{t('Close')}
|
{t('Close')}
|
||||||
</Button>
|
</Button>
|
||||||
{showSelector && (
|
{showSelector && (
|
||||||
<Button bsSize="sm" bsStyle="primary" onClick={this.onSave}>
|
<Button buttonSize="sm" buttonStyle="primary" onClick={this.onSave}>
|
||||||
{t('Save')}
|
{t('Save')}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -41,14 +41,3 @@
|
||||||
padding-left: 8px;
|
padding-left: 8px;
|
||||||
font-size: @font-size-m;
|
font-size: @font-size-m;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-button {
|
|
||||||
outline: none;
|
|
||||||
border: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
background: none;
|
|
||||||
text-decoration: none;
|
|
||||||
font-size: inherit;
|
|
||||||
font-weight: inherit;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -784,7 +784,7 @@ export class DatasourceEditor extends React.PureComponent {
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
bsStyle="primary"
|
buttonStyle="primary"
|
||||||
onClick={this.syncMetadata}
|
onClick={this.syncMetadata}
|
||||||
className="sync-from-source"
|
className="sync-from-source"
|
||||||
disabled={!!datasource.sql}
|
disabled={!!datasource.sql}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import React, { FunctionComponent, useState, useRef } from 'react';
|
import React, { FunctionComponent, useState, useRef } from 'react';
|
||||||
import { Alert, Button, Modal } from 'react-bootstrap';
|
import { Alert, Modal } from 'react-bootstrap';
|
||||||
|
import Button from 'src/components/Button';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import Dialog from 'react-bootstrap-dialog';
|
import Dialog from 'react-bootstrap-dialog';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
|
|
@ -158,8 +159,8 @@ const DatasourceModal: FunctionComponent<DatasourceModalProps> = ({
|
||||||
<Modal.Footer>
|
<Modal.Footer>
|
||||||
<span className="float-left">
|
<span className="float-left">
|
||||||
<Button
|
<Button
|
||||||
bsSize="sm"
|
buttonSize="sm"
|
||||||
bsStyle="default"
|
buttonStyle="default"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
href={currentDatasource.edit_url || currentDatasource.url}
|
href={currentDatasource.edit_url || currentDatasource.url}
|
||||||
>
|
>
|
||||||
|
|
@ -169,15 +170,16 @@ const DatasourceModal: FunctionComponent<DatasourceModalProps> = ({
|
||||||
|
|
||||||
<span className="float-right">
|
<span className="float-right">
|
||||||
<Button
|
<Button
|
||||||
bsSize="sm"
|
buttonSize="sm"
|
||||||
bsStyle="primary"
|
buttonStyle="primary"
|
||||||
className="m-r-5"
|
className="m-r-5"
|
||||||
|
data-test="datasource-modal-save"
|
||||||
onClick={onClickSave}
|
onClick={onClickSave}
|
||||||
disabled={errors.length > 0}
|
disabled={errors.length > 0}
|
||||||
>
|
>
|
||||||
{t('Save')}
|
{t('Save')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button bsSize="sm" onClick={onHide}>
|
<Button buttonSize="sm" onClick={onHide}>
|
||||||
{t('Cancel')}
|
{t('Cancel')}
|
||||||
</Button>
|
</Button>
|
||||||
<Dialog ref={dialog} />
|
<Dialog ref={dialog} />
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,9 @@
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Button, Popover, Tab, Tabs } from 'react-bootstrap';
|
import { Popover, Tab, Tabs } from 'react-bootstrap';
|
||||||
|
import Button from 'src/components/Button';
|
||||||
|
import { ThemeProvider } from '@superset-ui/style';
|
||||||
|
|
||||||
import columnType from '../propTypes/columnType';
|
import columnType from '../propTypes/columnType';
|
||||||
import adhocMetricType from '../propTypes/adhocMetricType';
|
import adhocMetricType from '../propTypes/adhocMetricType';
|
||||||
|
|
@ -40,6 +42,7 @@ const propTypes = {
|
||||||
).isRequired,
|
).isRequired,
|
||||||
datasource: PropTypes.object,
|
datasource: PropTypes.object,
|
||||||
partitionColumn: PropTypes.string,
|
partitionColumn: PropTypes.string,
|
||||||
|
theme: PropTypes.object,
|
||||||
};
|
};
|
||||||
|
|
||||||
const startingWidth = 300;
|
const startingWidth = 300;
|
||||||
|
|
@ -119,6 +122,7 @@ export default class AdhocFilterEditPopover extends React.Component {
|
||||||
onResize,
|
onResize,
|
||||||
datasource,
|
datasource,
|
||||||
partitionColumn,
|
partitionColumn,
|
||||||
|
theme,
|
||||||
...popoverProps
|
...popoverProps
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
|
@ -129,68 +133,74 @@ export default class AdhocFilterEditPopover extends React.Component {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover id="filter-edit-popover" {...popoverProps}>
|
<Popover id="filter-edit-popover" {...popoverProps}>
|
||||||
<Tabs
|
<ThemeProvider theme={theme}>
|
||||||
id="adhoc-filter-edit-tabs"
|
<Tabs
|
||||||
defaultActiveKey={adhocFilter.expressionType}
|
id="adhoc-filter-edit-tabs"
|
||||||
className="adhoc-filter-edit-tabs"
|
defaultActiveKey={adhocFilter.expressionType}
|
||||||
style={{ height: this.state.height, width: this.state.width }}
|
className="adhoc-filter-edit-tabs"
|
||||||
>
|
style={{ height: this.state.height, width: this.state.width }}
|
||||||
<Tab
|
|
||||||
className="adhoc-filter-edit-tab"
|
|
||||||
eventKey={EXPRESSION_TYPES.SIMPLE}
|
|
||||||
title="Simple"
|
|
||||||
>
|
>
|
||||||
<AdhocFilterEditPopoverSimpleTabContent
|
<Tab
|
||||||
adhocFilter={this.state.adhocFilter}
|
className="adhoc-filter-edit-tab"
|
||||||
onChange={this.onAdhocFilterChange}
|
eventKey={EXPRESSION_TYPES.SIMPLE}
|
||||||
options={options}
|
title="Simple"
|
||||||
datasource={datasource}
|
>
|
||||||
onHeightChange={this.adjustHeight}
|
<AdhocFilterEditPopoverSimpleTabContent
|
||||||
partitionColumn={partitionColumn}
|
|
||||||
/>
|
|
||||||
</Tab>
|
|
||||||
<Tab
|
|
||||||
className="adhoc-filter-edit-tab"
|
|
||||||
eventKey={EXPRESSION_TYPES.SQL}
|
|
||||||
title="Custom SQL"
|
|
||||||
>
|
|
||||||
{!this.props.datasource ||
|
|
||||||
this.props.datasource.type !== 'druid' ? (
|
|
||||||
<AdhocFilterEditPopoverSqlTabContent
|
|
||||||
adhocFilter={this.state.adhocFilter}
|
adhocFilter={this.state.adhocFilter}
|
||||||
onChange={this.onAdhocFilterChange}
|
onChange={this.onAdhocFilterChange}
|
||||||
options={this.props.options}
|
options={options}
|
||||||
height={this.state.height}
|
datasource={datasource}
|
||||||
|
onHeightChange={this.adjustHeight}
|
||||||
|
partitionColumn={partitionColumn}
|
||||||
/>
|
/>
|
||||||
) : (
|
</Tab>
|
||||||
<div className="custom-sql-disabled-message">
|
<Tab
|
||||||
Custom SQL Filters are not available on druid datasources
|
className="adhoc-filter-edit-tab"
|
||||||
</div>
|
eventKey={EXPRESSION_TYPES.SQL}
|
||||||
)}
|
title="Custom SQL"
|
||||||
</Tab>
|
>
|
||||||
</Tabs>
|
{!this.props.datasource ||
|
||||||
<div>
|
this.props.datasource.type !== 'druid' ? (
|
||||||
<Button
|
<AdhocFilterEditPopoverSqlTabContent
|
||||||
disabled={!stateIsValid}
|
adhocFilter={this.state.adhocFilter}
|
||||||
bsStyle={hasUnsavedChanges && stateIsValid ? 'primary' : 'default'}
|
onChange={this.onAdhocFilterChange}
|
||||||
bsSize="small"
|
options={this.props.options}
|
||||||
className="m-r-5"
|
height={this.state.height}
|
||||||
onClick={this.onSave}
|
/>
|
||||||
>
|
) : (
|
||||||
Save
|
<div className="custom-sql-disabled-message">
|
||||||
</Button>
|
Custom SQL Filters are not available on druid datasources
|
||||||
<Button bsSize="small" onClick={this.props.onClose}>
|
</div>
|
||||||
Close
|
)}
|
||||||
</Button>
|
</Tab>
|
||||||
<i
|
</Tabs>
|
||||||
role="button"
|
<div>
|
||||||
tabIndex={0}
|
<Button
|
||||||
onMouseDown={this.onDragDown}
|
disabled={!stateIsValid}
|
||||||
className="fa fa-expand edit-popover-resize text-muted"
|
buttonStyle={
|
||||||
/>
|
hasUnsavedChanges && stateIsValid ? 'primary' : 'default'
|
||||||
</div>
|
}
|
||||||
|
buttonSize="small"
|
||||||
|
className="m-r-5"
|
||||||
|
onClick={this.onSave}
|
||||||
|
cta
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
<Button buttonSize="small" onClick={this.props.onClose} cta>
|
||||||
|
Close
|
||||||
|
</Button>
|
||||||
|
<i
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
onMouseDown={this.onDragDown}
|
||||||
|
className="fa fa-expand edit-popover-resize text-muted"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</ThemeProvider>
|
||||||
</Popover>
|
</Popover>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AdhocFilterEditPopover.propTypes = propTypes;
|
AdhocFilterEditPopover.propTypes = propTypes;
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import PropTypes from 'prop-types';
|
||||||
import { OverlayTrigger } from 'react-bootstrap';
|
import { OverlayTrigger } from 'react-bootstrap';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
|
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
|
||||||
|
import { withTheme } from '@superset-ui/style';
|
||||||
|
|
||||||
import Label from 'src/components/Label';
|
import Label from 'src/components/Label';
|
||||||
import AdhocFilterEditPopover from './AdhocFilterEditPopover';
|
import AdhocFilterEditPopover from './AdhocFilterEditPopover';
|
||||||
|
|
@ -41,8 +42,7 @@ const propTypes = {
|
||||||
datasource: PropTypes.object,
|
datasource: PropTypes.object,
|
||||||
partitionColumn: PropTypes.string,
|
partitionColumn: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
class AdhocFilterOption extends React.PureComponent {
|
||||||
export default class AdhocFilterOption extends React.PureComponent {
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.closeFilterEditOverlay = this.closeFilterEditOverlay.bind(this);
|
this.closeFilterEditOverlay = this.closeFilterEditOverlay.bind(this);
|
||||||
|
|
@ -73,7 +73,7 @@ export default class AdhocFilterOption extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { adhocFilter } = this.props;
|
const { adhocFilter, theme } = this.props;
|
||||||
const overlay = (
|
const overlay = (
|
||||||
<AdhocFilterEditPopover
|
<AdhocFilterEditPopover
|
||||||
onResize={this.onPopoverResize}
|
onResize={this.onPopoverResize}
|
||||||
|
|
@ -83,6 +83,7 @@ export default class AdhocFilterOption extends React.PureComponent {
|
||||||
options={this.props.options}
|
options={this.props.options}
|
||||||
datasource={this.props.datasource}
|
datasource={this.props.datasource}
|
||||||
partitionColumn={this.props.partitionColumn}
|
partitionColumn={this.props.partitionColumn}
|
||||||
|
theme={theme}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
|
|
@ -123,4 +124,7 @@ export default class AdhocFilterOption extends React.PureComponent {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default withTheme(AdhocFilterOption);
|
||||||
|
|
||||||
AdhocFilterOption.propTypes = propTypes;
|
AdhocFilterOption.propTypes = propTypes;
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Button, FormGroup, Popover, Tab, Tabs } from 'react-bootstrap';
|
import { FormGroup, Popover, Tab, Tabs } from 'react-bootstrap';
|
||||||
|
import Button from 'src/components/Button';
|
||||||
import Select from 'src/components/Select';
|
import Select from 'src/components/Select';
|
||||||
import ace from 'brace';
|
import ace from 'brace';
|
||||||
import AceEditor from 'react-ace';
|
import AceEditor from 'react-ace';
|
||||||
|
|
@ -27,6 +28,7 @@ import 'brace/theme/github';
|
||||||
import 'brace/ext/language_tools';
|
import 'brace/ext/language_tools';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
import { ColumnOption } from '@superset-ui/chart-controls';
|
import { ColumnOption } from '@superset-ui/chart-controls';
|
||||||
|
import { ThemeProvider } from '@superset-ui/style';
|
||||||
|
|
||||||
import FormLabel from 'src/components/FormLabel';
|
import FormLabel from 'src/components/FormLabel';
|
||||||
|
|
||||||
|
|
@ -45,6 +47,7 @@ const propTypes = {
|
||||||
onResize: PropTypes.func.isRequired,
|
onResize: PropTypes.func.isRequired,
|
||||||
columns: PropTypes.arrayOf(columnType),
|
columns: PropTypes.arrayOf(columnType),
|
||||||
datasourceType: PropTypes.string,
|
datasourceType: PropTypes.string,
|
||||||
|
theme: PropTypes.object,
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
|
|
@ -192,6 +195,7 @@ export default class AdhocMetricEditPopover extends React.Component {
|
||||||
onClose,
|
onClose,
|
||||||
onResize,
|
onResize,
|
||||||
datasourceType,
|
datasourceType,
|
||||||
|
theme,
|
||||||
...popoverProps
|
...popoverProps
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
|
@ -232,98 +236,104 @@ export default class AdhocMetricEditPopover extends React.Component {
|
||||||
const hasUnsavedChanges = !adhocMetric.equals(propsAdhocMetric);
|
const hasUnsavedChanges = !adhocMetric.equals(propsAdhocMetric);
|
||||||
return (
|
return (
|
||||||
<Popover id="metrics-edit-popover" title={popoverTitle} {...popoverProps}>
|
<Popover id="metrics-edit-popover" title={popoverTitle} {...popoverProps}>
|
||||||
<Tabs
|
<ThemeProvider theme={theme}>
|
||||||
id="adhoc-metric-edit-tabs"
|
<Tabs
|
||||||
defaultActiveKey={adhocMetric.expressionType}
|
id="adhoc-metric-edit-tabs"
|
||||||
className="adhoc-metric-edit-tabs"
|
defaultActiveKey={adhocMetric.expressionType}
|
||||||
style={{ height: this.state.height, width: this.state.width }}
|
className="adhoc-metric-edit-tabs"
|
||||||
onSelect={this.refreshAceEditor}
|
style={{ height: this.state.height, width: this.state.width }}
|
||||||
animation={false}
|
onSelect={this.refreshAceEditor}
|
||||||
>
|
animation={false}
|
||||||
<Tab
|
|
||||||
className="adhoc-metric-edit-tab"
|
|
||||||
eventKey={EXPRESSION_TYPES.SIMPLE}
|
|
||||||
title="Simple"
|
|
||||||
>
|
>
|
||||||
<FormGroup>
|
<Tab
|
||||||
<FormLabel>
|
className="adhoc-metric-edit-tab"
|
||||||
<strong>column</strong>
|
eventKey={EXPRESSION_TYPES.SIMPLE}
|
||||||
</FormLabel>
|
title="Simple"
|
||||||
<Select
|
>
|
||||||
name="select-column"
|
|
||||||
{...this.selectProps}
|
|
||||||
{...columnSelectProps}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
<FormGroup>
|
|
||||||
<FormLabel>
|
|
||||||
<strong>aggregate</strong>
|
|
||||||
</FormLabel>
|
|
||||||
<Select
|
|
||||||
name="select-aggregate"
|
|
||||||
{...this.selectProps}
|
|
||||||
{...aggregateSelectProps}
|
|
||||||
autoFocus
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
</Tab>
|
|
||||||
<Tab
|
|
||||||
className="adhoc-metric-edit-tab"
|
|
||||||
eventKey={EXPRESSION_TYPES.SQL}
|
|
||||||
title="Custom SQL"
|
|
||||||
data-test="adhoc-metric-edit-tab#custom"
|
|
||||||
>
|
|
||||||
{this.props.datasourceType !== 'druid' ? (
|
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<AceEditor
|
<FormLabel>
|
||||||
ref={this.handleAceEditorRef}
|
<strong>column</strong>
|
||||||
mode="sql"
|
</FormLabel>
|
||||||
theme="github"
|
<Select
|
||||||
height={`${this.state.height - 43}px`}
|
name="select-column"
|
||||||
onChange={this.onSqlExpressionChange}
|
{...this.selectProps}
|
||||||
width="100%"
|
{...columnSelectProps}
|
||||||
showGutter={false}
|
|
||||||
value={
|
|
||||||
adhocMetric.sqlExpression || adhocMetric.translateToSql()
|
|
||||||
}
|
|
||||||
editorProps={{ $blockScrolling: true }}
|
|
||||||
enableLiveAutocompletion
|
|
||||||
className="adhoc-filter-sql-editor"
|
|
||||||
wrapEnabled
|
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
) : (
|
<FormGroup>
|
||||||
<div className="custom-sql-disabled-message">
|
<FormLabel>
|
||||||
Custom SQL Metrics are not available on druid datasources
|
<strong>aggregate</strong>
|
||||||
</div>
|
</FormLabel>
|
||||||
)}
|
<Select
|
||||||
</Tab>
|
name="select-aggregate"
|
||||||
</Tabs>
|
{...this.selectProps}
|
||||||
<div>
|
{...aggregateSelectProps}
|
||||||
<Button
|
autoFocus
|
||||||
disabled={!stateIsValid}
|
/>
|
||||||
bsStyle={hasUnsavedChanges && stateIsValid ? 'primary' : 'default'}
|
</FormGroup>
|
||||||
bsSize="small"
|
</Tab>
|
||||||
className="m-r-5"
|
<Tab
|
||||||
data-test="AdhocMetricEdit#save"
|
className="adhoc-metric-edit-tab"
|
||||||
onClick={this.onSave}
|
eventKey={EXPRESSION_TYPES.SQL}
|
||||||
>
|
title="Custom SQL"
|
||||||
Save
|
data-test="adhoc-metric-edit-tab#custom"
|
||||||
</Button>
|
>
|
||||||
<Button
|
{this.props.datasourceType !== 'druid' ? (
|
||||||
bsSize="small"
|
<FormGroup>
|
||||||
onClick={this.props.onClose}
|
<AceEditor
|
||||||
data-test="AdhocMetricEdit#cancel"
|
ref={this.handleAceEditorRef}
|
||||||
>
|
mode="sql"
|
||||||
Close
|
theme="github"
|
||||||
</Button>
|
height={`${this.state.height - 43}px`}
|
||||||
<i
|
onChange={this.onSqlExpressionChange}
|
||||||
role="button"
|
width="100%"
|
||||||
tabIndex={0}
|
showGutter={false}
|
||||||
onMouseDown={this.onDragDown}
|
value={
|
||||||
className="fa fa-expand edit-popover-resize text-muted"
|
adhocMetric.sqlExpression || adhocMetric.translateToSql()
|
||||||
/>
|
}
|
||||||
</div>
|
editorProps={{ $blockScrolling: true }}
|
||||||
|
enableLiveAutocompletion
|
||||||
|
className="adhoc-filter-sql-editor"
|
||||||
|
wrapEnabled
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
) : (
|
||||||
|
<div className="custom-sql-disabled-message">
|
||||||
|
Custom SQL Metrics are not available on druid datasources
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Tab>
|
||||||
|
</Tabs>
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
disabled={!stateIsValid}
|
||||||
|
buttonStyle={
|
||||||
|
hasUnsavedChanges && stateIsValid ? 'primary' : 'default'
|
||||||
|
}
|
||||||
|
buttonSize="small"
|
||||||
|
className="m-r-5"
|
||||||
|
data-test="AdhocMetricEdit#save"
|
||||||
|
onClick={this.onSave}
|
||||||
|
cta
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
buttonSize="small"
|
||||||
|
onClick={this.props.onClose}
|
||||||
|
data-test="AdhocMetricEdit#cancel"
|
||||||
|
cta
|
||||||
|
>
|
||||||
|
Close
|
||||||
|
</Button>
|
||||||
|
<i
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
onMouseDown={this.onDragDown}
|
||||||
|
className="fa fa-expand edit-popover-resize text-muted"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</ThemeProvider>
|
||||||
</Popover>
|
</Popover>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { OverlayTrigger } from 'react-bootstrap';
|
import { OverlayTrigger } from 'react-bootstrap';
|
||||||
|
import { withTheme } from '@superset-ui/style';
|
||||||
|
|
||||||
import Label from 'src/components/Label';
|
import Label from 'src/components/Label';
|
||||||
import AdhocMetricEditPopover from './AdhocMetricEditPopover';
|
import AdhocMetricEditPopover from './AdhocMetricEditPopover';
|
||||||
|
|
@ -33,7 +34,7 @@ const propTypes = {
|
||||||
datasourceType: PropTypes.string,
|
datasourceType: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class AdhocMetricOption extends React.PureComponent {
|
class AdhocMetricOption extends React.PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.closeMetricEditOverlay = this.closeMetricEditOverlay.bind(this);
|
this.closeMetricEditOverlay = this.closeMetricEditOverlay.bind(this);
|
||||||
|
|
@ -65,7 +66,7 @@ export default class AdhocMetricOption extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { adhocMetric } = this.props;
|
const { adhocMetric, theme } = this.props;
|
||||||
const overlayContent = (
|
const overlayContent = (
|
||||||
<AdhocMetricEditPopover
|
<AdhocMetricEditPopover
|
||||||
onResize={this.onPopoverResize}
|
onResize={this.onPopoverResize}
|
||||||
|
|
@ -74,6 +75,7 @@ export default class AdhocMetricOption extends React.PureComponent {
|
||||||
onClose={this.closeMetricEditOverlay}
|
onClose={this.closeMetricEditOverlay}
|
||||||
columns={this.props.columns}
|
columns={this.props.columns}
|
||||||
datasourceType={this.props.datasourceType}
|
datasourceType={this.props.datasourceType}
|
||||||
|
theme={theme}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -109,4 +111,7 @@ export default class AdhocMetricOption extends React.PureComponent {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default withTheme(AdhocMetricOption);
|
||||||
|
|
||||||
AdhocMetricOption.propTypes = propTypes;
|
AdhocMetricOption.propTypes = propTypes;
|
||||||
|
|
|
||||||
|
|
@ -38,13 +38,13 @@ import {
|
||||||
import { Table } from 'reactable-arc';
|
import { Table } from 'reactable-arc';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
|
|
||||||
|
import Button from 'src/components/Button';
|
||||||
import getClientErrorObject from '../../utils/getClientErrorObject';
|
import getClientErrorObject from '../../utils/getClientErrorObject';
|
||||||
import CopyToClipboard from './../../components/CopyToClipboard';
|
import CopyToClipboard from './../../components/CopyToClipboard';
|
||||||
import { getChartDataRequest } from '../../chart/chartAction';
|
import { getChartDataRequest } from '../../chart/chartAction';
|
||||||
import downloadAsImage from '../../utils/downloadAsImage';
|
import downloadAsImage from '../../utils/downloadAsImage';
|
||||||
import Loading from '../../components/Loading';
|
import Loading from '../../components/Loading';
|
||||||
import ModalTrigger from './../../components/ModalTrigger';
|
import ModalTrigger from './../../components/ModalTrigger';
|
||||||
import Button from '../../components/Button';
|
|
||||||
import RowCountLabel from './RowCountLabel';
|
import RowCountLabel from './RowCountLabel';
|
||||||
import {
|
import {
|
||||||
applyFormattingToTabularData,
|
applyFormattingToTabularData,
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ export default function ExploreActionButtons({
|
||||||
slice,
|
slice,
|
||||||
}) {
|
}) {
|
||||||
const exportToCSVClasses = cx('btn btn-default btn-sm', {
|
const exportToCSVClasses = cx('btn btn-default btn-sm', {
|
||||||
'disabled disabledButton': !canDownload,
|
disabled: !canDownload,
|
||||||
});
|
});
|
||||||
const doExportCSV = exportChart.bind(this, {
|
const doExportCSV = exportChart.bind(this, {
|
||||||
formData: latestQueryFormData,
|
formData: latestQueryFormData,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@
|
||||||
*/
|
*/
|
||||||
import React, { useState, useEffect, useRef } from 'react';
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
import {
|
import {
|
||||||
Button,
|
|
||||||
Modal,
|
Modal,
|
||||||
Row,
|
Row,
|
||||||
Col,
|
Col,
|
||||||
|
|
@ -26,6 +25,7 @@ import {
|
||||||
FormGroup,
|
FormGroup,
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
} from 'react-bootstrap';
|
} from 'react-bootstrap';
|
||||||
|
import Button from 'src/components/Button';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import Dialog from 'react-bootstrap-dialog';
|
import Dialog from 'react-bootstrap-dialog';
|
||||||
import { OptionsType } from 'react-select/src/types';
|
import { OptionsType } from 'react-select/src/types';
|
||||||
|
|
@ -263,15 +263,15 @@ function PropertiesModal({ slice, onHide, onSave }: InternalProps) {
|
||||||
</Row>
|
</Row>
|
||||||
</Modal.Body>
|
</Modal.Body>
|
||||||
<Modal.Footer>
|
<Modal.Footer>
|
||||||
<Button type="button" bsSize="sm" onClick={onHide}>
|
<Button type="button" buttonSize="sm" onClick={onHide} cta>
|
||||||
{t('Cancel')}
|
{t('Cancel')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
bsSize="sm"
|
buttonSize="sm"
|
||||||
bsStyle="primary"
|
buttonStyle="primary"
|
||||||
className="m-r-5"
|
|
||||||
disabled={!owners || submitting || !name}
|
disabled={!owners || submitting || !name}
|
||||||
|
cta
|
||||||
>
|
>
|
||||||
{t('Save')}
|
{t('Save')}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,10 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { ButtonGroup, OverlayTrigger, Tooltip } from 'react-bootstrap';
|
import { ButtonGroup, OverlayTrigger, Tooltip } from 'react-bootstrap';
|
||||||
import classnames from 'classnames';
|
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
import styled from '@superset-ui/style';
|
import styled from '@superset-ui/style';
|
||||||
|
|
||||||
import Button from '../../components/Button';
|
import Button from 'src/components/Button';
|
||||||
import Hotkeys from '../../components/Hotkeys';
|
import Hotkeys from '../../components/Hotkeys';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
|
|
@ -61,7 +60,8 @@ const Styles = styled.div`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding-bottom: ${({ theme }) => 2 * theme.gridUnit}px;
|
padding-bottom: ${({ theme }) => 2 * theme.gridUnit}px;
|
||||||
|
|
||||||
.save-btn {
|
.btn {
|
||||||
|
/* just to make sure buttons don't jiggle */
|
||||||
width: 100px;
|
width: 100px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
@ -75,12 +75,7 @@ export default function QueryAndSaveBtns({
|
||||||
chartIsStale,
|
chartIsStale,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
}) {
|
}) {
|
||||||
const saveClasses = classnames({
|
let qryButtonStyle = 'secondary';
|
||||||
'disabled disabledButton': !canAdd,
|
|
||||||
'save-btn': true,
|
|
||||||
});
|
|
||||||
|
|
||||||
let qryButtonStyle = 'default';
|
|
||||||
if (errorMessage) {
|
if (errorMessage) {
|
||||||
qryButtonStyle = 'danger';
|
qryButtonStyle = 'danger';
|
||||||
} else if (chartIsStale) {
|
} else if (chartIsStale) {
|
||||||
|
|
@ -89,15 +84,21 @@ export default function QueryAndSaveBtns({
|
||||||
|
|
||||||
const saveButtonDisabled = errorMessage ? true : loading;
|
const saveButtonDisabled = errorMessage ? true : loading;
|
||||||
const qryOrStopButton = loading ? (
|
const qryOrStopButton = loading ? (
|
||||||
<Button onClick={onStop} bsStyle="warning" className="save-btn">
|
<Button
|
||||||
|
onClick={onStop}
|
||||||
|
buttonStyle="warning"
|
||||||
|
buttonSize="small"
|
||||||
|
disabled={!canAdd}
|
||||||
|
>
|
||||||
<i className="fa fa-stop-circle-o" /> Stop
|
<i className="fa fa-stop-circle-o" /> Stop
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
) : (
|
||||||
<Button
|
<Button
|
||||||
className="query save-btn"
|
buttonSize="small"
|
||||||
onClick={onQuery}
|
onClick={onQuery}
|
||||||
bsStyle={qryButtonStyle}
|
buttonStyle={qryButtonStyle}
|
||||||
disabled={!!errorMessage}
|
disabled={!!errorMessage}
|
||||||
|
data-test="run-query-button"
|
||||||
>
|
>
|
||||||
<i className="fa fa-bolt" /> {t('Run')}
|
<i className="fa fa-bolt" /> {t('Run')}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -109,7 +110,8 @@ export default function QueryAndSaveBtns({
|
||||||
<ButtonGroup className="query-and-save">
|
<ButtonGroup className="query-and-save">
|
||||||
{qryOrStopButton}
|
{qryOrStopButton}
|
||||||
<Button
|
<Button
|
||||||
className={saveClasses}
|
buttonStyle="secondary"
|
||||||
|
buttonSize="small"
|
||||||
data-target="#save_modal"
|
data-target="#save_modal"
|
||||||
data-toggle="modal"
|
data-toggle="modal"
|
||||||
disabled={saveButtonDisabled}
|
disabled={saveButtonDisabled}
|
||||||
|
|
|
||||||
|
|
@ -20,14 +20,8 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import {
|
import { Alert, FormControl, FormGroup, Modal, Radio } from 'react-bootstrap';
|
||||||
Alert,
|
import Button from 'src/components/Button';
|
||||||
Button,
|
|
||||||
FormControl,
|
|
||||||
FormGroup,
|
|
||||||
Modal,
|
|
||||||
Radio,
|
|
||||||
} from 'react-bootstrap';
|
|
||||||
import FormLabel from 'src/components/FormLabel';
|
import FormLabel from 'src/components/FormLabel';
|
||||||
import { CreatableSelect } from 'src/components/Select/SupersetStyledSelect';
|
import { CreatableSelect } from 'src/components/Select/SupersetStyledSelect';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
|
|
@ -208,18 +202,12 @@ class SaveModal extends React.Component {
|
||||||
|
|
||||||
<Modal.Footer>
|
<Modal.Footer>
|
||||||
<div className="float-right">
|
<div className="float-right">
|
||||||
<Button
|
<Button id="btn_cancel" buttonSize="sm" onClick={this.props.onHide}>
|
||||||
type="button"
|
|
||||||
id="btn_cancel"
|
|
||||||
bsSize="sm"
|
|
||||||
onClick={this.props.onHide}
|
|
||||||
>
|
|
||||||
{t('Cancel')}
|
{t('Cancel')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
|
||||||
id="btn_modal_save_goto_dash"
|
id="btn_modal_save_goto_dash"
|
||||||
bsSize="sm"
|
buttonSize="sm"
|
||||||
disabled={
|
disabled={
|
||||||
!this.state.newSliceName || !this.state.newDashboardName
|
!this.state.newSliceName || !this.state.newDashboardName
|
||||||
}
|
}
|
||||||
|
|
@ -228,10 +216,9 @@ class SaveModal extends React.Component {
|
||||||
{t('Save & go to dashboard')}
|
{t('Save & go to dashboard')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
|
||||||
id="btn_modal_save"
|
id="btn_modal_save"
|
||||||
bsSize="sm"
|
buttonSize="sm"
|
||||||
bsStyle="primary"
|
buttonStyle="primary"
|
||||||
onClick={this.saveOrOverwrite.bind(this, false)}
|
onClick={this.saveOrOverwrite.bind(this, false)}
|
||||||
disabled={!this.state.newSliceName}
|
disabled={!this.state.newSliceName}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -19,13 +19,14 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { CompactPicker } from 'react-color';
|
import { CompactPicker } from 'react-color';
|
||||||
import { Button } from 'react-bootstrap';
|
import Button from 'src/components/Button';
|
||||||
import mathjs from 'mathjs';
|
import mathjs from 'mathjs';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
import { SupersetClient } from '@superset-ui/connection';
|
import { SupersetClient } from '@superset-ui/connection';
|
||||||
import { getCategoricalSchemeRegistry } from '@superset-ui/color';
|
import { getCategoricalSchemeRegistry } from '@superset-ui/color';
|
||||||
import { getChartMetadataRegistry } from '@superset-ui/chart';
|
import { getChartMetadataRegistry } from '@superset-ui/chart';
|
||||||
import { validateNonEmpty } from '@superset-ui/validator';
|
import { validateNonEmpty } from '@superset-ui/validator';
|
||||||
|
import { ThemeProvider } from '@superset-ui/style';
|
||||||
|
|
||||||
import SelectControl from './SelectControl';
|
import SelectControl from './SelectControl';
|
||||||
import TextControl from './TextControl';
|
import TextControl from './TextControl';
|
||||||
|
|
@ -63,6 +64,7 @@ const propTypes = {
|
||||||
timeColumn: PropTypes.string,
|
timeColumn: PropTypes.string,
|
||||||
intervalEndColumn: PropTypes.string,
|
intervalEndColumn: PropTypes.string,
|
||||||
vizType: PropTypes.string,
|
vizType: PropTypes.string,
|
||||||
|
theme: PropTypes.object,
|
||||||
|
|
||||||
error: PropTypes.string,
|
error: PropTypes.string,
|
||||||
colorScheme: PropTypes.string,
|
colorScheme: PropTypes.string,
|
||||||
|
|
@ -619,8 +621,8 @@ export default class AnnotationLayer extends React.PureComponent {
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
style={{ marginTop: '0.5rem', marginBottom: '0.5rem' }}
|
style={{ marginTop: '0.5rem', marginBottom: '0.5rem' }}
|
||||||
bsStyle={color === AUTOMATIC_COLOR ? 'success' : 'default'}
|
buttonStyle={color === AUTOMATIC_COLOR ? 'success' : 'default'}
|
||||||
bsSize="xsmall"
|
buttonSize="xsmall"
|
||||||
onClick={() => this.setState({ color: AUTOMATIC_COLOR })}
|
onClick={() => this.setState({ color: AUTOMATIC_COLOR })}
|
||||||
>
|
>
|
||||||
Automatic Color
|
Automatic Color
|
||||||
|
|
@ -661,7 +663,7 @@ export default class AnnotationLayer extends React.PureComponent {
|
||||||
render() {
|
render() {
|
||||||
const { isNew, name, annotationType, sourceType, show } = this.state;
|
const { isNew, name, annotationType, sourceType, show } = this.state;
|
||||||
const isValid = this.isValidForm();
|
const isValid = this.isValidForm();
|
||||||
|
const { theme } = this.props;
|
||||||
const metadata = getChartMetadataRegistry().get(this.props.vizType);
|
const metadata = getChartMetadataRegistry().get(this.props.vizType);
|
||||||
const supportedAnnotationTypes = metadata
|
const supportedAnnotationTypes = metadata
|
||||||
? metadata.supportedAnnotationTypes.map(
|
? metadata.supportedAnnotationTypes.map(
|
||||||
|
|
@ -671,7 +673,7 @@ export default class AnnotationLayer extends React.PureComponent {
|
||||||
const supportedSourceTypes = this.getSupportedSourceTypes(annotationType);
|
const supportedSourceTypes = this.getSupportedSourceTypes(annotationType);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<ThemeProvider theme={theme}>
|
||||||
{this.props.error && (
|
{this.props.error && (
|
||||||
<span style={{ color: 'red' }}>ERROR: {this.props.error}</span>
|
<span style={{ color: 'red' }}>ERROR: {this.props.error}</span>
|
||||||
)}
|
)}
|
||||||
|
|
@ -724,12 +726,12 @@ export default class AnnotationLayer extends React.PureComponent {
|
||||||
{this.renderDisplayConfiguration()}
|
{this.renderDisplayConfiguration()}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||||
<Button bsSize="sm" onClick={this.deleteAnnotation}>
|
<Button buttonSize="sm" onClick={this.deleteAnnotation}>
|
||||||
{!isNew ? t('Remove') : t('Cancel')}
|
{!isNew ? t('Remove') : t('Cancel')}
|
||||||
</Button>
|
</Button>
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button
|
||||||
bsSize="sm"
|
buttonSize="sm"
|
||||||
disabled={!isValid}
|
disabled={!isValid}
|
||||||
onClick={this.applyAnnotation}
|
onClick={this.applyAnnotation}
|
||||||
>
|
>
|
||||||
|
|
@ -737,7 +739,7 @@ export default class AnnotationLayer extends React.PureComponent {
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
bsSize="sm"
|
buttonSize="sm"
|
||||||
disabled={!isValid}
|
disabled={!isValid}
|
||||||
onClick={this.submitAnnotation}
|
onClick={this.submitAnnotation}
|
||||||
>
|
>
|
||||||
|
|
@ -745,7 +747,7 @@ export default class AnnotationLayer extends React.PureComponent {
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import {
|
||||||
} from 'react-bootstrap';
|
} from 'react-bootstrap';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
|
import { withTheme } from '@superset-ui/style';
|
||||||
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
|
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
|
||||||
import { getChartKey } from '../../exploreUtils';
|
import { getChartKey } from '../../exploreUtils';
|
||||||
import { runAnnotationQuery } from '../../../chart/chartAction';
|
import { runAnnotationQuery } from '../../../chart/chartAction';
|
||||||
|
|
@ -100,6 +101,7 @@ class AnnotationLayerControl extends React.PureComponent {
|
||||||
|
|
||||||
renderPopover(parent, annotation, error) {
|
renderPopover(parent, annotation, error) {
|
||||||
const id = !annotation ? '_new' : annotation.name;
|
const id = !annotation ? '_new' : annotation.name;
|
||||||
|
const { theme } = this.props;
|
||||||
return (
|
return (
|
||||||
<Popover
|
<Popover
|
||||||
style={{ maxWidth: 'none' }}
|
style={{ maxWidth: 'none' }}
|
||||||
|
|
@ -116,6 +118,7 @@ class AnnotationLayerControl extends React.PureComponent {
|
||||||
addAnnotationLayer={this.addAnnotationLayer}
|
addAnnotationLayer={this.addAnnotationLayer}
|
||||||
removeAnnotationLayer={this.removeAnnotationLayer}
|
removeAnnotationLayer={this.removeAnnotationLayer}
|
||||||
close={() => this.refs[parent].hide()}
|
close={() => this.refs[parent].hide()}
|
||||||
|
theme={theme}
|
||||||
/>
|
/>
|
||||||
</Popover>
|
</Popover>
|
||||||
);
|
);
|
||||||
|
|
@ -208,7 +211,9 @@ function mapDispatchToProps(dispatch) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const themedAnnotationLayerControl = withTheme(AnnotationLayerControl);
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
mapDispatchToProps,
|
mapDispatchToProps,
|
||||||
)(AnnotationLayerControl);
|
)(themedAnnotationLayerControl);
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {
|
import {
|
||||||
Button,
|
|
||||||
DropdownButton,
|
DropdownButton,
|
||||||
FormControl,
|
FormControl,
|
||||||
FormGroup,
|
FormGroup,
|
||||||
|
|
@ -32,6 +31,7 @@ import {
|
||||||
Tabs,
|
Tabs,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from 'react-bootstrap';
|
} from 'react-bootstrap';
|
||||||
|
import Button from 'src/components/Button';
|
||||||
import Datetime from 'react-datetime';
|
import Datetime from 'react-datetime';
|
||||||
import 'react-datetime/css/react-datetime.css';
|
import 'react-datetime/css/react-datetime.css';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
@ -365,7 +365,7 @@ class DateFilterControl extends React.Component {
|
||||||
onClick={() => {}}
|
onClick={() => {}}
|
||||||
/>
|
/>
|
||||||
<InputGroup.Button onClick={() => this.toggleCalendar(key)}>
|
<InputGroup.Button onClick={() => this.toggleCalendar(key)}>
|
||||||
<Button>
|
<Button theme={this.props.theme}>
|
||||||
<i className="fa fa-calendar" />
|
<i className="fa fa-calendar" />
|
||||||
</Button>
|
</Button>
|
||||||
</InputGroup.Button>
|
</InputGroup.Button>
|
||||||
|
|
@ -563,10 +563,11 @@ class DateFilterControl extends React.Component {
|
||||||
</Tabs>
|
</Tabs>
|
||||||
<div className="clearfix">
|
<div className="clearfix">
|
||||||
<Button
|
<Button
|
||||||
bsSize="small"
|
buttonSize="small"
|
||||||
className="float-right ok"
|
className="float-right ok"
|
||||||
bsStyle="primary"
|
buttonStyle="primary"
|
||||||
onClick={this.close}
|
onClick={this.close}
|
||||||
|
theme={this.props.theme}
|
||||||
>
|
>
|
||||||
Ok
|
Ok
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Row, Col, Button, OverlayTrigger, Popover } from 'react-bootstrap';
|
import { Row, Col, OverlayTrigger, Popover } from 'react-bootstrap';
|
||||||
|
import Button from 'src/components/Button';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
|
|
||||||
import Label from 'src/components/Label';
|
import Label from 'src/components/Label';
|
||||||
|
|
@ -204,9 +205,9 @@ export default class SpatialControl extends React.Component {
|
||||||
</PopoverSection>
|
</PopoverSection>
|
||||||
<div className="clearfix">
|
<div className="clearfix">
|
||||||
<Button
|
<Button
|
||||||
bsSize="small"
|
buttonSize="small"
|
||||||
className="float-left ok"
|
className="float-left ok"
|
||||||
bsStyle="primary"
|
buttonStyle="primary"
|
||||||
onClick={this.close.bind(this)}
|
onClick={this.close.bind(this)}
|
||||||
>
|
>
|
||||||
Ok
|
Ok
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Button, FormGroup, FormControl } from 'react-bootstrap';
|
import { FormGroup, FormControl } from 'react-bootstrap';
|
||||||
|
import Button from 'src/components/Button';
|
||||||
|
|
||||||
import AceEditor from 'react-ace';
|
import AceEditor from 'react-ace';
|
||||||
import 'brace/mode/sql';
|
import 'brace/mode/sql';
|
||||||
|
|
@ -121,7 +122,7 @@ export default class TextAreaControl extends React.Component {
|
||||||
bsSize="large"
|
bsSize="large"
|
||||||
modalTitle={controlHeader}
|
modalTitle={controlHeader}
|
||||||
triggerNode={
|
triggerNode={
|
||||||
<Button bsSize="small" className="m-t-5">
|
<Button buttonSize="small" className="m-t-5">
|
||||||
{t('Edit')} <strong>{this.props.language}</strong>{' '}
|
{t('Edit')} <strong>{this.props.language}</strong>{' '}
|
||||||
{t('in modal')}
|
{t('in modal')}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -1,72 +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 styled from '@superset-ui/style';
|
|
||||||
import BaseButton from 'src/components/Button';
|
|
||||||
|
|
||||||
interface ModalProps {
|
|
||||||
children: React.ReactNode;
|
|
||||||
disabled?: boolean;
|
|
||||||
onClick: () => void;
|
|
||||||
padding?: number;
|
|
||||||
bsStyle?: 'default' | 'primary' | 'danger';
|
|
||||||
width?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const StyledButton = styled(BaseButton)`
|
|
||||||
border-radius: ${({ theme }) => theme.borderRadius}px;
|
|
||||||
border: none;
|
|
||||||
padding: ${(props: ModalProps) => props.padding || 8}px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
width: ${(props: ModalProps) => props.width || 160}px;
|
|
||||||
|
|
||||||
&.btn,
|
|
||||||
&.btn:hover {
|
|
||||||
background-color: ${({ theme }) => theme.colors.primary.light4};
|
|
||||||
color: ${({ theme }) => theme.colors.primary.base};
|
|
||||||
}
|
|
||||||
&.btn[disabled],
|
|
||||||
&.btn[disabled]:hover {
|
|
||||||
background-color: ${({ theme }) => theme.colors.grayscale.light2};
|
|
||||||
color: ${({ theme }) => theme.colors.grayscale.light1};
|
|
||||||
}
|
|
||||||
&.btn-primary,
|
|
||||||
&.btn-primary:hover {
|
|
||||||
background-color: ${({ theme }) => theme.colors.primary.base};
|
|
||||||
color: ${({ theme }) => theme.colors.grayscale.light5};
|
|
||||||
}
|
|
||||||
&.btn-danger,
|
|
||||||
&.btn-danger:hover {
|
|
||||||
background-color: ${({ theme }) => theme.colors.error.base};
|
|
||||||
color: ${({ theme }) => theme.colors.grayscale.light5};
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export default function Modal({
|
|
||||||
bsStyle = 'default',
|
|
||||||
disabled,
|
|
||||||
onClick,
|
|
||||||
children,
|
|
||||||
}: ModalProps) {
|
|
||||||
return (
|
|
||||||
<StyledButton disabled={disabled} bsStyle={bsStyle} onClick={onClick}>
|
|
||||||
{children}
|
|
||||||
</StyledButton>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -21,7 +21,7 @@ import PropTypes from 'prop-types';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import { max as d3Max } from 'd3-array';
|
import { max as d3Max } from 'd3-array';
|
||||||
import { AsyncCreatableSelect, CreatableSelect } from 'src/components/Select';
|
import { AsyncCreatableSelect, CreatableSelect } from 'src/components/Select';
|
||||||
import { Button } from 'react-bootstrap';
|
import Button from 'src/components/Button';
|
||||||
import { t } from '@superset-ui/translation';
|
import { t } from '@superset-ui/translation';
|
||||||
import { SupersetClient } from '@superset-ui/connection';
|
import { SupersetClient } from '@superset-ui/connection';
|
||||||
import styled from '@superset-ui/style';
|
import styled from '@superset-ui/style';
|
||||||
|
|
@ -438,8 +438,8 @@ class FilterBox extends React.Component {
|
||||||
{this.renderFilters()}
|
{this.renderFilters()}
|
||||||
{!instantFiltering && (
|
{!instantFiltering && (
|
||||||
<Button
|
<Button
|
||||||
bsSize="small"
|
buttonSize="small"
|
||||||
bsStyle="primary"
|
buttonStyle="primary"
|
||||||
onClick={this.clickApply.bind(this)}
|
onClick={this.clickApply.bind(this)}
|
||||||
disabled={!this.state.hasChanged}
|
disabled={!this.state.hasChanged}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -196,6 +196,10 @@ table.table-no-hover tr:hover {
|
||||||
background-color: initial;
|
background-color: initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.editable-title {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.editable-title input {
|
.editable-title input {
|
||||||
outline: none;
|
outline: none;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
|
||||||
|
|
||||||
import { exploreChart } from '../../explore/exploreUtils';
|
import { exploreChart } from '../../explore/exploreUtils';
|
||||||
import * as actions from '../actions/sqlLab';
|
import * as actions from '../actions/sqlLab';
|
||||||
import Button from '../../components/Button';
|
import Button from 'src/components/Button';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
actions: PropTypes.object.isRequired,
|
actions: PropTypes.object.isRequired,
|
||||||
|
|
@ -88,7 +88,7 @@ class ExploreCtasResultsButton extends React.PureComponent {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
bsSize="small"
|
buttonSize="small"
|
||||||
onClick={this.onClick}
|
onClick={this.onClick}
|
||||||
tooltip={t('Explore the result set in the data exploration view')}
|
tooltip={t('Explore the result set in the data exploration view')}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue