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