chore: upgrade eslint, babel, and prettier (#12393)
This commit is contained in:
parent
6bee3a0581
commit
9acf48fd1e
|
|
@ -135,6 +135,7 @@ module.exports = {
|
|||
'react/no-unused-prop-types': 0,
|
||||
'react/prop-types': 0,
|
||||
'react/require-default-props': 0,
|
||||
'react/sort-comp': 0, // TODO: re-enable in separate PR
|
||||
'react/static-property-placement': 0, // re-enable up for discussion
|
||||
'prettier/prettier': 'error',
|
||||
},
|
||||
|
|
@ -246,6 +247,7 @@ module.exports = {
|
|||
'react/no-unused-prop-types': 0,
|
||||
'react/prop-types': 0,
|
||||
'react/require-default-props': 0,
|
||||
'react/sort-comp': 0, // TODO: re-enable in separate PR
|
||||
'react/static-property-placement': 0, // disabled temporarily
|
||||
'prettier/prettier': 'error',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -42,8 +42,9 @@ module.exports = {
|
|||
plugins: [
|
||||
'lodash',
|
||||
'@babel/plugin-syntax-dynamic-import',
|
||||
'@babel/plugin-proposal-class-properties',
|
||||
'@babel/plugin-proposal-optional-chaining',
|
||||
['@babel/plugin-proposal-class-properties', { loose: true }],
|
||||
['@babel/plugin-proposal-optional-chaining', { loose: true }],
|
||||
['@babel/plugin-proposal-private-methods', { loose: true }],
|
||||
['@babel/plugin-transform-runtime', { corejs: 3 }],
|
||||
'react-hot-loader/babel',
|
||||
],
|
||||
|
|
|
|||
|
|
@ -40,9 +40,7 @@ describe('Dashboard filter', () => {
|
|||
let filterId: number;
|
||||
let aliases: string[];
|
||||
|
||||
const getAlias = (id: number) => {
|
||||
return `@${DASHBOARD_CHART_ALIAS_PREFIX}${id}`;
|
||||
};
|
||||
const getAlias = (id: number) => `@${DASHBOARD_CHART_ALIAS_PREFIX}${id}`;
|
||||
|
||||
beforeEach(() => {
|
||||
cy.server();
|
||||
|
|
@ -87,8 +85,8 @@ describe('Dashboard filter', () => {
|
|||
});
|
||||
|
||||
cy.get('.filter_box button').click({ force: true });
|
||||
cy.wait(aliases.filter(x => x !== getAlias(filterId))).then(requests => {
|
||||
return Promise.all(
|
||||
cy.wait(aliases.filter(x => x !== getAlias(filterId))).then(requests =>
|
||||
Promise.all(
|
||||
requests.map(async xhr => {
|
||||
expect(xhr.status).to.eq(200);
|
||||
const responseBody = await readResponseBlob(xhr.response.body);
|
||||
|
|
@ -108,8 +106,8 @@ describe('Dashboard filter', () => {
|
|||
val: 'South Asia',
|
||||
});
|
||||
}),
|
||||
);
|
||||
});
|
||||
),
|
||||
);
|
||||
|
||||
// TODO add test with South Asia{enter} type action to select filter
|
||||
});
|
||||
|
|
|
|||
|
|
@ -44,8 +44,8 @@ describe('Dashboard load', () => {
|
|||
|
||||
it('should load dashboard', () => {
|
||||
// wait and verify one-by-one
|
||||
cy.wait(aliases).then(requests => {
|
||||
return Promise.all(
|
||||
cy.wait(aliases).then(requests =>
|
||||
Promise.all(
|
||||
requests.map(async xhr => {
|
||||
expect(xhr.status).to.eq(200);
|
||||
const responseBody = await readResponseBlob(xhr.response.body);
|
||||
|
|
@ -65,7 +65,7 @@ describe('Dashboard load', () => {
|
|||
.find(`#chart-id-${sliceId}`)
|
||||
.should('be.visible');
|
||||
}),
|
||||
);
|
||||
});
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ describe('Dashboard form data', () => {
|
|||
it('should apply url params to slice requests', () => {
|
||||
const aliases = getChartAliases(dashboard.slices);
|
||||
// wait and verify one-by-one
|
||||
cy.wait(aliases).then(requests => {
|
||||
return Promise.all(
|
||||
cy.wait(aliases).then(requests =>
|
||||
Promise.all(
|
||||
requests.map(async xhr => {
|
||||
expect(xhr.status).to.eq(200);
|
||||
const responseBody = await readResponseBlob(xhr.response.body);
|
||||
|
|
@ -55,7 +55,7 @@ describe('Dashboard form data', () => {
|
|||
});
|
||||
}
|
||||
}),
|
||||
);
|
||||
});
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -24,9 +24,8 @@ import rison from 'rison';
|
|||
import shortid from 'shortid';
|
||||
import { HEALTH_POP_FORM_DATA_DEFAULTS } from './visualizations/shared.helper';
|
||||
|
||||
const apiURL = (endpoint, queryObject) => {
|
||||
return `${endpoint}?q=${rison.encode(queryObject)}`;
|
||||
};
|
||||
const apiURL = (endpoint, queryObject) =>
|
||||
`${endpoint}?q=${rison.encode(queryObject)}`;
|
||||
|
||||
describe('Test explore links', () => {
|
||||
beforeEach(() => {
|
||||
|
|
|
|||
|
|
@ -48,9 +48,9 @@ Cypress.Commands.add('visitChartByName', name => {
|
|||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('visitChartById', chartId => {
|
||||
return cy.visit(`${BASE_EXPLORE_URL}{"slice_id": ${chartId}}`);
|
||||
});
|
||||
Cypress.Commands.add('visitChartById', chartId =>
|
||||
cy.visit(`${BASE_EXPLORE_URL}{"slice_id": ${chartId}}`),
|
||||
);
|
||||
|
||||
Cypress.Commands.add('visitChartByParams', params => {
|
||||
const queryString =
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -62,7 +62,7 @@
|
|||
"homepage": "https://superset.apache.org/",
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^4.2.2",
|
||||
"@babel/runtime-corejs3": "^7.8.4",
|
||||
"@babel/runtime-corejs3": "^7.12.5",
|
||||
"@data-ui/sparkline": "^0.0.84",
|
||||
"@emotion/core": "^10.0.35",
|
||||
"@superset-ui/chart-controls": "^0.16.4",
|
||||
|
|
@ -176,18 +176,18 @@
|
|||
"use-query-params": "^1.1.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.11.5",
|
||||
"@babel/compat-data": "^7.9.6",
|
||||
"@babel/core": "^7.8.7",
|
||||
"@babel/node": "^7.8.7",
|
||||
"@babel/plugin-proposal-class-properties": "^7.8.3",
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.8.3",
|
||||
"@babel/cli": "^7.12.10",
|
||||
"@babel/compat-data": "^7.12.7",
|
||||
"@babel/core": "^7.12.10",
|
||||
"@babel/node": "^7.12.10",
|
||||
"@babel/plugin-proposal-class-properties": "^7.12.1",
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.12.7",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||
"@babel/plugin-transform-runtime": "^7.8.3",
|
||||
"@babel/preset-env": "^7.8.7",
|
||||
"@babel/preset-react": "^7.8.3",
|
||||
"@babel/register": "^7.8.6",
|
||||
"@emotion/babel-preset-css-prop": "^10.0.27",
|
||||
"@babel/plugin-transform-runtime": "^7.12.10",
|
||||
"@babel/preset-env": "^7.12.11",
|
||||
"@babel/preset-react": "^7.12.10",
|
||||
"@babel/register": "^7.12.10",
|
||||
"@emotion/babel-preset-css-prop": "^10.2.1",
|
||||
"@hot-loader/react-dom": "^16.13.0",
|
||||
"@istanbuljs/nyc-config-typescript": "^1.0.1",
|
||||
"@storybook/addon-actions": "^6.0.13",
|
||||
|
|
@ -231,10 +231,10 @@
|
|||
"@typescript-eslint/eslint-plugin": "^4.1.0",
|
||||
"@typescript-eslint/parser": "^4.1.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-jest": "^26.1.0",
|
||||
"babel-loader": "^8.0.6",
|
||||
"babel-plugin-dynamic-import-node": "^2.3.0",
|
||||
"babel-plugin-emotion": "^10.0.29",
|
||||
"babel-jest": "^26.6.3",
|
||||
"babel-loader": "^8.2.2",
|
||||
"babel-plugin-dynamic-import-node": "^2.3.3",
|
||||
"babel-plugin-emotion": "^10.0.33",
|
||||
"babel-plugin-jsx-remove-data-test-id": "^2.1.3",
|
||||
"babel-plugin-lodash": "^3.3.4",
|
||||
"cache-loader": "^1.2.2",
|
||||
|
|
@ -245,20 +245,20 @@
|
|||
"emotion-ts-plugin": "^0.5.3",
|
||||
"enzyme": "^3.10.0",
|
||||
"enzyme-adapter-react-16": "^1.14.0",
|
||||
"eslint": "^7.8.1",
|
||||
"eslint-config-airbnb": "^18.2.0",
|
||||
"eslint-config-prettier": "^6.11.0",
|
||||
"eslint": "^7.17.0",
|
||||
"eslint-config-airbnb": "^18.2.1",
|
||||
"eslint-config-prettier": "^7.1.0",
|
||||
"eslint-import-resolver-typescript": "^2.3.0",
|
||||
"eslint-import-resolver-webpack": "^0.12.2",
|
||||
"eslint-plugin-cypress": "^2.11.1",
|
||||
"eslint-plugin-import": "^2.22.0",
|
||||
"eslint-plugin-jest": "^23.17.1",
|
||||
"eslint-plugin-jest-dom": "^3.2.4",
|
||||
"eslint-plugin-jsx-a11y": "^6.3.1",
|
||||
"eslint-plugin-no-only-tests": "^2.0.1",
|
||||
"eslint-plugin-prettier": "^3.1.3",
|
||||
"eslint-plugin-react": "^7.20.6",
|
||||
"eslint-plugin-react-hooks": "^4.1.2",
|
||||
"eslint-import-resolver-webpack": "^0.13.0",
|
||||
"eslint-plugin-cypress": "^2.11.2",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-jest": "^24.1.3",
|
||||
"eslint-plugin-jest-dom": "^3.6.5",
|
||||
"eslint-plugin-jsx-a11y": "^6.4.1",
|
||||
"eslint-plugin-no-only-tests": "^2.4.0",
|
||||
"eslint-plugin-prettier": "^3.3.1",
|
||||
"eslint-plugin-react": "^7.22.0",
|
||||
"eslint-plugin-react-hooks": "^4.2.0",
|
||||
"eslint-plugin-testing-library": "^3.10.1",
|
||||
"exports-loader": "^0.7.0",
|
||||
"fetch-mock": "^7.7.3",
|
||||
|
|
@ -276,7 +276,7 @@
|
|||
"node-fetch": "^2.6.1",
|
||||
"optimize-css-assets-webpack-plugin": "^5.0.1",
|
||||
"po2json": "^0.4.5",
|
||||
"prettier": "^2.1.1",
|
||||
"prettier": "^2.2.1",
|
||||
"react-test-renderer": "^16.9.0",
|
||||
"redux-mock-store": "^1.5.4",
|
||||
"sinon": "^9.0.2",
|
||||
|
|
|
|||
|
|
@ -62,8 +62,8 @@ describe('AsyncSelect', () => {
|
|||
});
|
||||
|
||||
describe('auto select', () => {
|
||||
it('should not call onChange if autoSelect=false', () => {
|
||||
return new Promise(done => {
|
||||
it('should not call onChange if autoSelect=false', () =>
|
||||
new Promise(done => {
|
||||
expect.assertions(2);
|
||||
|
||||
const onChangeSpy = jest.fn();
|
||||
|
|
@ -74,11 +74,10 @@ describe('AsyncSelect', () => {
|
|||
expect(onChangeSpy.mock.calls).toHaveLength(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
it('should auto select the first option if autoSelect=true', () => {
|
||||
return new Promise(done => {
|
||||
it('should auto select the first option if autoSelect=true', () =>
|
||||
new Promise(done => {
|
||||
expect.assertions(3);
|
||||
|
||||
const onChangeSpy = jest.fn();
|
||||
|
|
@ -94,11 +93,10 @@ describe('AsyncSelect', () => {
|
|||
);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not auto select when value prop is set and autoSelect=true', () => {
|
||||
return new Promise(done => {
|
||||
it('should not auto select when value prop is set and autoSelect=true', () =>
|
||||
new Promise(done => {
|
||||
expect.assertions(3);
|
||||
|
||||
const onChangeSpy = jest.fn();
|
||||
|
|
@ -117,8 +115,7 @@ describe('AsyncSelect', () => {
|
|||
expect(wrapper.find(Select)).toExist();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
it('should call onAsyncError if there is an error fetching options', () => {
|
||||
expect.assertions(3);
|
||||
|
|
|
|||
|
|
@ -489,7 +489,7 @@ describe('dashboardLayout actions', () => {
|
|||
});
|
||||
|
||||
describe('undoLayoutAction', () => {
|
||||
it('should dispatch a redux-undo .undo() action ', () => {
|
||||
it('should dispatch a redux-undo .undo() action', () => {
|
||||
const { getState, dispatch } = setup({
|
||||
dashboardLayout: { past: ['non-empty'] },
|
||||
});
|
||||
|
|
@ -513,7 +513,7 @@ describe('dashboardLayout actions', () => {
|
|||
});
|
||||
|
||||
describe('redoLayoutAction', () => {
|
||||
it('should dispatch a redux-undo .redo() action ', () => {
|
||||
it('should dispatch a redux-undo .redo() action', () => {
|
||||
const { getState, dispatch } = setup();
|
||||
const thunk = redoLayoutAction();
|
||||
thunk(dispatch, getState);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ describe('FilterConfigurationButton', () => {
|
|||
const mockedProps = {
|
||||
createNewOnOpen: false,
|
||||
};
|
||||
it('it is valid', () => {
|
||||
it('is valid', () => {
|
||||
expect(
|
||||
React.isValidElement(<FilterConfigurationLink {...mockedProps} />),
|
||||
).toBe(true);
|
||||
|
|
|
|||
|
|
@ -64,8 +64,8 @@ describe('DatasourceEditor', () => {
|
|||
expect(wrapper.find(Tabs)).toExist();
|
||||
});
|
||||
|
||||
it('makes an async request', () => {
|
||||
return new Promise(done => {
|
||||
it('makes an async request', () =>
|
||||
new Promise(done => {
|
||||
wrapper.setState({ activeTabKey: 2 });
|
||||
const syncButton = wrapper.find('.sync-from-source');
|
||||
expect(syncButton).toHaveLength(1);
|
||||
|
|
@ -76,8 +76,7 @@ describe('DatasourceEditor', () => {
|
|||
fetchMock.reset();
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
it('to add, remove and modify columns accordingly', () => {
|
||||
const columns = [
|
||||
|
|
|
|||
|
|
@ -201,8 +201,8 @@ describe('SaveModal', () => {
|
|||
Object.defineProperty(window, 'location', windowLocation);
|
||||
});
|
||||
|
||||
it('Save & go to dashboard', () => {
|
||||
return new Promise(done => {
|
||||
it('Save & go to dashboard', () =>
|
||||
new Promise(done => {
|
||||
wrapper.instance().saveOrOverwrite(true);
|
||||
defaultProps.actions.saveSlice().then(() => {
|
||||
expect(window.location.assign.callCount).toEqual(1);
|
||||
|
|
@ -211,11 +211,10 @@ describe('SaveModal', () => {
|
|||
);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
it('saveas new slice', () => {
|
||||
return new Promise(done => {
|
||||
it('saveas new slice', () =>
|
||||
new Promise(done => {
|
||||
wrapper.setState({
|
||||
action: 'saveas',
|
||||
newSliceName: 'new slice name',
|
||||
|
|
@ -228,11 +227,10 @@ describe('SaveModal', () => {
|
|||
);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
it('overwrite original slice', () => {
|
||||
return new Promise(done => {
|
||||
it('overwrite original slice', () =>
|
||||
new Promise(done => {
|
||||
wrapper.setState({ action: 'overwrite' });
|
||||
wrapper.instance().saveOrOverwrite(false);
|
||||
defaultProps.actions.saveSlice().then(() => {
|
||||
|
|
@ -242,8 +240,7 @@ describe('SaveModal', () => {
|
|||
);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -57,9 +57,9 @@ const defaultProps = {
|
|||
|
||||
function verify(sourceProp: string) {
|
||||
const mock = jest.fn();
|
||||
mock.mockImplementation(async (props: ControlPropsWithExtras) => {
|
||||
return { [sourceProp]: props.validMetrics || [VALID_METRIC] };
|
||||
});
|
||||
mock.mockImplementation(async (props: ControlPropsWithExtras) => ({
|
||||
[sourceProp]: props.validMetrics || [VALID_METRIC],
|
||||
}));
|
||||
return mock;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,8 +43,8 @@ describe('Toast', () => {
|
|||
expect(alert.childAt(0).childAt(1).text()).toBe(props.toast.text);
|
||||
});
|
||||
|
||||
it('should call onCloseToast upon alert dismissal', () => {
|
||||
return new Promise(done => {
|
||||
it('should call onCloseToast upon alert dismissal', () =>
|
||||
new Promise(done => {
|
||||
const onCloseToast = id => {
|
||||
expect(id).toBe(props.toast.id);
|
||||
done();
|
||||
|
|
@ -57,6 +57,5 @@ describe('Toast', () => {
|
|||
const alertProps = wrapper.find(Alert).props();
|
||||
expect(alertProps.onDismiss).toBe(handleClosePress);
|
||||
handleClosePress(); // there is a timeout for onCloseToast to be called
|
||||
});
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ describe('SaveDatasetModal', () => {
|
|||
const wrapper = shallow(<SaveDatasetModal {...mockedProps} />);
|
||||
expect(wrapper.find(AutoComplete)).toExist();
|
||||
});
|
||||
it('renders an input form ', () => {
|
||||
it('renders an input form', () => {
|
||||
// @ts-ignore
|
||||
const wrapper = shallow(<SaveDatasetModal {...mockedProps} />);
|
||||
expect(wrapper.find(Input)).toExist();
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ describe('sqlLabReducer', () => {
|
|||
newState = sqlLabReducer(newState, action);
|
||||
expect(newState.queryEditors[1].schema).toBe(schema);
|
||||
});
|
||||
it('should not fail while setting autorun ', () => {
|
||||
it('should not fail while setting autorun', () => {
|
||||
const action = {
|
||||
type: actions.QUERY_EDITOR_SET_AUTORUN,
|
||||
queryEditor: qe,
|
||||
|
|
|
|||
|
|
@ -21,9 +21,7 @@ import parseCookie from 'src/utils/parseCookie';
|
|||
describe('parseCookie', () => {
|
||||
let cookieVal = '';
|
||||
Object.defineProperty(document, 'cookie', {
|
||||
get: jest.fn().mockImplementation(() => {
|
||||
return cookieVal;
|
||||
}),
|
||||
get: jest.fn().mockImplementation(() => cookieVal),
|
||||
});
|
||||
it('parses cookie strings', () => {
|
||||
cookieVal = 'val1=foo; val2=bar';
|
||||
|
|
|
|||
|
|
@ -70,13 +70,13 @@ describe('ActivityTable', () => {
|
|||
await waitForComponentToPaint(wrapper);
|
||||
});
|
||||
|
||||
it('the component renders ', () => {
|
||||
it('the component renders', () => {
|
||||
expect(wrapper.find(ActivityTable)).toExist();
|
||||
});
|
||||
it('renders tabs with three buttons', () => {
|
||||
expect(wrapper.find('li')).toHaveLength(3);
|
||||
});
|
||||
it('it renders ActivityCards', async () => {
|
||||
it('renders ActivityCards', async () => {
|
||||
expect(wrapper.find('ListViewCard')).toExist();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -58,11 +58,11 @@ describe('ChartTable', () => {
|
|||
},
|
||||
};
|
||||
const wrapper = mount(<ChartTable store={store} {...mockedProps} />);
|
||||
it('it renders', () => {
|
||||
it('renders', () => {
|
||||
expect(wrapper.find(ChartTable)).toExist();
|
||||
});
|
||||
|
||||
it('fetches chart favorites and renders chart cards ', async () => {
|
||||
it('fetches chart favorites and renders chart cards', async () => {
|
||||
act(() => {
|
||||
const handler = wrapper.find('li.no-router a').at(0).prop('onClick');
|
||||
if (handler) {
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ describe('SavedQueries', () => {
|
|||
expect(wrapper.find('ListViewCard')).toExist();
|
||||
});
|
||||
|
||||
it('it renders a submenu with clickable tables and buttons', async () => {
|
||||
it('renders a submenu with clickable tables and buttons', async () => {
|
||||
expect(wrapper.find(SubMenu)).toExist();
|
||||
expect(wrapper.find('li')).toHaveLength(1);
|
||||
expect(wrapper.find('button')).toHaveLength(2);
|
||||
|
|
|
|||
|
|
@ -184,9 +184,8 @@ export default class ResultSet extends React.PureComponent<
|
|||
}
|
||||
}
|
||||
|
||||
getDefaultDatasetName = () => {
|
||||
return `${this.props.query.tab} ${moment().format('MM/DD/YYYY HH:mm:ss')}`;
|
||||
};
|
||||
getDefaultDatasetName = () =>
|
||||
`${this.props.query.tab} ${moment().format('MM/DD/YYYY HH:mm:ss')}`;
|
||||
|
||||
handleOnChangeAutoComplete = () => {
|
||||
this.setState({ datasetToOverwrite: {} });
|
||||
|
|
@ -341,9 +340,7 @@ export default class ResultSet extends React.PureComponent<
|
|||
handleFilterAutocompleteOption = (
|
||||
inputValue: string,
|
||||
option: { value: string; datasetId: number },
|
||||
) => {
|
||||
return option.value.toLowerCase().includes(inputValue.toLowerCase());
|
||||
};
|
||||
) => option.value.toLowerCase().includes(inputValue.toLowerCase());
|
||||
|
||||
clearQueryResults(query: Query) {
|
||||
this.props.actions.clearQueryResults(query);
|
||||
|
|
|
|||
|
|
@ -91,84 +91,82 @@ export const SaveDatasetModal: FunctionComponent<SaveDatasetModalProps> = ({
|
|||
filterAutocompleteOption,
|
||||
userDatasetOptions,
|
||||
onChangeAutoComplete,
|
||||
}) => {
|
||||
return (
|
||||
<StyledModal
|
||||
show={visible}
|
||||
title="Save or Overwrite Dataset"
|
||||
onHide={onHide}
|
||||
footer={
|
||||
<>
|
||||
{!shouldOverwriteDataset && (
|
||||
<Button
|
||||
disabled={disableSaveAndExploreBtn}
|
||||
buttonSize="medium"
|
||||
buttonStyle="primary"
|
||||
onClick={onOk}
|
||||
>
|
||||
{t('Save & Explore')}
|
||||
</Button>
|
||||
)}
|
||||
{shouldOverwriteDataset && (
|
||||
<>
|
||||
<Button buttonSize="medium" onClick={handleOverwriteCancel}>
|
||||
Back
|
||||
</Button>
|
||||
<Button
|
||||
className="md"
|
||||
buttonSize="medium"
|
||||
buttonStyle="primary"
|
||||
onClick={handleOverwriteDataset}
|
||||
disabled={disableSaveAndExploreBtn}
|
||||
>
|
||||
{t('Overwrite & Explore')}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
>
|
||||
<Styles>
|
||||
}) => (
|
||||
<StyledModal
|
||||
show={visible}
|
||||
title="Save or Overwrite Dataset"
|
||||
onHide={onHide}
|
||||
footer={
|
||||
<>
|
||||
{!shouldOverwriteDataset && (
|
||||
<div className="smd-body">
|
||||
<div className="smd-prompt">
|
||||
Save this query as virtual dataset to continue exploring.
|
||||
</div>
|
||||
<Radio.Group
|
||||
onChange={handleSaveDatasetRadioBtnState}
|
||||
value={saveDatasetRadioBtnState}
|
||||
>
|
||||
<Radio className="smd-radio" value={1}>
|
||||
Save as new
|
||||
<Input
|
||||
className="smd-input"
|
||||
defaultValue={defaultCreateDatasetValue}
|
||||
onChange={handleDatasetNameChange}
|
||||
disabled={saveDatasetRadioBtnState !== 1}
|
||||
/>
|
||||
</Radio>
|
||||
<Radio className="smd-radio" value={2}>
|
||||
Overwrite existing
|
||||
<AutoComplete
|
||||
className="smd-autocomplete"
|
||||
options={userDatasetOptions}
|
||||
onSelect={handleOverwriteDatasetOption}
|
||||
onSearch={handleSaveDatasetModalSearch}
|
||||
onChange={onChangeAutoComplete}
|
||||
placeholder="Select or type dataset name"
|
||||
filterOption={filterAutocompleteOption}
|
||||
disabled={saveDatasetRadioBtnState !== 2}
|
||||
/>
|
||||
</Radio>
|
||||
</Radio.Group>
|
||||
</div>
|
||||
<Button
|
||||
disabled={disableSaveAndExploreBtn}
|
||||
buttonSize="medium"
|
||||
buttonStyle="primary"
|
||||
onClick={onOk}
|
||||
>
|
||||
{t('Save & Explore')}
|
||||
</Button>
|
||||
)}
|
||||
{shouldOverwriteDataset && (
|
||||
<div className="smd-overwrite-msg">
|
||||
Are you sure you want to overwrite this dataset?
|
||||
</div>
|
||||
<>
|
||||
<Button buttonSize="medium" onClick={handleOverwriteCancel}>
|
||||
Back
|
||||
</Button>
|
||||
<Button
|
||||
className="md"
|
||||
buttonSize="medium"
|
||||
buttonStyle="primary"
|
||||
onClick={handleOverwriteDataset}
|
||||
disabled={disableSaveAndExploreBtn}
|
||||
>
|
||||
{t('Overwrite & Explore')}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</Styles>
|
||||
</StyledModal>
|
||||
);
|
||||
};
|
||||
</>
|
||||
}
|
||||
>
|
||||
<Styles>
|
||||
{!shouldOverwriteDataset && (
|
||||
<div className="smd-body">
|
||||
<div className="smd-prompt">
|
||||
Save this query as virtual dataset to continue exploring.
|
||||
</div>
|
||||
<Radio.Group
|
||||
onChange={handleSaveDatasetRadioBtnState}
|
||||
value={saveDatasetRadioBtnState}
|
||||
>
|
||||
<Radio className="smd-radio" value={1}>
|
||||
Save as new
|
||||
<Input
|
||||
className="smd-input"
|
||||
defaultValue={defaultCreateDatasetValue}
|
||||
onChange={handleDatasetNameChange}
|
||||
disabled={saveDatasetRadioBtnState !== 1}
|
||||
/>
|
||||
</Radio>
|
||||
<Radio className="smd-radio" value={2}>
|
||||
Overwrite existing
|
||||
<AutoComplete
|
||||
className="smd-autocomplete"
|
||||
options={userDatasetOptions}
|
||||
onSelect={handleOverwriteDatasetOption}
|
||||
onSearch={handleSaveDatasetModalSearch}
|
||||
onChange={onChangeAutoComplete}
|
||||
placeholder="Select or type dataset name"
|
||||
filterOption={filterAutocompleteOption}
|
||||
disabled={saveDatasetRadioBtnState !== 2}
|
||||
/>
|
||||
</Radio>
|
||||
</Radio.Group>
|
||||
</div>
|
||||
)}
|
||||
{shouldOverwriteDataset && (
|
||||
<div className="smd-overwrite-msg">
|
||||
Are you sure you want to overwrite this dataset?
|
||||
</div>
|
||||
)}
|
||||
</Styles>
|
||||
</StyledModal>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -79,13 +79,11 @@ export default function SaveQuery({
|
|||
const [showSave, setShowSave] = useState<boolean>(false);
|
||||
const isSaved = !!query.remoteId;
|
||||
|
||||
const queryPayload = () => {
|
||||
return {
|
||||
...query,
|
||||
title: label,
|
||||
description,
|
||||
};
|
||||
};
|
||||
const queryPayload = () => ({
|
||||
...query,
|
||||
title: label,
|
||||
description,
|
||||
});
|
||||
|
||||
const close = () => {
|
||||
setShowSave(false);
|
||||
|
|
@ -113,47 +111,45 @@ export default function SaveQuery({
|
|||
setShowSave(!showSave);
|
||||
};
|
||||
|
||||
const renderModalBody = () => {
|
||||
return (
|
||||
<FormGroup bsSize="small">
|
||||
<Row>
|
||||
<Col md={12}>
|
||||
<small>
|
||||
<FormLabel htmlFor="embed-height">{t('Name')}</FormLabel>
|
||||
</small>
|
||||
<FormControl type="text" value={label} onChange={onLabelChange} />
|
||||
</Col>
|
||||
</Row>
|
||||
<br />
|
||||
<Row>
|
||||
<Col md={12}>
|
||||
<small>
|
||||
<FormLabel htmlFor="embed-height">{t('Description')}</FormLabel>
|
||||
</small>
|
||||
<FormControl
|
||||
rows={5}
|
||||
componentClass="textarea"
|
||||
value={description}
|
||||
onChange={onDescriptionChange}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
{saveQueryWarning && (
|
||||
<>
|
||||
const renderModalBody = () => (
|
||||
<FormGroup bsSize="small">
|
||||
<Row>
|
||||
<Col md={12}>
|
||||
<small>
|
||||
<FormLabel htmlFor="embed-height">{t('Name')}</FormLabel>
|
||||
</small>
|
||||
<FormControl type="text" value={label} onChange={onLabelChange} />
|
||||
</Col>
|
||||
</Row>
|
||||
<br />
|
||||
<Row>
|
||||
<Col md={12}>
|
||||
<small>
|
||||
<FormLabel htmlFor="embed-height">{t('Description')}</FormLabel>
|
||||
</small>
|
||||
<FormControl
|
||||
rows={5}
|
||||
componentClass="textarea"
|
||||
value={description}
|
||||
onChange={onDescriptionChange}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
{saveQueryWarning && (
|
||||
<>
|
||||
<br />
|
||||
<div>
|
||||
<Row>
|
||||
<Col md={12}>
|
||||
<small>{saveQueryWarning}</small>
|
||||
</Col>
|
||||
</Row>
|
||||
<br />
|
||||
<div>
|
||||
<Row>
|
||||
<Col md={12}>
|
||||
<small>{saveQueryWarning}</small>
|
||||
</Col>
|
||||
</Row>
|
||||
<br />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</FormGroup>
|
||||
);
|
||||
};
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</FormGroup>
|
||||
);
|
||||
|
||||
return (
|
||||
<Styles className="SaveQuery">
|
||||
|
|
|
|||
|
|
@ -148,13 +148,13 @@ const legacyChartDataRequest = async (
|
|||
'GET' && isFeatureEnabled(FeatureFlag.CLIENT_CACHE)
|
||||
? SupersetClient.get
|
||||
: SupersetClient.post;
|
||||
return clientMethod(querySettings).then(({ json }) => {
|
||||
return clientMethod(querySettings).then(({ json }) =>
|
||||
// Make the legacy endpoint return a payload that corresponds to the
|
||||
// V1 chart data endpoint response signature.
|
||||
return {
|
||||
({
|
||||
result: [json],
|
||||
};
|
||||
});
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const v1ChartDataRequest = async (
|
||||
|
|
@ -195,9 +195,7 @@ const v1ChartDataRequest = async (
|
|||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload),
|
||||
};
|
||||
return SupersetClient.post(querySettings).then(({ json }) => {
|
||||
return json;
|
||||
});
|
||||
return SupersetClient.post(querySettings).then(({ json }) => json);
|
||||
};
|
||||
|
||||
export async function getChartDataRequest({
|
||||
|
|
|
|||
|
|
@ -70,6 +70,4 @@ export type ErrorMessageComponentProps<
|
|||
source?: ErrorSource;
|
||||
};
|
||||
|
||||
export type ErrorMessageComponent = React.ComponentType<
|
||||
ErrorMessageComponentProps
|
||||
>;
|
||||
export type ErrorMessageComponent = React.ComponentType<ErrorMessageComponentProps>;
|
||||
|
|
|
|||
|
|
@ -55,6 +55,6 @@ const users = [...new Array(10)].map((_, i) => ({
|
|||
id: i,
|
||||
}));
|
||||
|
||||
export const SupersetFacePile = () => {
|
||||
return <FacePile users={users} maxCount={number('maxCount', 4)} />;
|
||||
};
|
||||
export const SupersetFacePile = () => (
|
||||
<FacePile users={users} maxCount={number('maxCount', 4)} />
|
||||
);
|
||||
|
|
|
|||
|
|
@ -61,26 +61,24 @@ const IconBlock = styled.div`
|
|||
}
|
||||
`;
|
||||
|
||||
export const SupersetIcon = () => {
|
||||
return (
|
||||
<IconSet>
|
||||
{Object.keys(iconsRegistry)
|
||||
.sort()
|
||||
.map(iconName => (
|
||||
<IconBlock key={iconName}>
|
||||
<Icon
|
||||
name={iconName}
|
||||
key={iconName}
|
||||
color={select(
|
||||
colorKnob.label,
|
||||
colorKnob.options,
|
||||
colorKnob.defaultValue,
|
||||
colorKnob.groupId,
|
||||
)}
|
||||
/>
|
||||
<div>{iconName}</div>
|
||||
</IconBlock>
|
||||
))}
|
||||
</IconSet>
|
||||
);
|
||||
};
|
||||
export const SupersetIcon = () => (
|
||||
<IconSet>
|
||||
{Object.keys(iconsRegistry)
|
||||
.sort()
|
||||
.map(iconName => (
|
||||
<IconBlock key={iconName}>
|
||||
<Icon
|
||||
name={iconName}
|
||||
key={iconName}
|
||||
color={select(
|
||||
colorKnob.label,
|
||||
colorKnob.options,
|
||||
colorKnob.defaultValue,
|
||||
colorKnob.groupId,
|
||||
)}
|
||||
/>
|
||||
<div>{iconName}</div>
|
||||
</IconBlock>
|
||||
))}
|
||||
</IconSet>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -68,9 +68,9 @@ export default function CardCollection({
|
|||
<CardContainer>
|
||||
{loading &&
|
||||
rows.length === 0 &&
|
||||
[...new Array(25)].map((e, i) => {
|
||||
return <div key={i}>{renderCard({ loading })}</div>;
|
||||
})}
|
||||
[...new Array(25)].map((e, i) => (
|
||||
<div key={i}>{renderCard({ loading })}</div>
|
||||
))}
|
||||
{rows.length > 0 &&
|
||||
rows.map(row => {
|
||||
if (!renderCard) return null;
|
||||
|
|
|
|||
|
|
@ -174,34 +174,32 @@ const ViewModeToggle = ({
|
|||
}: {
|
||||
mode: 'table' | 'card';
|
||||
setMode: (mode: 'table' | 'card') => void;
|
||||
}) => {
|
||||
return (
|
||||
<ViewModeContainer>
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={e => {
|
||||
e.currentTarget.blur();
|
||||
setMode('card');
|
||||
}}
|
||||
className={cx('toggle-button', { active: mode === 'card' })}
|
||||
>
|
||||
<Icon name="card-view" />
|
||||
</div>
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={e => {
|
||||
e.currentTarget.blur();
|
||||
setMode('table');
|
||||
}}
|
||||
className={cx('toggle-button', { active: mode === 'table' })}
|
||||
>
|
||||
<Icon name="list-view" />
|
||||
</div>
|
||||
</ViewModeContainer>
|
||||
);
|
||||
};
|
||||
}) => (
|
||||
<ViewModeContainer>
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={e => {
|
||||
e.currentTarget.blur();
|
||||
setMode('card');
|
||||
}}
|
||||
className={cx('toggle-button', { active: mode === 'card' })}
|
||||
>
|
||||
<Icon name="card-view" />
|
||||
</div>
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={e => {
|
||||
e.currentTarget.blur();
|
||||
setMode('table');
|
||||
}}
|
||||
className={cx('toggle-button', { active: mode === 'table' })}
|
||||
>
|
||||
<Icon name="list-view" />
|
||||
</div>
|
||||
</ViewModeContainer>
|
||||
);
|
||||
|
||||
export interface ListViewProps<T extends object = any> {
|
||||
columns: any[];
|
||||
|
|
|
|||
|
|
@ -41,49 +41,43 @@ const imgFallbackKnob = {
|
|||
defaultValue: DashboardImg,
|
||||
};
|
||||
|
||||
export const SupersetListViewCard = () => {
|
||||
return (
|
||||
<ListViewCard
|
||||
title="Superset Card Title"
|
||||
loading={boolean('loading', false)}
|
||||
url="/superset/dashboard/births/"
|
||||
imgURL={text('imgURL', 'https://picsum.photos/800/600')}
|
||||
imgFallbackURL={select(
|
||||
imgFallbackKnob.label,
|
||||
imgFallbackKnob.options,
|
||||
imgFallbackKnob.defaultValue,
|
||||
)}
|
||||
description="Lorem ipsum dolor sit amet, consectetur adipiscing elit..."
|
||||
coverLeft="Left Section"
|
||||
coverRight="Right Section"
|
||||
actions={
|
||||
<ListViewCard.Actions>
|
||||
<FaveStar
|
||||
itemId={0}
|
||||
fetchFaveStar={action('fetchFaveStar')}
|
||||
saveFaveStar={action('saveFaveStar')}
|
||||
isStarred={boolean('isStarred', false)}
|
||||
/>
|
||||
<Dropdown
|
||||
overlay={
|
||||
<Menu>
|
||||
<Menu.Item
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={action('Delete')}
|
||||
>
|
||||
<ListViewCard.MenuIcon name="trash" /> Delete
|
||||
</Menu.Item>
|
||||
<Menu.Item role="button" tabIndex={0} onClick={action('Edit')}>
|
||||
<ListViewCard.MenuIcon name="edit-alt" /> Edit
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
}
|
||||
>
|
||||
<Icon name="more-horiz" />
|
||||
</Dropdown>
|
||||
</ListViewCard.Actions>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
export const SupersetListViewCard = () => (
|
||||
<ListViewCard
|
||||
title="Superset Card Title"
|
||||
loading={boolean('loading', false)}
|
||||
url="/superset/dashboard/births/"
|
||||
imgURL={text('imgURL', 'https://picsum.photos/800/600')}
|
||||
imgFallbackURL={select(
|
||||
imgFallbackKnob.label,
|
||||
imgFallbackKnob.options,
|
||||
imgFallbackKnob.defaultValue,
|
||||
)}
|
||||
description="Lorem ipsum dolor sit amet, consectetur adipiscing elit..."
|
||||
coverLeft="Left Section"
|
||||
coverRight="Right Section"
|
||||
actions={
|
||||
<ListViewCard.Actions>
|
||||
<FaveStar
|
||||
itemId={0}
|
||||
fetchFaveStar={action('fetchFaveStar')}
|
||||
saveFaveStar={action('saveFaveStar')}
|
||||
isStarred={boolean('isStarred', false)}
|
||||
/>
|
||||
<Dropdown
|
||||
overlay={
|
||||
<Menu>
|
||||
<Menu.Item role="button" tabIndex={0} onClick={action('Delete')}>
|
||||
<ListViewCard.MenuIcon name="trash" /> Delete
|
||||
</Menu.Item>
|
||||
<Menu.Item role="button" tabIndex={0} onClick={action('Edit')}>
|
||||
<ListViewCard.MenuIcon name="edit-alt" /> Edit
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
}
|
||||
>
|
||||
<Icon name="more-horiz" />
|
||||
</Dropdown>
|
||||
</ListViewCard.Actions>
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -49,45 +49,43 @@ export default {
|
|||
},
|
||||
};
|
||||
|
||||
export const SelectGallery = ({ value }: { value: OptionTypeBase }) => {
|
||||
return (
|
||||
<>
|
||||
<h4>With default value</h4>
|
||||
<Select
|
||||
value={OPTIONS[0]}
|
||||
ignoreAccents={false}
|
||||
name="select-datasource"
|
||||
onChange={() => {}}
|
||||
options={OPTIONS}
|
||||
placeholder="choose one"
|
||||
width={600}
|
||||
/>
|
||||
<hr />
|
||||
<h4>With no value</h4>
|
||||
<Select
|
||||
ignoreAccents={false}
|
||||
name="select-datasource"
|
||||
onChange={() => {}}
|
||||
options={OPTIONS}
|
||||
placeholder="choose one"
|
||||
width={600}
|
||||
value={value}
|
||||
/>
|
||||
<hr />
|
||||
<h4>Multi select</h4>
|
||||
<Select
|
||||
ignoreAccents={false}
|
||||
name="select-datasource"
|
||||
onChange={() => {}}
|
||||
options={OPTIONS}
|
||||
placeholder="choose one or more values"
|
||||
width={600}
|
||||
value={[OPTIONS[0]]}
|
||||
multi
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export const SelectGallery = ({ value }: { value: OptionTypeBase }) => (
|
||||
<>
|
||||
<h4>With default value</h4>
|
||||
<Select
|
||||
value={OPTIONS[0]}
|
||||
ignoreAccents={false}
|
||||
name="select-datasource"
|
||||
onChange={() => {}}
|
||||
options={OPTIONS}
|
||||
placeholder="choose one"
|
||||
width={600}
|
||||
/>
|
||||
<hr />
|
||||
<h4>With no value</h4>
|
||||
<Select
|
||||
ignoreAccents={false}
|
||||
name="select-datasource"
|
||||
onChange={() => {}}
|
||||
options={OPTIONS}
|
||||
placeholder="choose one"
|
||||
width={600}
|
||||
value={value}
|
||||
/>
|
||||
<hr />
|
||||
<h4>Multi select</h4>
|
||||
<Select
|
||||
ignoreAccents={false}
|
||||
name="select-datasource"
|
||||
onChange={() => {}}
|
||||
options={OPTIONS}
|
||||
placeholder="choose one or more values"
|
||||
width={600}
|
||||
value={[OPTIONS[0]]}
|
||||
multi
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
SelectGallery.args = {
|
||||
value: '',
|
||||
|
|
|
|||
|
|
@ -99,9 +99,9 @@ function styled<
|
|||
OptionType extends OptionTypeBase,
|
||||
SelectComponentType extends
|
||||
| WindowedSelectComponentType<OptionType>
|
||||
| ComponentType<SelectProps<OptionType>> = WindowedSelectComponentType<
|
||||
OptionType
|
||||
>
|
||||
| ComponentType<
|
||||
SelectProps<OptionType>
|
||||
> = WindowedSelectComponentType<OptionType>
|
||||
>(SelectComponent: SelectComponentType) {
|
||||
type SelectProps = SupersetStyledSelectProps<OptionType>;
|
||||
type Components = SelectComponents<OptionType>;
|
||||
|
|
@ -113,8 +113,8 @@ function styled<
|
|||
// default components for the given OptionType
|
||||
const supersetDefaultComponents: SelectComponentsConfig<OptionType> = DEFAULT_COMPONENTS;
|
||||
|
||||
const getSortableMultiValue = (MultiValue: Components['MultiValue']) => {
|
||||
return SortableElement((props: MultiValueProps<OptionType>) => {
|
||||
const getSortableMultiValue = (MultiValue: Components['MultiValue']) =>
|
||||
SortableElement((props: MultiValueProps<OptionType>) => {
|
||||
const onMouseDown = (e: SyntheticEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
|
@ -122,7 +122,6 @@ function styled<
|
|||
const innerProps = { onMouseDown };
|
||||
return <MultiValue {...props} innerProps={innerProps} />;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Superset styled `Select` component. Apply Superset themed stylesheets and
|
||||
|
|
|
|||
|
|
@ -125,9 +125,7 @@ export default function WindowedMenuList<OptionType extends OptionTypeBase>({
|
|||
data,
|
||||
index,
|
||||
style,
|
||||
}) => {
|
||||
return <div style={style}>{data[index]}</div>;
|
||||
};
|
||||
}) => <div style={style}>{data[index]}</div>;
|
||||
|
||||
useEffect(() => {
|
||||
const lastSelected = getLastSelected(children);
|
||||
|
|
|
|||
|
|
@ -91,21 +91,19 @@ export type PartialThemeConfig = RecursivePartial<ThemeConfig>;
|
|||
|
||||
export const defaultTheme: (
|
||||
theme: SupersetTheme,
|
||||
) => PartialThemeConfig = theme => {
|
||||
return {
|
||||
borderRadius: theme.borderRadius,
|
||||
zIndex: 11,
|
||||
colors: colors(theme),
|
||||
spacing: {
|
||||
baseUnit: 3,
|
||||
menuGutter: 0,
|
||||
controlHeight: 28,
|
||||
lineHeight: 19,
|
||||
fontSize: 14,
|
||||
minWidth: '7.5em', // just enough to display 'No options'
|
||||
},
|
||||
};
|
||||
};
|
||||
) => PartialThemeConfig = theme => ({
|
||||
borderRadius: theme.borderRadius,
|
||||
zIndex: 11,
|
||||
colors: colors(theme),
|
||||
spacing: {
|
||||
baseUnit: 3,
|
||||
menuGutter: 0,
|
||||
controlHeight: 28,
|
||||
lineHeight: 19,
|
||||
fontSize: 14,
|
||||
minWidth: '7.5em', // just enough to display 'No options'
|
||||
},
|
||||
});
|
||||
|
||||
// let styles accept serialized CSS, too
|
||||
type CSSStyles = CSSProperties | SerializedStyles;
|
||||
|
|
|
|||
|
|
@ -90,11 +90,10 @@ export default function SupersetResourceSelect<T, V>({
|
|||
return cachedSupersetGet({
|
||||
endpoint: `/api/v1/${resource}/?q=${query}`,
|
||||
}).then(
|
||||
response => {
|
||||
return response.json.result
|
||||
response =>
|
||||
response.json.result
|
||||
.map(transformItem)
|
||||
.sort((a: Value<V>, b: Value<V>) => a.label.localeCompare(b.label));
|
||||
},
|
||||
.sort((a: Value<V>, b: Value<V>) => a.label.localeCompare(b.label)),
|
||||
async badResponse => {
|
||||
onError(await getClientErrorObject(badResponse));
|
||||
return [];
|
||||
|
|
|
|||
|
|
@ -43,56 +43,52 @@ const BuilderComponentPaneTabs = styled(Tabs)`
|
|||
margin-top: ${({ theme }) => theme.gridUnit * 2}px;
|
||||
`;
|
||||
|
||||
const BuilderComponentPane: React.FC<BCPProps> = ({ topOffset = 0 }) => {
|
||||
return (
|
||||
<div
|
||||
className="dashboard-builder-sidepane"
|
||||
style={{
|
||||
height: `calc(100vh - ${topOffset + SUPERSET_HEADER_HEIGHT}px)`,
|
||||
}}
|
||||
>
|
||||
<ParentSize>
|
||||
{({ height }) => (
|
||||
<StickyContainer>
|
||||
<Sticky topOffset={-topOffset} bottomOffset={Infinity}>
|
||||
{({ style, isSticky }: { style: any; isSticky: boolean }) => (
|
||||
<div
|
||||
className="viewport"
|
||||
style={isSticky ? { ...style, top: topOffset } : null}
|
||||
const BuilderComponentPane: React.FC<BCPProps> = ({ topOffset = 0 }) => (
|
||||
<div
|
||||
className="dashboard-builder-sidepane"
|
||||
style={{
|
||||
height: `calc(100vh - ${topOffset + SUPERSET_HEADER_HEIGHT}px)`,
|
||||
}}
|
||||
>
|
||||
<ParentSize>
|
||||
{({ height }) => (
|
||||
<StickyContainer>
|
||||
<Sticky topOffset={-topOffset} bottomOffset={Infinity}>
|
||||
{({ style, isSticky }: { style: any; isSticky: boolean }) => (
|
||||
<div
|
||||
className="viewport"
|
||||
style={isSticky ? { ...style, top: topOffset } : null}
|
||||
>
|
||||
<BuilderComponentPaneTabs
|
||||
id="tabs"
|
||||
className="tabs-components"
|
||||
data-test="dashboard-builder-component-pane-tabs-navigation"
|
||||
>
|
||||
<BuilderComponentPaneTabs
|
||||
id="tabs"
|
||||
className="tabs-components"
|
||||
data-test="dashboard-builder-component-pane-tabs-navigation"
|
||||
<Tabs.TabPane key={1} tab={t('Components')}>
|
||||
<NewTabs />
|
||||
<NewRow />
|
||||
<NewColumn />
|
||||
<NewHeader />
|
||||
<NewMarkdown />
|
||||
<NewDivider />
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane
|
||||
key={2}
|
||||
tab={t('Charts')}
|
||||
className="tab-charts"
|
||||
>
|
||||
<Tabs.TabPane key={1} tab={t('Components')}>
|
||||
<NewTabs />
|
||||
<NewRow />
|
||||
<NewColumn />
|
||||
<NewHeader />
|
||||
<NewMarkdown />
|
||||
<NewDivider />
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane
|
||||
key={2}
|
||||
tab={t('Charts')}
|
||||
className="tab-charts"
|
||||
>
|
||||
<SliceAdder
|
||||
height={
|
||||
height + (isSticky ? SUPERSET_HEADER_HEIGHT : 0)
|
||||
}
|
||||
/>
|
||||
</Tabs.TabPane>
|
||||
</BuilderComponentPaneTabs>
|
||||
</div>
|
||||
)}
|
||||
</Sticky>
|
||||
</StickyContainer>
|
||||
)}
|
||||
</ParentSize>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
<SliceAdder
|
||||
height={height + (isSticky ? SUPERSET_HEADER_HEIGHT : 0)}
|
||||
/>
|
||||
</Tabs.TabPane>
|
||||
</BuilderComponentPaneTabs>
|
||||
</div>
|
||||
)}
|
||||
</Sticky>
|
||||
</StickyContainer>
|
||||
)}
|
||||
</ParentSize>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default BuilderComponentPane;
|
||||
|
|
|
|||
|
|
@ -96,9 +96,10 @@ const StyledDashboardContent = styled.div`
|
|||
margin: ${({ theme }) => theme.gridUnit * 2}px
|
||||
${({ theme }) => theme.gridUnit * 8}px
|
||||
${({ theme }) => theme.gridUnit * 6}px
|
||||
${({ theme, dashboardFiltersOpen }) =>
|
||||
// eslint-disable-next-line prettier/prettier
|
||||
(dashboardFiltersOpen ? theme.gridUnit * 4 : 0)}px;
|
||||
${({ theme, dashboardFiltersOpen }) => {
|
||||
if (dashboardFiltersOpen) return theme.gridUnit * 4;
|
||||
return 0;
|
||||
}}px;
|
||||
}
|
||||
|
||||
.dashboard-component-chart-holder {
|
||||
|
|
|
|||
|
|
@ -45,20 +45,18 @@ export interface IndicatorProps {
|
|||
const Indicator = ({
|
||||
indicator: { column, name, value = [], path },
|
||||
onClick,
|
||||
}: IndicatorProps) => {
|
||||
return (
|
||||
<Item onClick={() => onClick([...path, `LABEL-${column}`])}>
|
||||
<Title bold>
|
||||
<ItemIcon>
|
||||
<SearchOutlined />
|
||||
</ItemIcon>
|
||||
{name.toUpperCase()}
|
||||
{value.length ? ': ' : ''}
|
||||
</Title>
|
||||
<FilterValue>{value.length ? value.join(', ') : ''}</FilterValue>
|
||||
</Item>
|
||||
);
|
||||
};
|
||||
}: IndicatorProps) => (
|
||||
<Item onClick={() => onClick([...path, `LABEL-${column}`])}>
|
||||
<Title bold>
|
||||
<ItemIcon>
|
||||
<SearchOutlined />
|
||||
</ItemIcon>
|
||||
{name.toUpperCase()}
|
||||
{value.length ? ': ' : ''}
|
||||
</Title>
|
||||
<FilterValue>{value.length ? value.join(', ') : ''}</FilterValue>
|
||||
</Item>
|
||||
);
|
||||
|
||||
export interface DetailsPanelProps {
|
||||
appliedIndicators: Indicator[];
|
||||
|
|
|
|||
|
|
@ -91,7 +91,8 @@ export const Title = styled.span<TitleProps>`
|
|||
position: relative;
|
||||
margin-right: ${({ theme }) => theme.gridUnit}px;
|
||||
font-weight: ${({ bold, theme }) => {
|
||||
return bold ? theme.typography.weights.bold : 'auto';
|
||||
if (bold) return theme.typography.weights.bold;
|
||||
return 'auto';
|
||||
}};
|
||||
color: ${({ color, theme }) => color || theme.colors.grayscale.light5};
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -90,12 +90,11 @@ const loadOwnerOptions = (input = '') => {
|
|||
return SupersetClient.get({
|
||||
endpoint: `/api/v1/dashboard/related/owners?q=${query}`,
|
||||
}).then(
|
||||
response => {
|
||||
return response.json.result.map(item => ({
|
||||
response =>
|
||||
response.json.result.map(item => ({
|
||||
value: item.value,
|
||||
label: item.text,
|
||||
}));
|
||||
},
|
||||
})),
|
||||
badResponse => {
|
||||
handleErrorResponse(badResponse);
|
||||
return [];
|
||||
|
|
|
|||
|
|
@ -181,9 +181,13 @@ class SliceHeaderControls extends React.PureComponent {
|
|||
);
|
||||
const updatedWhen = updatedDttm ? moment.utc(updatedDttm).fromNow() : '';
|
||||
const getCachedTitle = itemCached => {
|
||||
return itemCached
|
||||
? t('Cached %s', cachedWhen)
|
||||
: updatedWhen && t('Fetched %s', updatedWhen);
|
||||
if (itemCached) {
|
||||
return t('Cached %s', cachedWhen);
|
||||
}
|
||||
if (updatedWhen) {
|
||||
return t('Fetched %s', updatedWhen);
|
||||
}
|
||||
return '';
|
||||
};
|
||||
const refreshTooltipData = isCached.map(getCachedTitle) || '';
|
||||
// If all queries have same cache time we can unit them to one
|
||||
|
|
|
|||
|
|
@ -32,8 +32,7 @@ const Wrapper = styled.div`
|
|||
/* keeping these for posterity, in case we can improve that resizing performance */
|
||||
/* &.animated {
|
||||
transition: width 0;
|
||||
transition-delay: ${({ theme }) =>
|
||||
theme.transitionTiming * 2}s;
|
||||
transition-delay: ${({ theme }) => theme.transitionTiming * 2}s;
|
||||
} */
|
||||
&.open {
|
||||
width: 250px;
|
||||
|
|
@ -68,38 +67,36 @@ export const StickyVerticalBar: React.FC<SVBProps> = ({
|
|||
topOffset,
|
||||
children,
|
||||
filtersOpen,
|
||||
}) => {
|
||||
return (
|
||||
<Wrapper className={cx({ open: filtersOpen })}>
|
||||
<StickyContainer>
|
||||
<Sticky topOffset={-topOffset} bottomOffset={Infinity}>
|
||||
{({
|
||||
style,
|
||||
isSticky,
|
||||
distanceFromTop,
|
||||
}: {
|
||||
style: any;
|
||||
isSticky: boolean;
|
||||
distanceFromTop: number;
|
||||
}) => (
|
||||
<Contents
|
||||
style={
|
||||
isSticky
|
||||
? {
|
||||
...style,
|
||||
top: topOffset,
|
||||
height: `calc(100vh - ${topOffset}px)`,
|
||||
}
|
||||
: {
|
||||
height: `calc(100vh - ${distanceFromTop}px)`,
|
||||
}
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</Contents>
|
||||
)}
|
||||
</Sticky>
|
||||
</StickyContainer>
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
}) => (
|
||||
<Wrapper className={cx({ open: filtersOpen })}>
|
||||
<StickyContainer>
|
||||
<Sticky topOffset={-topOffset} bottomOffset={Infinity}>
|
||||
{({
|
||||
style,
|
||||
isSticky,
|
||||
distanceFromTop,
|
||||
}: {
|
||||
style: any;
|
||||
isSticky: boolean;
|
||||
distanceFromTop: number;
|
||||
}) => (
|
||||
<Contents
|
||||
style={
|
||||
isSticky
|
||||
? {
|
||||
...style,
|
||||
top: topOffset,
|
||||
height: `calc(100vh - ${topOffset}px)`,
|
||||
}
|
||||
: {
|
||||
height: `calc(100vh - ${distanceFromTop}px)`,
|
||||
}
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</Contents>
|
||||
)}
|
||||
</Sticky>
|
||||
</StickyContainer>
|
||||
</Wrapper>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -204,28 +204,26 @@ export default class Tab extends React.PureComponent {
|
|||
onDrop={this.handleDrop}
|
||||
editMode={editMode}
|
||||
>
|
||||
{({ dropIndicatorProps, dragSourceRef }) => {
|
||||
return (
|
||||
<div className="dragdroppable-tab" ref={dragSourceRef}>
|
||||
<EditableTitle
|
||||
title={component.meta.text}
|
||||
canEdit={editMode && isFocused}
|
||||
onSaveTitle={this.handleChangeText}
|
||||
showTooltip={false}
|
||||
{({ dropIndicatorProps, dragSourceRef }) => (
|
||||
<div className="dragdroppable-tab" ref={dragSourceRef}>
|
||||
<EditableTitle
|
||||
title={component.meta.text}
|
||||
canEdit={editMode && isFocused}
|
||||
onSaveTitle={this.handleChangeText}
|
||||
showTooltip={false}
|
||||
/>
|
||||
{!editMode && (
|
||||
<AnchorLink
|
||||
anchorLinkId={component.id}
|
||||
filters={filters}
|
||||
showShortLinkButton
|
||||
placement={index >= 5 ? 'left' : 'right'}
|
||||
/>
|
||||
{!editMode && (
|
||||
<AnchorLink
|
||||
anchorLinkId={component.id}
|
||||
filters={filters}
|
||||
showShortLinkButton
|
||||
placement={index >= 5 ? 'left' : 'right'}
|
||||
/>
|
||||
)}
|
||||
)}
|
||||
|
||||
{dropIndicatorProps && <div {...dropIndicatorProps} />}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
{dropIndicatorProps && <div {...dropIndicatorProps} />}
|
||||
</div>
|
||||
)}
|
||||
</DragDroppable>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,11 +73,10 @@ export function ColumnSelect({
|
|||
return cachedSupersetGet({
|
||||
endpoint: `/api/v1/dataset/${datasetId}`,
|
||||
}).then(
|
||||
({ json: { result } }) => {
|
||||
return result.columns
|
||||
({ json: { result } }) =>
|
||||
result.columns
|
||||
.map((col: any) => col.column_name)
|
||||
.sort((a: string, b: string) => a.localeCompare(b));
|
||||
},
|
||||
.sort((a: string, b: string) => a.localeCompare(b)),
|
||||
async badResponse => {
|
||||
const { error, message } = await getClientErrorObject(badResponse);
|
||||
let errorText = message || error || t('An error has occurred');
|
||||
|
|
|
|||
|
|
@ -67,18 +67,14 @@ const Bar = styled.div`
|
|||
/* &.animated {
|
||||
display: flex;
|
||||
transform: translateX(-100%);
|
||||
transition: transform ${({
|
||||
theme,
|
||||
}) => theme.transitionTiming}s;
|
||||
transition: transform ${({ theme }) => theme.transitionTiming}s;
|
||||
transition-delay: 0s;
|
||||
} */
|
||||
&.open {
|
||||
display: flex;
|
||||
/* &.animated {
|
||||
transform: translateX(0);
|
||||
transition-delay: ${({
|
||||
theme,
|
||||
}) => theme.transitionTiming * 2}s;
|
||||
transition-delay: ${({ theme }) => theme.transitionTiming * 2}s;
|
||||
} */
|
||||
}
|
||||
`;
|
||||
|
|
@ -95,9 +91,7 @@ const CollapsedBar = styled.div`
|
|||
/* &.animated {
|
||||
display: block;
|
||||
transform: translateX(-100%);
|
||||
transition: transform ${({
|
||||
theme,
|
||||
}) => theme.transitionTiming}s;
|
||||
transition: transform ${({ theme }) => theme.transitionTiming}s;
|
||||
transition-delay: 0s;
|
||||
} */
|
||||
&.open {
|
||||
|
|
@ -107,9 +101,7 @@ const CollapsedBar = styled.div`
|
|||
padding: ${({ theme }) => theme.gridUnit * 2}px;
|
||||
/* &.animated {
|
||||
transform: translateX(0);
|
||||
transition-delay: ${({
|
||||
theme,
|
||||
}) => theme.transitionTiming * 3}s;
|
||||
transition-delay: ${({ theme }) => theme.transitionTiming * 3}s;
|
||||
} */
|
||||
}
|
||||
svg {
|
||||
|
|
@ -321,30 +313,28 @@ interface CascadeFilterControlProps {
|
|||
export const CascadeFilterControl: React.FC<CascadeFilterControlProps> = ({
|
||||
filter,
|
||||
onExtraFormDataChange,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<StyledFilterControlBox>
|
||||
<StyledCaretIcon name="caret-down" />
|
||||
<FilterControl
|
||||
filter={filter}
|
||||
onExtraFormDataChange={onExtraFormDataChange}
|
||||
/>
|
||||
</StyledFilterControlBox>
|
||||
}) => (
|
||||
<>
|
||||
<StyledFilterControlBox>
|
||||
<StyledCaretIcon name="caret-down" />
|
||||
<FilterControl
|
||||
filter={filter}
|
||||
onExtraFormDataChange={onExtraFormDataChange}
|
||||
/>
|
||||
</StyledFilterControlBox>
|
||||
|
||||
<StyledCascadeChildrenList>
|
||||
{filter.cascadeChildren?.map(childFilter => (
|
||||
<li key={childFilter.id}>
|
||||
<CascadeFilterControl
|
||||
filter={childFilter}
|
||||
onExtraFormDataChange={onExtraFormDataChange}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
</StyledCascadeChildrenList>
|
||||
</>
|
||||
);
|
||||
};
|
||||
<StyledCascadeChildrenList>
|
||||
{filter.cascadeChildren?.map(childFilter => (
|
||||
<li key={childFilter.id}>
|
||||
<CascadeFilterControl
|
||||
filter={childFilter}
|
||||
onExtraFormDataChange={onExtraFormDataChange}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
</StyledCascadeChildrenList>
|
||||
</>
|
||||
);
|
||||
|
||||
const FilterBar: React.FC<FiltersBarProps> = ({
|
||||
filtersOpen,
|
||||
|
|
|
|||
|
|
@ -60,9 +60,9 @@ export function useFilterConfigMap() {
|
|||
}
|
||||
|
||||
export function useFilterState(id: string) {
|
||||
return useSelector<any, FilterState>(state => {
|
||||
return state.nativeFilters.filtersState[id] || getInitialFilterState(id);
|
||||
});
|
||||
return useSelector<any, FilterState>(
|
||||
state => state.nativeFilters.filtersState[id] || getInitialFilterState(id),
|
||||
);
|
||||
}
|
||||
|
||||
export function useSetExtraFormData() {
|
||||
|
|
|
|||
|
|
@ -343,7 +343,9 @@ class DatasourceEditor extends React.PureComponent {
|
|||
onDatasourcePropChange(attr, value) {
|
||||
const datasource = { ...this.state.datasource, [attr]: value };
|
||||
this.setState(
|
||||
prevState => ({ datasource: { ...prevState.datasource, [attr]: value } }),
|
||||
prevState => ({
|
||||
datasource: { ...prevState.datasource, [attr]: value },
|
||||
}),
|
||||
this.onDatasourceChange(datasource),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,9 +42,8 @@ const OPERATORS_TO_SQL = {
|
|||
REGEX: 'REGEX',
|
||||
'IS NOT NULL': 'IS NOT NULL',
|
||||
'IS NULL': 'IS NULL',
|
||||
'LATEST PARTITION': ({ datasource }) => {
|
||||
return `= '{{ presto.latest_partition('${datasource.schema}.${datasource.datasource_name}') }}'`;
|
||||
},
|
||||
'LATEST PARTITION': ({ datasource }) =>
|
||||
`= '{{ presto.latest_partition('${datasource.schema}.${datasource.datasource_name}') }}'`,
|
||||
};
|
||||
|
||||
function translateToSql(adhocMetric, { useSimple } = {}) {
|
||||
|
|
|
|||
|
|
@ -96,7 +96,10 @@ export const DataTablesPane = ({
|
|||
|
||||
const getData = useCallback(
|
||||
(resultType: string) => {
|
||||
setIsLoading(prevIsLoading => ({ ...prevIsLoading, [resultType]: true }));
|
||||
setIsLoading(prevIsLoading => ({
|
||||
...prevIsLoading,
|
||||
[resultType]: true,
|
||||
}));
|
||||
return getChartDataRequest({
|
||||
formData: queryFormData,
|
||||
resultFormat: 'json',
|
||||
|
|
|
|||
|
|
@ -218,11 +218,9 @@ const ExploreChartPanel = props => {
|
|||
/>
|
||||
);
|
||||
|
||||
const elementStyle = (dimension, elementSize, gutterSize) => {
|
||||
return {
|
||||
[dimension]: `calc(${elementSize}% - ${gutterSize + gutterMargin}px)`,
|
||||
};
|
||||
};
|
||||
const elementStyle = (dimension, elementSize, gutterSize) => ({
|
||||
[dimension]: `calc(${elementSize}% - ${gutterSize + gutterMargin}px)`,
|
||||
});
|
||||
|
||||
const panelBody = <div className="panel-body">{renderChart()}</div>;
|
||||
|
||||
|
|
|
|||
|
|
@ -198,12 +198,16 @@ export const customTimeRangeEncode = (customRange: CustomRangeType): string => {
|
|||
// relative : specific
|
||||
if (sinceMode === 'relative' && SPECIFIC_MODE.includes(untilMode)) {
|
||||
const until = untilMode === 'specific' ? untilDatetime : untilMode;
|
||||
const since = `DATEADD(DATETIME("${until}"), ${-Math.abs(sinceGrainValue)}, ${sinceGrain})`; // eslint-disable-line
|
||||
const since = `DATEADD(DATETIME("${until}"), ${-Math.abs(
|
||||
sinceGrainValue,
|
||||
)}, ${sinceGrain})`; // eslint-disable-line
|
||||
return `${since} : ${until}`;
|
||||
}
|
||||
|
||||
// relative : relative
|
||||
const since = `DATEADD(DATETIME("${anchorValue}"), ${-Math.abs(sinceGrainValue)}, ${sinceGrain})`; // eslint-disable-line
|
||||
const since = `DATEADD(DATETIME("${anchorValue}"), ${-Math.abs(
|
||||
sinceGrainValue,
|
||||
)}, ${sinceGrain})`; // eslint-disable-line
|
||||
const until = `DATEADD(DATETIME("${anchorValue}"), ${untilGrainValue}, ${untilGrain})`;
|
||||
return `${since} : ${until}`;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -222,9 +222,8 @@ export const buildV1ChartDataPayload = ({
|
|||
});
|
||||
};
|
||||
|
||||
export const getLegacyEndpointType = ({ resultType, resultFormat }) => {
|
||||
return resultFormat === 'csv' ? resultFormat : resultType;
|
||||
};
|
||||
export const getLegacyEndpointType = ({ resultType, resultFormat }) =>
|
||||
resultFormat === 'csv' ? resultFormat : resultType;
|
||||
|
||||
export function postForm(url, payload, target = '_blank') {
|
||||
if (!url) {
|
||||
|
|
|
|||
|
|
@ -39,36 +39,34 @@ import {
|
|||
export default function buildQuery(formData: QueryFormData) {
|
||||
const { groupby } = formData;
|
||||
const [column] = groupby || [];
|
||||
return buildQueryContext(formData, baseQueryObject => {
|
||||
return [
|
||||
{
|
||||
...baseQueryObject,
|
||||
groupby: [],
|
||||
metrics: [
|
||||
{
|
||||
aggregate: 'MIN',
|
||||
column: {
|
||||
columnName: column,
|
||||
id: 1,
|
||||
type: ColumnType.FLOAT,
|
||||
},
|
||||
expressionType: 'SIMPLE',
|
||||
hasCustomLabel: true,
|
||||
label: 'min',
|
||||
return buildQueryContext(formData, baseQueryObject => [
|
||||
{
|
||||
...baseQueryObject,
|
||||
groupby: [],
|
||||
metrics: [
|
||||
{
|
||||
aggregate: 'MIN',
|
||||
column: {
|
||||
columnName: column,
|
||||
id: 1,
|
||||
type: ColumnType.FLOAT,
|
||||
},
|
||||
{
|
||||
aggregate: 'MAX',
|
||||
column: {
|
||||
columnName: column,
|
||||
id: 2,
|
||||
type: ColumnType.FLOAT,
|
||||
},
|
||||
expressionType: 'SIMPLE',
|
||||
hasCustomLabel: true,
|
||||
label: 'max',
|
||||
expressionType: 'SIMPLE',
|
||||
hasCustomLabel: true,
|
||||
label: 'min',
|
||||
},
|
||||
{
|
||||
aggregate: 'MAX',
|
||||
column: {
|
||||
columnName: column,
|
||||
id: 2,
|
||||
type: ColumnType.FLOAT,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
});
|
||||
expressionType: 'SIMPLE',
|
||||
hasCustomLabel: true,
|
||||
label: 'max',
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,11 +33,9 @@ import { buildQueryContext, QueryFormData } from '@superset-ui/core';
|
|||
* if a viz needs multiple different result sets.
|
||||
*/
|
||||
export default function buildQuery(formData: QueryFormData) {
|
||||
return buildQueryContext(formData, baseQueryObject => {
|
||||
return [
|
||||
{
|
||||
...baseQueryObject,
|
||||
},
|
||||
];
|
||||
});
|
||||
return buildQueryContext(formData, baseQueryObject => [
|
||||
{
|
||||
...baseQueryObject,
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,14 +21,12 @@ export const cacheWrapper = <T extends Array<any>, U>(
|
|||
fn: (...args: T) => U,
|
||||
cache: Map<string, any>,
|
||||
keyFn: (...args: T) => string = (...args: T) => JSON.stringify([...args]),
|
||||
) => {
|
||||
return (...args: T): U => {
|
||||
const key = keyFn(...args);
|
||||
if (cache.has(key)) {
|
||||
return cache.get(key);
|
||||
}
|
||||
const result = fn(...args);
|
||||
cache.set(key, result);
|
||||
return result;
|
||||
};
|
||||
) => (...args: T): U => {
|
||||
const key = keyFn(...args);
|
||||
if (cache.has(key)) {
|
||||
return cache.get(key);
|
||||
}
|
||||
const result = fn(...args);
|
||||
cache.set(key, result);
|
||||
return result;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -34,11 +34,8 @@ const GRAY_BACKGROUND_COLOR = '#F5F5F5';
|
|||
* @param description title or description of content of file
|
||||
* @param date date when file was generated
|
||||
*/
|
||||
const generateFileStem = (description: string, date = new Date()) => {
|
||||
return `${kebabCase(description)}-${date
|
||||
.toISOString()
|
||||
.replace(/[: ]/g, '-')}`;
|
||||
};
|
||||
const generateFileStem = (description: string, date = new Date()) =>
|
||||
`${kebabCase(description)}-${date.toISOString().replace(/[: ]/g, '-')}`;
|
||||
|
||||
/**
|
||||
* Create an event handler for turning an element into an image
|
||||
|
|
|
|||
|
|
@ -205,11 +205,10 @@ function AlertList({
|
|||
row: {
|
||||
original: { last_eval_dttm: lastEvalDttm },
|
||||
},
|
||||
}: any) => {
|
||||
return lastEvalDttm
|
||||
}: any) =>
|
||||
lastEvalDttm
|
||||
? moment.utc(lastEvalDttm).local().format(DATETIME_WITH_TIME_ZONE)
|
||||
: '';
|
||||
},
|
||||
: '',
|
||||
accessor: 'last_eval_dttm',
|
||||
Header: t('Last Run'),
|
||||
size: 'lg',
|
||||
|
|
|
|||
|
|
@ -415,13 +415,11 @@ const NotificationMethod: FunctionComponent<NotificationMethodProps> = ({
|
|||
setRecipientValue(recipients);
|
||||
}
|
||||
|
||||
const methodOptions = (options || []).map((method: NotificationMethod) => {
|
||||
return (
|
||||
<Select.Option key={method} value={method}>
|
||||
{t(method)}
|
||||
</Select.Option>
|
||||
);
|
||||
});
|
||||
const methodOptions = (options || []).map((method: NotificationMethod) => (
|
||||
<Select.Option key={method} value={method}>
|
||||
{t(method)}
|
||||
</Select.Option>
|
||||
));
|
||||
|
||||
return (
|
||||
<StyledNotificationMethod>
|
||||
|
|
@ -477,9 +475,10 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({
|
|||
isReport = false,
|
||||
}) => {
|
||||
const [disableSave, setDisableSave] = useState<boolean>(true);
|
||||
const [currentAlert, setCurrentAlert] = useState<Partial<
|
||||
AlertObject
|
||||
> | null>();
|
||||
const [
|
||||
currentAlert,
|
||||
setCurrentAlert,
|
||||
] = useState<Partial<AlertObject> | null>();
|
||||
const [isHidden, setIsHidden] = useState<boolean>(true);
|
||||
const [contentType, setContentType] = useState<string>('dashboard');
|
||||
|
||||
|
|
@ -491,9 +490,10 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({
|
|||
|
||||
const isEditMode = alert !== null;
|
||||
|
||||
const [notificationAddState, setNotificationAddState] = useState<
|
||||
NotificationAddStatus
|
||||
>('active');
|
||||
const [
|
||||
notificationAddState,
|
||||
setNotificationAddState,
|
||||
] = useState<NotificationAddStatus>('active');
|
||||
const [notificationSettings, setNotificationSettings] = useState<
|
||||
NotificationSetting[]
|
||||
>([]);
|
||||
|
|
@ -636,15 +636,12 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({
|
|||
return SupersetClient.get({
|
||||
endpoint: `/api/v1/report/related/owners?q=${query}`,
|
||||
}).then(
|
||||
response => {
|
||||
return response.json.result.map((item: any) => ({
|
||||
response =>
|
||||
response.json.result.map((item: any) => ({
|
||||
value: item.value,
|
||||
label: item.text,
|
||||
}));
|
||||
},
|
||||
badResponse => {
|
||||
return [];
|
||||
},
|
||||
})),
|
||||
badResponse => [],
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -672,9 +669,7 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({
|
|||
|
||||
return list;
|
||||
},
|
||||
badResponse => {
|
||||
return [];
|
||||
},
|
||||
badResponse => [],
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -721,9 +716,7 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({
|
|||
|
||||
return list;
|
||||
},
|
||||
badResponse => {
|
||||
return [];
|
||||
},
|
||||
badResponse => [],
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -766,9 +759,7 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({
|
|||
|
||||
return list;
|
||||
},
|
||||
badResponse => {
|
||||
return [];
|
||||
},
|
||||
badResponse => [],
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -1029,21 +1020,17 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({
|
|||
}
|
||||
|
||||
// Dropdown options
|
||||
const conditionOptions = CONDITIONS.map(condition => {
|
||||
return (
|
||||
<Select.Option key={condition.value} value={condition.value}>
|
||||
{condition.label}
|
||||
</Select.Option>
|
||||
);
|
||||
});
|
||||
const conditionOptions = CONDITIONS.map(condition => (
|
||||
<Select.Option key={condition.value} value={condition.value}>
|
||||
{condition.label}
|
||||
</Select.Option>
|
||||
));
|
||||
|
||||
const retentionOptions = RETENTION_OPTIONS.map(option => {
|
||||
return (
|
||||
<Select.Option key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</Select.Option>
|
||||
);
|
||||
});
|
||||
const retentionOptions = RETENTION_OPTIONS.map(option => (
|
||||
<Select.Option key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</Select.Option>
|
||||
));
|
||||
|
||||
return (
|
||||
<Modal
|
||||
|
|
|
|||
|
|
@ -68,9 +68,10 @@ function AnnotationLayersList({
|
|||
addDangerToast,
|
||||
);
|
||||
|
||||
const [annotationLayerModalOpen, setAnnotationLayerModalOpen] = useState<
|
||||
boolean
|
||||
>(false);
|
||||
const [
|
||||
annotationLayerModalOpen,
|
||||
setAnnotationLayerModalOpen,
|
||||
] = useState<boolean>(false);
|
||||
const [
|
||||
currentAnnotationLayer,
|
||||
setCurrentAnnotationLayer,
|
||||
|
|
|
|||
|
|
@ -536,13 +536,12 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
|
|||
);
|
||||
};
|
||||
|
||||
const handleBulkDatasetExport = (datasetsToExport: Dataset[]) => {
|
||||
return window.location.assign(
|
||||
const handleBulkDatasetExport = (datasetsToExport: Dataset[]) =>
|
||||
window.location.assign(
|
||||
`/api/v1/dataset/export/?q=${rison.encode(
|
||||
datasetsToExport.map(({ id }) => id),
|
||||
)}`,
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -102,9 +102,10 @@ function QueryList({ addDangerToast, addSuccessToast }: QueryListProps) {
|
|||
false,
|
||||
);
|
||||
|
||||
const [queryCurrentlyPreviewing, setQueryCurrentlyPreviewing] = useState<
|
||||
QueryObject
|
||||
>();
|
||||
const [
|
||||
queryCurrentlyPreviewing,
|
||||
setQueryCurrentlyPreviewing,
|
||||
] = useState<QueryObject>();
|
||||
|
||||
const handleQueryPreview = useCallback(
|
||||
(id: number) => {
|
||||
|
|
@ -298,20 +299,18 @@ function QueryList({ addDangerToast, addSuccessToast }: QueryListProps) {
|
|||
{
|
||||
accessor: QueryObjectColumns.sql,
|
||||
Header: t('SQL'),
|
||||
Cell: ({ row: { original, id } }: any) => {
|
||||
return (
|
||||
<div
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
data-test={`open-sql-preview-${id}`}
|
||||
onClick={() => setQueryCurrentlyPreviewing(original)}
|
||||
>
|
||||
<StyledSyntaxHighlighter language="sql" style={github}>
|
||||
{shortenSQL(original.sql, SQL_PREVIEW_MAX_LINES)}
|
||||
</StyledSyntaxHighlighter>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
Cell: ({ row: { original, id } }: any) => (
|
||||
<div
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
data-test={`open-sql-preview-${id}`}
|
||||
onClick={() => setQueryCurrentlyPreviewing(original)}
|
||||
>
|
||||
<StyledSyntaxHighlighter language="sql" style={github}>
|
||||
{shortenSQL(original.sql, SQL_PREVIEW_MAX_LINES)}
|
||||
</StyledSyntaxHighlighter>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
Header: t('Actions'),
|
||||
|
|
@ -321,15 +320,13 @@ function QueryList({ addDangerToast, addSuccessToast }: QueryListProps) {
|
|||
row: {
|
||||
original: { id },
|
||||
},
|
||||
}: any) => {
|
||||
return (
|
||||
<Tooltip title={t('Open query in SQL Lab')} placement="bottom">
|
||||
<a href={`/superset/sqllab?queryId=${id}`}>
|
||||
<Icon name="full" />
|
||||
</a>
|
||||
</Tooltip>
|
||||
);
|
||||
},
|
||||
}: any) => (
|
||||
<Tooltip title={t('Open query in SQL Lab')} placement="bottom">
|
||||
<a href={`/superset/sqllab?queryId=${id}`}>
|
||||
<Icon name="full" />
|
||||
</a>
|
||||
</Tooltip>
|
||||
),
|
||||
},
|
||||
],
|
||||
[],
|
||||
|
|
|
|||
|
|
@ -146,28 +146,26 @@ export default function ActivityTable({
|
|||
}
|
||||
return e.sql ? `/superset/sqllab?savedQueryId=${e.id}` : e.url;
|
||||
};
|
||||
return activityData[activeChild].map((e: ActivityObjects) => {
|
||||
return (
|
||||
<CardStyles
|
||||
onClick={() => {
|
||||
window.location.href = getRecentRef(e);
|
||||
}}
|
||||
key={e.id}
|
||||
>
|
||||
<ListViewCard
|
||||
loading={loading}
|
||||
cover={<></>}
|
||||
url={e.sql ? `/superset/sqllab?savedQueryId=${e.id}` : e.url}
|
||||
title={getFilterTitle(e)}
|
||||
description={`Last Edited: ${moment(e.changed_on_utc).format(
|
||||
'MM/DD/YYYY HH:mm:ss',
|
||||
)}`}
|
||||
avatar={getIconName(e)}
|
||||
actions={null}
|
||||
/>
|
||||
</CardStyles>
|
||||
);
|
||||
});
|
||||
return activityData[activeChild].map((e: ActivityObjects) => (
|
||||
<CardStyles
|
||||
onClick={() => {
|
||||
window.location.href = getRecentRef(e);
|
||||
}}
|
||||
key={e.id}
|
||||
>
|
||||
<ListViewCard
|
||||
loading={loading}
|
||||
cover={<></>}
|
||||
url={e.sql ? `/superset/sqllab?savedQueryId=${e.id}` : e.url}
|
||||
title={getFilterTitle(e)}
|
||||
description={`Last Edited: ${moment(e.changed_on_utc).format(
|
||||
'MM/DD/YYYY HH:mm:ss',
|
||||
)}`}
|
||||
avatar={getIconName(e)}
|
||||
actions={null}
|
||||
/>
|
||||
</CardStyles>
|
||||
));
|
||||
};
|
||||
if (loading) return <Loading position="inline" />;
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -100,8 +100,8 @@ function ChartTable({
|
|||
return filters;
|
||||
};
|
||||
|
||||
const getData = (filter: string) => {
|
||||
return fetchData({
|
||||
const getData = (filter: string) =>
|
||||
fetchData({
|
||||
pageIndex: 0,
|
||||
pageSize: PAGE_SIZE,
|
||||
sortBy: [
|
||||
|
|
@ -112,7 +112,6 @@ function ChartTable({
|
|||
],
|
||||
filters: getFilters(filter),
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
|
|
|
|||
|
|
@ -66,8 +66,8 @@ function DashboardTable({
|
|||
const [editModal, setEditModal] = useState<Dashboard>();
|
||||
const [dashboardFilter, setDashboardFilter] = useState('Mine');
|
||||
|
||||
const handleDashboardEdit = (edits: Dashboard) => {
|
||||
return SupersetClient.get({
|
||||
const handleDashboardEdit = (edits: Dashboard) =>
|
||||
SupersetClient.get({
|
||||
endpoint: `/api/v1/dashboard/${edits.id}`,
|
||||
}).then(
|
||||
({ json = {} }) => {
|
||||
|
|
@ -86,7 +86,6 @@ function DashboardTable({
|
|||
),
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
const getFilters = (filterName: string) => {
|
||||
const filters = [];
|
||||
|
|
@ -114,8 +113,8 @@ function DashboardTable({
|
|||
});
|
||||
}
|
||||
|
||||
const getData = (filter: string) => {
|
||||
return fetchData({
|
||||
const getData = (filter: string) =>
|
||||
fetchData({
|
||||
pageIndex: 0,
|
||||
pageSize: PAGE_SIZE,
|
||||
sortBy: [
|
||||
|
|
@ -126,7 +125,6 @@ function DashboardTable({
|
|||
],
|
||||
filters: getFilters(filter),
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -187,8 +187,8 @@ const SavedQueries = ({
|
|||
return filters;
|
||||
};
|
||||
|
||||
const getData = (filter: string) => {
|
||||
return fetchData({
|
||||
const getData = (filter: string) =>
|
||||
fetchData({
|
||||
pageIndex: 0,
|
||||
pageSize: PAGE_SIZE,
|
||||
sortBy: [
|
||||
|
|
@ -199,7 +199,6 @@ const SavedQueries = ({
|
|||
],
|
||||
filters: getFilters(filter),
|
||||
});
|
||||
};
|
||||
|
||||
const renderMenu = (query: Query) => (
|
||||
<Menu>
|
||||
|
|
|
|||
|
|
@ -130,9 +130,7 @@ class FilterBox extends React.PureComponent {
|
|||
return this.onFilterMenuOpen(TIME_RANGE);
|
||||
}
|
||||
|
||||
onCloseDateFilterControl = () => {
|
||||
return this.onFilterMenuClose(TIME_RANGE);
|
||||
};
|
||||
onCloseDateFilterControl = () => this.onFilterMenuClose(TIME_RANGE);
|
||||
|
||||
getControlData(controlName) {
|
||||
const { selectedValues } = this.state;
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ const babelLoader = {
|
|||
[
|
||||
'@emotion/babel-preset-css-prop',
|
||||
{
|
||||
autoLabel: true,
|
||||
autoLabel: 'dev-only',
|
||||
labelFormat: '[local]',
|
||||
},
|
||||
],
|
||||
|
|
@ -441,9 +441,7 @@ if (isDevMode) {
|
|||
// and proxy everything else to Superset backend
|
||||
proxy: [
|
||||
// functions are called for every request
|
||||
() => {
|
||||
return proxyConfig;
|
||||
},
|
||||
() => proxyConfig,
|
||||
],
|
||||
contentBase: path.join(process.cwd(), '../static/assets'),
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue