diff --git a/superset-frontend/.eslintrc.js b/superset-frontend/.eslintrc.js
index d1cbd2ce0..591539b62 100644
--- a/superset-frontend/.eslintrc.js
+++ b/superset-frontend/.eslintrc.js
@@ -84,7 +84,6 @@ module.exports = {
'jsx-a11y/anchor-is-valid': 0, // disabled temporarily
'jsx-a11y/click-events-have-key-events': 0, // re-enable up for discussion
'jsx-a11y/mouse-events-have-key-events': 0, // re-enable up for discussion
- 'lines-between-class-members': 0, // disabled temporarily
'new-cap': 0,
'no-bitwise': 0,
'no-continue': 0,
@@ -197,7 +196,6 @@ module.exports = {
'jsx-a11y/anchor-is-valid': 0, // disabled temporarily
'jsx-a11y/click-events-have-key-events': 0, // re-enable up for discussion
'jsx-a11y/mouse-events-have-key-events': 0, // re-enable up for discussion
- 'lines-between-class-members': 0, // disabled temporarily
'new-cap': 0,
'no-bitwise': 0,
'no-continue': 0,
diff --git a/superset-frontend/src/CRUD/CollectionTable.tsx b/superset-frontend/src/CRUD/CollectionTable.tsx
index 61a5477d8..661547fbe 100644
--- a/superset-frontend/src/CRUD/CollectionTable.tsx
+++ b/superset-frontend/src/CRUD/CollectionTable.tsx
@@ -78,6 +78,7 @@ export default class CRUDCollection extends React.PureComponent<
this.renderTableBody = this.renderTableBody.bind(this);
this.changeCollection = this.changeCollection.bind(this);
}
+
UNSAFE_componentWillReceiveProps(nextProps: CRUDCollectionProps) {
if (nextProps.collection !== this.props.collection) {
this.setState({
@@ -85,6 +86,7 @@ export default class CRUDCollection extends React.PureComponent<
});
}
}
+
onCellChange(id: number, col: string, val: boolean) {
this.changeCollection({
...this.state.collection,
@@ -94,6 +96,7 @@ export default class CRUDCollection extends React.PureComponent<
},
});
}
+
onAddItem() {
if (this.props.itemGenerator) {
let newItem = this.props.itemGenerator();
@@ -106,12 +109,14 @@ export default class CRUDCollection extends React.PureComponent<
});
}
}
+
onFieldsetChange(item: any) {
this.changeCollection({
...this.state.collection,
[item.id]: item,
});
}
+
getLabel(col: any) {
const { columnLabels } = this.props;
let label = columnLabels && columnLabels[col] ? columnLabels[col] : col;
@@ -121,17 +126,20 @@ export default class CRUDCollection extends React.PureComponent<
}
return label;
}
+
changeCollection(collection: any) {
this.setState({ collection });
if (this.props.onChange) {
this.props.onChange(Object.keys(collection).map(k => collection[k]));
}
}
+
deleteItem(id: number) {
const newColl = { ...this.state.collection };
delete newColl[id];
this.changeCollection(newColl);
}
+
effectiveTableColumns() {
const { tableColumns, allowDeletes, expandFieldset } = this.props;
const cols = allowDeletes
@@ -139,6 +147,7 @@ export default class CRUDCollection extends React.PureComponent<
: tableColumns;
return expandFieldset ? ['__expand'].concat(cols) : cols;
}
+
toggleExpand(id: any) {
this.onCellChange(id, '__expanded', false);
this.setState({
@@ -148,6 +157,7 @@ export default class CRUDCollection extends React.PureComponent<
},
});
}
+
renderHeaderRow() {
const cols = this.effectiveTableColumns();
const {
@@ -178,6 +188,7 @@ export default class CRUDCollection extends React.PureComponent<
);
}
+
renderExpandableSection(item: any) {
const propsGenerator = () => ({ item, onChange: this.onFieldsetChange });
return recurseReactClone(
@@ -186,12 +197,14 @@ export default class CRUDCollection extends React.PureComponent<
propsGenerator,
);
}
+
renderCell(record: any, col: any) {
const renderer = this.props.itemRenderers && this.props.itemRenderers[col];
const val = record[col];
const onChange = this.onCellChange.bind(this, record.id, col);
return renderer ? renderer(val, onChange, this.getLabel(col), record) : val;
}
+
renderItem(record: any) {
const {
allowAddItem,
@@ -258,6 +271,7 @@ export default class CRUDCollection extends React.PureComponent<
}
return trs;
}
+
renderEmptyCell() {
return (
@@ -265,6 +279,7 @@ export default class CRUDCollection extends React.PureComponent<
);
}
+
renderTableBody() {
const data = Object.keys(this.state.collection).map(
k => this.state.collection[k],
@@ -274,6 +289,7 @@ export default class CRUDCollection extends React.PureComponent<
: this.renderEmptyCell();
return {content};
}
+
render() {
return (
diff --git a/superset-frontend/src/CRUD/Field.jsx b/superset-frontend/src/CRUD/Field.jsx
index 7b249b439..3d56019fa 100644
--- a/superset-frontend/src/CRUD/Field.jsx
+++ b/superset-frontend/src/CRUD/Field.jsx
@@ -50,9 +50,11 @@ export default class Field extends React.PureComponent {
super(props);
this.onChange = this.onChange.bind(this);
}
+
onChange(newValue) {
this.props.onChange(this.props.fieldKey, newValue);
}
+
render() {
const {
compact,
diff --git a/superset-frontend/src/CRUD/Fieldset.jsx b/superset-frontend/src/CRUD/Fieldset.jsx
index f73cd7928..15eb1a7cb 100644
--- a/superset-frontend/src/CRUD/Fieldset.jsx
+++ b/superset-frontend/src/CRUD/Fieldset.jsx
@@ -40,12 +40,14 @@ export default class Fieldset extends React.PureComponent {
super(props);
this.onChange = this.onChange.bind(this);
}
+
onChange(fieldKey, val) {
return this.props.onChange({
...this.props.item,
[fieldKey]: val,
});
}
+
render() {
const { title } = this.props;
const propExtender = field => ({
diff --git a/superset-frontend/src/SqlLab/components/AceEditorWrapper.tsx b/superset-frontend/src/SqlLab/components/AceEditorWrapper.tsx
index f3779b90a..a05ef3cdf 100644
--- a/superset-frontend/src/SqlLab/components/AceEditorWrapper.tsx
+++ b/superset-frontend/src/SqlLab/components/AceEditorWrapper.tsx
@@ -83,11 +83,13 @@ class AceEditorWrapper extends React.PureComponent
{
};
this.onChange = this.onChange.bind(this);
}
+
componentDidMount() {
// Making sure no text is selected from previous mount
this.props.actions.queryEditorSetSelectedText(this.props.queryEditor, null);
this.setAutoCompleter(this.props);
}
+
UNSAFE_componentWillReceiveProps(nextProps: Props) {
if (
!areArraysShallowEqual(this.props.tables, nextProps.tables) ||
@@ -103,12 +105,15 @@ class AceEditorWrapper extends React.PureComponent {
this.setState({ sql: nextProps.sql });
}
}
+
onBlur() {
this.props.onBlur(this.state.sql);
}
+
onAltEnter() {
this.props.onBlur(this.state.sql);
}
+
onEditorLoad(editor: any) {
editor.commands.addCommand({
name: 'runQuery',
@@ -140,10 +145,12 @@ class AceEditorWrapper extends React.PureComponent {
}
});
}
+
onChange(text: string) {
this.setState({ sql: text });
this.props.onChange(text);
}
+
getCompletions(
aceEditor: any,
session: any,
@@ -180,6 +187,7 @@ class AceEditorWrapper extends React.PureComponent {
});
callback(null, words);
}
+
setAutoCompleter(props: Props) {
// Loading schema, table and column names as auto-completable words
const schemas = props.schemas || [];
@@ -236,6 +244,7 @@ class AceEditorWrapper extends React.PureComponent {
}
});
}
+
getAceAnnotations() {
const { validationResult } = this.props.queryEditor;
const resultIsReady = validationResult && validationResult.completed;
@@ -250,6 +259,7 @@ class AceEditorWrapper extends React.PureComponent {
}
return [];
}
+
render() {
return (
=
@@ -64,13 +66,16 @@ class App extends React.PureComponent {
);
}
}
+
componentWillUnmount() {
window.removeEventListener('hashchange', this.onHashChanged.bind(this));
window.removeEventListener('resize', this.handleResize.bind(this));
}
+
onHashChanged() {
this.setState({ hash: window.location.hash });
}
+
getHeight() {
const warningEl = $('#navbar-warning');
const tabsEl = $('.nav-tabs');
@@ -96,6 +101,7 @@ class App extends React.PureComponent {
alertHeight
}px`;
}
+
showLocalStorageUsageWarning(currentUsage) {
this.props.actions.addDangerToast(
t(
@@ -109,9 +115,11 @@ class App extends React.PureComponent {
),
);
}
+
handleResize() {
this.setState({ contentHeight: this.getHeight() });
}
+
render() {
let content;
if (this.state.hash) {
diff --git a/superset-frontend/src/SqlLab/components/ExploreCtasResultsButton.jsx b/superset-frontend/src/SqlLab/components/ExploreCtasResultsButton.jsx
index 5e11204b6..5c6f78f2f 100644
--- a/superset-frontend/src/SqlLab/components/ExploreCtasResultsButton.jsx
+++ b/superset-frontend/src/SqlLab/components/ExploreCtasResultsButton.jsx
@@ -47,6 +47,7 @@ class ExploreCtasResultsButton extends React.PureComponent {
this.visualize = this.visualize.bind(this);
this.onClick = this.onClick.bind(this);
}
+
onClick() {
this.visualize();
}
@@ -59,6 +60,7 @@ class ExploreCtasResultsButton extends React.PureComponent {
templateParams: this.props.templateParams,
};
}
+
visualize() {
this.props.actions
.createCtasDatasource(this.buildVizOptions())
@@ -85,6 +87,7 @@ class ExploreCtasResultsButton extends React.PureComponent {
);
});
}
+
render() {
return (
<>
diff --git a/superset-frontend/src/SqlLab/components/ExploreResultsButton.jsx b/superset-frontend/src/SqlLab/components/ExploreResultsButton.jsx
index 2e5c1879e..0e3661d9a 100644
--- a/superset-frontend/src/SqlLab/components/ExploreResultsButton.jsx
+++ b/superset-frontend/src/SqlLab/components/ExploreResultsButton.jsx
@@ -52,6 +52,7 @@ class ExploreResultsButton extends React.PureComponent {
this,
);
}
+
onClick() {
const { timeout } = this.props;
const msg = this.renderInvalidColumnMessage();
@@ -85,6 +86,7 @@ class ExploreResultsButton extends React.PureComponent {
this.visualize();
}
}
+
getColumns() {
const { props } = this;
if (
@@ -96,11 +98,13 @@ class ExploreResultsButton extends React.PureComponent {
}
return [];
}
+
getQueryDuration() {
return moment
.duration(this.props.query.endDttm - this.props.query.startDttm)
.asSeconds();
}
+
getInvalidColumns() {
const re1 = /__\d+$/; // duplicate column name pattern
const re2 = /^__timestamp/i; // reserved temporal column alias
@@ -109,6 +113,7 @@ class ExploreResultsButton extends React.PureComponent {
.map(col => col.name)
.filter(col => re1.test(col) || re2.test(col));
}
+
datasourceName() {
const { query } = this.props;
const uniqueId = shortid.generate();
@@ -119,6 +124,7 @@ class ExploreResultsButton extends React.PureComponent {
}
return datasourceName;
}
+
buildVizOptions() {
const { schema, sql, dbId, templateParams } = this.props.query;
return {
@@ -130,6 +136,7 @@ class ExploreResultsButton extends React.PureComponent {
columns: this.getColumns(),
};
}
+
visualize() {
this.props.actions
.createDatasource(this.buildVizOptions())
@@ -158,6 +165,7 @@ class ExploreResultsButton extends React.PureComponent {
);
});
}
+
renderTimeoutWarning() {
return (
@@ -181,6 +189,7 @@ class ExploreResultsButton extends React.PureComponent {
);
}
+
renderInvalidColumnMessage() {
const invalidColumns = this.getInvalidColumns();
if (invalidColumns.length === 0) {
@@ -200,6 +209,7 @@ class ExploreResultsButton extends React.PureComponent {
);
}
+
render() {
const allowsSubquery =
this.props.database && this.props.database.allows_subquery;
diff --git a/superset-frontend/src/SqlLab/components/HighlightedSql.jsx b/superset-frontend/src/SqlLab/components/HighlightedSql.jsx
index e2409fd91..57ce57910 100644
--- a/superset-frontend/src/SqlLab/components/HighlightedSql.jsx
+++ b/superset-frontend/src/SqlLab/components/HighlightedSql.jsx
@@ -50,6 +50,7 @@ class HighlightedSql extends React.Component {
modalBody: null,
};
}
+
shrinkSql() {
const ssql = this.props.sql || '';
let lines = ssql.split('\n');
@@ -66,6 +67,7 @@ class HighlightedSql extends React.Component {
})
.join('\n');
}
+
triggerNode() {
const shownSql = this.props.shrink
? this.shrinkSql(this.props.sql)
@@ -76,6 +78,7 @@ class HighlightedSql extends React.Component {
);
}
+
generateModal() {
let rawSql;
if (this.props.rawSql && this.props.rawSql !== this.props.sql) {
@@ -100,6 +103,7 @@ class HighlightedSql extends React.Component {
),
});
}
+
render() {
return (
isQueryRunning(q) && now - q.startDttm < MAX_QUERY_AGE_TO_POLL,
);
}
+
startTimer() {
if (!this.timer) {
this.timer = setInterval(this.stopwatch.bind(this), QUERY_UPDATE_FREQ);
}
}
+
stopTimer() {
clearInterval(this.timer);
this.timer = null;
}
+
stopwatch() {
// only poll /superset/queries/ if there are started or running queries
if (this.shouldCheckForQueries()) {
@@ -89,6 +96,7 @@ class QueryAutoRefresh extends React.PureComponent {
this.setState({ offline: false });
}
}
+
render() {
return null;
}
diff --git a/superset-frontend/src/SqlLab/components/QueryTable.jsx b/superset-frontend/src/SqlLab/components/QueryTable.jsx
index 2a23acd4f..978427df7 100644
--- a/superset-frontend/src/SqlLab/components/QueryTable.jsx
+++ b/superset-frontend/src/SqlLab/components/QueryTable.jsx
@@ -60,15 +60,19 @@ class QueryTable extends React.PureComponent {
openQueryInNewTab(query) {
this.props.actions.cloneQueryToNewTab(query, true);
}
+
openAsyncResults(query, displayLimit) {
this.props.actions.fetchQueryResults(query, displayLimit);
}
+
clearQueryResults(query) {
this.props.actions.clearQueryResults(query);
}
+
removeQuery(query) {
this.props.actions.removeQuery(query);
}
+
render() {
const data = this.props.queries
.map(query => {
diff --git a/superset-frontend/src/SqlLab/components/ResultSet.tsx b/superset-frontend/src/SqlLab/components/ResultSet.tsx
index 3b2c218d9..1846ddc1a 100644
--- a/superset-frontend/src/SqlLab/components/ResultSet.tsx
+++ b/superset-frontend/src/SqlLab/components/ResultSet.tsx
@@ -86,10 +86,12 @@ export default class ResultSet extends React.PureComponent<
this,
);
}
+
componentDidMount() {
// only do this the first time the component is rendered/mounted
this.reRunQueryIfSessionTimeoutErrorOnMount();
}
+
UNSAFE_componentWillReceiveProps(nextProps: ResultSetProps) {
// when new results comes in, save them locally and clear in store
if (
@@ -110,9 +112,11 @@ export default class ResultSet extends React.PureComponent<
this.fetchResults(nextProps.query);
}
}
+
clearQueryResults(query: Query) {
this.props.actions.clearQueryResults(query);
}
+
popSelectStar(tempSchema: string | null, tempTable: string) {
const qe = {
id: shortid.generate(),
@@ -123,20 +127,25 @@ export default class ResultSet extends React.PureComponent<
};
this.props.actions.addQueryEditor(qe);
}
+
toggleExploreResultsButton() {
this.setState({
showExploreResultsButton: !this.state.showExploreResultsButton,
});
}
+
changeSearch(event: React.ChangeEvent) {
this.setState({ searchText: event.target.value });
}
+
fetchResults(query: Query) {
this.props.actions.fetchQueryResults(query, this.props.displayLimit);
}
+
reFetchQueryResults(query: Query) {
this.props.actions.reFetchQueryResults(query);
}
+
reRunQueryIfSessionTimeoutErrorOnMount() {
const { query } = this.props;
if (
@@ -146,6 +155,7 @@ export default class ResultSet extends React.PureComponent<
this.props.actions.runQuery(query, true);
}
}
+
renderControls() {
if (this.props.search || this.props.visualize || this.props.csv) {
let { data } = this.props.query.results;
@@ -198,6 +208,7 @@ export default class ResultSet extends React.PureComponent<
}
return ;
}
+
render() {
const { query } = this.props;
const height = Math.max(
diff --git a/superset-frontend/src/SqlLab/components/SaveQuery.jsx b/superset-frontend/src/SqlLab/components/SaveQuery.jsx
index e7ed40883..cbda842dc 100644
--- a/superset-frontend/src/SqlLab/components/SaveQuery.jsx
+++ b/superset-frontend/src/SqlLab/components/SaveQuery.jsx
@@ -55,23 +55,29 @@ class SaveQuery extends React.PureComponent {
this.onLabelChange = this.onLabelChange.bind(this);
this.onDescriptionChange = this.onDescriptionChange.bind(this);
}
+
onSave() {
this.props.onSave(this.queryPayload());
this.close();
}
+
onUpdate() {
this.props.onUpdate(this.queryPayload());
this.close();
}
+
onCancel() {
this.close();
}
+
onLabelChange(e) {
this.setState({ label: e.target.value });
}
+
onDescriptionChange(e) {
this.setState({ description: e.target.value });
}
+
queryPayload() {
return {
...this.props.query,
@@ -79,12 +85,15 @@ class SaveQuery extends React.PureComponent {
description: this.state.description,
};
}
+
close() {
if (this.saveModal) this.saveModal.close();
}
+
toggleSave() {
this.setState({ showSave: !this.state.showSave });
}
+
renderModalBody() {
const isSaved = !!this.props.query.remoteId;
return (
@@ -157,6 +166,7 @@ class SaveQuery extends React.PureComponent {
);
}
+
render() {
return (
diff --git a/superset-frontend/src/SqlLab/components/ScheduleQueryButton.jsx b/superset-frontend/src/SqlLab/components/ScheduleQueryButton.jsx
index 96d055efc..f9a778dd5 100644
--- a/superset-frontend/src/SqlLab/components/ScheduleQueryButton.jsx
+++ b/superset-frontend/src/SqlLab/components/ScheduleQueryButton.jsx
@@ -106,6 +106,7 @@ class ScheduleQueryButton extends React.PureComponent {
this.onLabelChange = this.onLabelChange.bind(this);
this.onDescriptionChange = this.onDescriptionChange.bind(this);
}
+
onSchedule({ formData }) {
const query = {
label: this.state.label,
@@ -118,18 +119,23 @@ class ScheduleQueryButton extends React.PureComponent {
this.props.onSchedule(query);
this.saveModal.close();
}
+
onCancel() {
this.saveModal.close();
}
+
onLabelChange(e) {
this.setState({ label: e.target.value });
}
+
onDescriptionChange(e) {
this.setState({ description: e.target.value });
}
+
toggleSchedule() {
this.setState({ showSchedule: !this.state.showSchedule });
}
+
renderModalBody() {
return (
@@ -181,6 +187,7 @@ class ScheduleQueryButton extends React.PureComponent {
);
}
+
render() {
return (
diff --git a/superset-frontend/src/SqlLab/components/SouthPane.jsx b/superset-frontend/src/SqlLab/components/SouthPane.jsx
index 92a3c4e4d..2b2b27052 100644
--- a/superset-frontend/src/SqlLab/components/SouthPane.jsx
+++ b/superset-frontend/src/SqlLab/components/SouthPane.jsx
@@ -68,19 +68,23 @@ export class SouthPane extends React.PureComponent {
this.getSouthPaneHeight = this.getSouthPaneHeight.bind(this);
this.switchTab = this.switchTab.bind(this);
}
+
UNSAFE_componentWillReceiveProps() {
// south pane expands the entire height of the tab content on mount
this.setState({ height: this.getSouthPaneHeight() });
}
+
// One layer of abstraction for easy spying in unit tests
getSouthPaneHeight() {
return this.southPaneRef.current
? this.southPaneRef.current.clientHeight
: 0;
}
+
switchTab(id) {
this.props.actions.setActiveSouthPaneTab(id);
}
+
render() {
if (this.props.offline) {
return (
diff --git a/superset-frontend/src/SqlLab/components/SqlEditor.jsx b/superset-frontend/src/SqlLab/components/SqlEditor.jsx
index c3757c79a..a95dbd038 100644
--- a/superset-frontend/src/SqlLab/components/SqlEditor.jsx
+++ b/superset-frontend/src/SqlLab/components/SqlEditor.jsx
@@ -128,6 +128,7 @@ class SqlEditor extends React.PureComponent {
WINDOW_RESIZE_THROTTLE_MS,
);
}
+
UNSAFE_componentWillMount() {
if (this.state.autorun) {
this.setState({ autorun: false });
@@ -135,6 +136,7 @@ class SqlEditor extends React.PureComponent {
this.startQuery();
}
}
+
componentDidMount() {
// We need to measure the height of the sql editor post render to figure the height of
// the south pane so it gets rendered properly
@@ -143,14 +145,17 @@ class SqlEditor extends React.PureComponent {
window.addEventListener('resize', this.handleWindowResize);
}
+
componentWillUnmount() {
window.removeEventListener('resize', this.handleWindowResize);
}
+
onResizeStart() {
// Set the heights on the ace editor and the ace content area after drag starts
// to smooth out the visual transition to the new heights when drag ends
document.getElementsByClassName('ace_content')[0].style.height = '100%';
}
+
onResizeEnd([northPercent, southPercent]) {
this.setState({ northPercent, southPercent });
@@ -162,6 +167,7 @@ class SqlEditor extends React.PureComponent {
);
}
}
+
onSqlChanged(sql) {
this.setState({ sql });
this.setQueryEditorSqlWithDebounce(sql);
@@ -171,12 +177,14 @@ class SqlEditor extends React.PureComponent {
this.requestValidation();
}
}
+
// One layer of abstraction for easy spying in unit tests
getSqlEditorHeight() {
return this.sqlEditorRef.current
? this.sqlEditorRef.current.clientHeight - SQL_EDITOR_PADDING * 2
: 0;
}
+
// Return the heights for the ace editor and the south pane as an object
// given the height of the sql editor, north pane percent and south pane percent.
getAceEditorAndSouthPaneHeights(height, northPercent, southPercent) {
@@ -190,6 +198,7 @@ class SqlEditor extends React.PureComponent {
(SQL_EDITOR_GUTTER_HEIGHT / 2 + SQL_EDITOR_GUTTER_MARGIN),
};
}
+
getHotkeyConfig() {
return [
{
@@ -224,15 +233,18 @@ class SqlEditor extends React.PureComponent {
},
];
}
+
setQueryEditorSql(sql) {
this.props.actions.queryEditorSetSql(this.props.queryEditor, sql);
}
+
setQueryLimit(queryLimit) {
this.props.actions.queryEditorSetQueryLimit(
this.props.queryEditor,
queryLimit,
);
}
+
getQueryCostEstimate() {
if (this.props.database) {
const qe = this.props.queryEditor;
@@ -246,12 +258,15 @@ class SqlEditor extends React.PureComponent {
this.props.actions.estimateQueryCost(query);
}
}
+
handleToggleAutocompleteEnabled = () => {
this.setState({ autocompleteEnabled: !this.state.autocompleteEnabled });
};
+
handleWindowResize() {
this.setState({ height: this.getSqlEditorHeight() });
}
+
elementStyle(dimension, elementSize, gutterSize) {
return {
[dimension]: `calc(${elementSize}% - ${
@@ -259,6 +274,7 @@ class SqlEditor extends React.PureComponent {
}px)`,
};
}
+
requestValidation() {
if (this.props.database) {
const qe = this.props.queryEditor;
@@ -272,6 +288,7 @@ class SqlEditor extends React.PureComponent {
this.props.actions.validateQuery(query);
}
}
+
canValidateQuery() {
// Check whether or not we can validate the current query based on whether
// or not the backend has a validator configured for it.
@@ -281,11 +298,13 @@ class SqlEditor extends React.PureComponent {
}
return false;
}
+
runQuery() {
if (this.props.database) {
this.startQuery();
}
}
+
startQuery(ctas = false, ctas_method = CtasEnum.TABLE) {
const qe = this.props.queryEditor;
const query = {
@@ -307,6 +326,7 @@ class SqlEditor extends React.PureComponent {
this.props.actions.runQuery(query);
this.props.actions.setActiveSouthPaneTab('Results');
}
+
stopQuery() {
if (
this.props.latestQuery &&
@@ -315,15 +335,19 @@ class SqlEditor extends React.PureComponent {
this.props.actions.postStopQuery(this.props.latestQuery);
}
}
+
createTableAs() {
this.startQuery(true, CtasEnum.TABLE);
}
+
createViewAs() {
this.startQuery(true, CtasEnum.VIEW);
}
+
ctasChanged(event) {
this.setState({ ctas: event.target.value });
}
+
queryPane() {
const hotkeys = this.getHotkeyConfig();
const {
@@ -376,6 +400,7 @@ class SqlEditor extends React.PureComponent {
);
}
+
renderEditorBottomBar(hotkeys) {
let ctasControls;
if (
@@ -560,6 +585,7 @@ class SqlEditor extends React.PureComponent {
);
}
+
render() {
return (
diff --git a/superset-frontend/src/SqlLab/components/SqlEditorLeftBar.jsx b/superset-frontend/src/SqlLab/components/SqlEditorLeftBar.jsx
index dfd04e0a1..552ba4ce6 100644
--- a/superset-frontend/src/SqlLab/components/SqlEditorLeftBar.jsx
+++ b/superset-frontend/src/SqlLab/components/SqlEditorLeftBar.jsx
@@ -50,27 +50,33 @@ export default class SqlEditorLeftBar extends React.PureComponent {
this.getDbList = this.getDbList.bind(this);
this.onTableChange = this.onTableChange.bind(this);
}
+
onSchemaChange(schema) {
this.props.actions.queryEditorSetSchema(this.props.queryEditor, schema);
}
+
onSchemasLoad(schemas) {
this.props.actions.queryEditorSetSchemaOptions(
this.props.queryEditor,
schemas,
);
}
+
onTablesLoad(tables) {
this.props.actions.queryEditorSetTableOptions(
this.props.queryEditor,
tables,
);
}
+
onDbChange(db) {
this.props.actions.queryEditorSetDb(this.props.queryEditor, db.id);
}
+
onTableChange(tableName, schemaName) {
this.props.actions.addTable(this.props.queryEditor, tableName, schemaName);
}
+
getDbList(dbs) {
this.props.actions.setDatabases(dbs);
}
@@ -92,6 +98,7 @@ export default class SqlEditorLeftBar extends React.PureComponent {
resetState() {
this.props.actions.resetState();
}
+
changeTable(tableOpt) {
if (!tableOpt) {
return;
@@ -105,6 +112,7 @@ export default class SqlEditorLeftBar extends React.PureComponent {
closePopover(ref) {
this.refs[ref].hide();
}
+
render() {
const shouldShowReset = window.location.search === '?reset=1';
const tableMetaDataHeight = this.props.height - 130; // 130 is the height of the selects above
diff --git a/superset-frontend/src/SqlLab/components/TabbedSqlEditors.jsx b/superset-frontend/src/SqlLab/components/TabbedSqlEditors.jsx
index 9ab25012c..b97d28d81 100644
--- a/superset-frontend/src/SqlLab/components/TabbedSqlEditors.jsx
+++ b/superset-frontend/src/SqlLab/components/TabbedSqlEditors.jsx
@@ -75,6 +75,7 @@ class TabbedSqlEditors extends React.PureComponent {
);
this.duplicateQueryEditor = this.duplicateQueryEditor.bind(this);
}
+
componentDidMount() {
// migrate query editor and associated tables state to server
if (isFeatureEnabled(FeatureFlag.SQLLAB_BACKEND_PERSISTENCE)) {
@@ -168,6 +169,7 @@ class TabbedSqlEditors extends React.PureComponent {
}
}
}
+
UNSAFE_componentWillReceiveProps(nextProps) {
const nextActiveQeId =
nextProps.tabHistory[nextProps.tabHistory.length - 1];
@@ -201,11 +203,13 @@ class TabbedSqlEditors extends React.PureComponent {
this.setState({ dataPreviewQueries });
}
}
+
popNewTab() {
queryCount += 1;
// Clean the url in browser history
window.history.replaceState({}, document.title, this.state.sqlLabUrl);
}
+
renameTab(qe) {
/* eslint no-alert: 0 */
const newTitle = prompt(t('Enter a new title for the tab'));
@@ -213,6 +217,7 @@ class TabbedSqlEditors extends React.PureComponent {
this.props.actions.queryEditorSetTitle(qe, newTitle);
}
}
+
activeQueryEditor() {
if (this.props.tabHistory.length === 0) {
return this.props.queryEditors[0];
@@ -220,6 +225,7 @@ class TabbedSqlEditors extends React.PureComponent {
const qeid = this.props.tabHistory[this.props.tabHistory.length - 1];
return this.props.queryEditors.find(qe => qe.id === qeid) || null;
}
+
newQueryEditor() {
queryCount += 1;
const activeQueryEditor = this.activeQueryEditor();
@@ -244,6 +250,7 @@ class TabbedSqlEditors extends React.PureComponent {
};
this.props.actions.addQueryEditor(qe);
}
+
handleSelect(key) {
if (key === 'add_tab') {
this.newQueryEditor();
@@ -258,20 +265,25 @@ class TabbedSqlEditors extends React.PureComponent {
}
}
}
+
removeQueryEditor(qe) {
this.props.actions.removeQueryEditor(qe);
}
+
removeAllOtherQueryEditors(cqe) {
this.props.queryEditors.forEach(
qe => qe !== cqe && this.removeQueryEditor(qe),
);
}
+
duplicateQueryEditor(qe) {
this.props.actions.cloneQueryToNewTab(qe, false);
}
+
toggleLeftBar() {
this.setState({ hideLeftBar: !this.state.hideLeftBar });
}
+
render() {
const editors = this.props.queryEditors.map((qe, i) => {
const isSelected =
diff --git a/superset-frontend/src/SqlLab/components/TableElement.jsx b/superset-frontend/src/SqlLab/components/TableElement.jsx
index ed7563ae5..5594f4194 100644
--- a/superset-frontend/src/SqlLab/components/TableElement.jsx
+++ b/superset-frontend/src/SqlLab/components/TableElement.jsx
@@ -83,6 +83,7 @@ class TableElement extends React.PureComponent {
this.setState({ expanded: false });
this.props.actions.removeDataPreview(this.props.table);
}
+
toggleSortColumns() {
this.setState({ sortColumns: !this.state.sortColumns });
}
@@ -127,6 +128,7 @@ class TableElement extends React.PureComponent {
}
return header;
}
+
renderControls() {
let keyLink;
const { table } = this.props;
@@ -190,6 +192,7 @@ class TableElement extends React.PureComponent {
);
}
+
renderHeader() {
const { table } = this.props;
return (
@@ -228,6 +231,7 @@ class TableElement extends React.PureComponent {
);
}
+
renderBody() {
const { table } = this.props;
let cols;
diff --git a/superset-frontend/src/SqlLab/components/TemplateParamsEditor.jsx b/superset-frontend/src/SqlLab/components/TemplateParamsEditor.jsx
index 85ea0cebf..75b317fe5 100644
--- a/superset-frontend/src/SqlLab/components/TemplateParamsEditor.jsx
+++ b/superset-frontend/src/SqlLab/components/TemplateParamsEditor.jsx
@@ -56,9 +56,11 @@ export default class TemplateParamsEditor extends React.Component {
};
this.onChange = this.onChange.bind(this);
}
+
componentDidMount() {
this.onChange(this.state.codeText);
}
+
onChange(value) {
const codeText = value;
let isValid;
@@ -75,6 +77,7 @@ export default class TemplateParamsEditor extends React.Component {
this.props.onChange(newValue);
}
}
+
renderDoc() {
return (
@@ -96,6 +99,7 @@ export default class TemplateParamsEditor extends React.Component {
);
}
+
renderModalBody() {
return (
@@ -115,6 +119,7 @@ export default class TemplateParamsEditor extends React.Component {
);
}
+
render() {
const paramCount = this.state.parsedJSON
? Object.keys(this.state.parsedJSON).length
diff --git a/superset-frontend/src/components/FilterableTable/FilterableTable.tsx b/superset-frontend/src/components/FilterableTable/FilterableTable.tsx
index c58b4c12a..2df936f81 100644
--- a/superset-frontend/src/components/FilterableTable/FilterableTable.tsx
+++ b/superset-frontend/src/components/FilterableTable/FilterableTable.tsx
@@ -124,10 +124,15 @@ export default class FilterableTable extends PureComponent<
};
list: List;
+
complexColumns: Record;
+
widthsForColumnsByKey: Record;
+
totalTableWidth: number;
+
totalTableHeight: number;
+
container: React.RefObject;
constructor(props: FilterableTableProps) {
diff --git a/superset-frontend/src/components/FlashProvider.tsx b/superset-frontend/src/components/FlashProvider.tsx
index 5504288e8..5ecbc3279 100644
--- a/superset-frontend/src/components/FlashProvider.tsx
+++ b/superset-frontend/src/components/FlashProvider.tsx
@@ -48,6 +48,7 @@ class FlashProvider extends React.PureComponent {
}
});
}
+
render() {
return this.props.children;
}
diff --git a/superset-frontend/src/components/Hotkeys.jsx b/superset-frontend/src/components/Hotkeys.jsx
index 52d5e4dc3..c0d4707bf 100644
--- a/superset-frontend/src/components/Hotkeys.jsx
+++ b/superset-frontend/src/components/Hotkeys.jsx
@@ -45,6 +45,7 @@ export default class Hotkeys extends React.PureComponent {
}
});
}
+
renderPopover() {
const { header, hotkeys } = this.props;
return (
@@ -70,6 +71,7 @@ export default class Hotkeys extends React.PureComponent {
);
}
+
render() {
return (
({ showModal: true }));
}
+
renderModal() {
return (
{
static Next = Next;
+
static Prev = Prev;
+
static Item = Item;
+
static Ellipsis = Ellipsis;
+
render() {
return {this.props.children};
}
diff --git a/superset-frontend/src/dashboard/components/BuilderComponentPane.jsx b/superset-frontend/src/dashboard/components/BuilderComponentPane.jsx
index c697cdad2..0c9086f70 100644
--- a/superset-frontend/src/dashboard/components/BuilderComponentPane.jsx
+++ b/superset-frontend/src/dashboard/components/BuilderComponentPane.jsx
@@ -64,6 +64,7 @@ class BuilderComponentPane extends React.PureComponent {
);
}
+
render() {
const { topOffset } = this.props;
return (
diff --git a/superset-frontend/src/dashboard/components/ColorSchemeControlWrapper.jsx b/superset-frontend/src/dashboard/components/ColorSchemeControlWrapper.jsx
index 89d8e4d95..b2e14d103 100644
--- a/superset-frontend/src/dashboard/components/ColorSchemeControlWrapper.jsx
+++ b/superset-frontend/src/dashboard/components/ColorSchemeControlWrapper.jsx
@@ -41,6 +41,7 @@ class ColorSchemeControlWrapper extends React.PureComponent {
this.choices = this.categoricalSchemeRegistry.keys().map(s => [s, s]);
this.schemes = this.categoricalSchemeRegistry.getMap();
}
+
setHover(hovered) {
this.setState({ hovered });
}
diff --git a/superset-frontend/src/dashboard/components/PropertiesModal.jsx b/superset-frontend/src/dashboard/components/PropertiesModal.jsx
index 838aac0e8..fe4ed2e7e 100644
--- a/superset-frontend/src/dashboard/components/PropertiesModal.jsx
+++ b/superset-frontend/src/dashboard/components/PropertiesModal.jsx
@@ -80,6 +80,7 @@ class PropertiesModal extends React.PureComponent {
componentDidMount() {
this.fetchDashboardDetails();
}
+
onColorSchemeChange(value) {
this.updateFormState('colorScheme', value);
}
diff --git a/superset-frontend/src/datasource/DatasourceEditor.jsx b/superset-frontend/src/datasource/DatasourceEditor.jsx
index b76370e7e..ce85ef725 100644
--- a/superset-frontend/src/datasource/DatasourceEditor.jsx
+++ b/superset-frontend/src/datasource/DatasourceEditor.jsx
@@ -280,6 +280,7 @@ export class DatasourceEditor extends React.PureComponent {
};
this.props.onChange(datasource, this.state.errors);
}
+
onDatasourceChange(datasource) {
this.setState({ datasource }, this.validateAndChange);
}
diff --git a/superset-frontend/src/explore/components/Control.jsx b/superset-frontend/src/explore/components/Control.jsx
index 1683b6ae0..68f0e656f 100644
--- a/superset-frontend/src/explore/components/Control.jsx
+++ b/superset-frontend/src/explore/components/Control.jsx
@@ -68,12 +68,15 @@ export default class Control extends React.PureComponent {
this.onMouseEnter = this.setHover.bind(this, true);
this.onMouseLeave = this.setHover.bind(this, false);
}
+
onChange(value, errors) {
this.props.actions.setControlValue(this.props.name, value, errors);
}
+
setHover(hovered) {
this.setState({ hovered });
}
+
render() {
const { type, hidden } = this.props;
if (!type) return null;
diff --git a/superset-frontend/src/explore/components/ControlHeader.jsx b/superset-frontend/src/explore/components/ControlHeader.jsx
index 579a47ba3..7bc6a3a2e 100644
--- a/superset-frontend/src/explore/components/ControlHeader.jsx
+++ b/superset-frontend/src/explore/components/ControlHeader.jsx
@@ -75,6 +75,7 @@ export default class ControlHeader extends React.Component {
}
return null;
}
+
render() {
if (!this.props.label) {
return null;
diff --git a/superset-frontend/src/explore/components/ControlPanelSection.jsx b/superset-frontend/src/explore/components/ControlPanelSection.jsx
index c4ea64447..9913b7803 100644
--- a/superset-frontend/src/explore/components/ControlPanelSection.jsx
+++ b/superset-frontend/src/explore/components/ControlPanelSection.jsx
@@ -42,9 +42,11 @@ export default class ControlPanelSection extends React.Component {
this.state = { expanded: this.props.startExpanded };
this.toggleExpand = this.toggleExpand.bind(this);
}
+
toggleExpand() {
this.setState({ expanded: !this.state.expanded });
}
+
renderHeader() {
const { label, description, hasErrors } = this.props;
return (
diff --git a/superset-frontend/src/explore/components/DisplayQueryButton.jsx b/superset-frontend/src/explore/components/DisplayQueryButton.jsx
index 720026115..cc0ba2f87 100644
--- a/superset-frontend/src/explore/components/DisplayQueryButton.jsx
+++ b/superset-frontend/src/explore/components/DisplayQueryButton.jsx
@@ -90,6 +90,7 @@ export class DisplayQueryButton extends React.PureComponent {
this.openPropertiesModal = this.openPropertiesModal.bind(this);
this.closePropertiesModal = this.closePropertiesModal.bind(this);
}
+
beforeOpen(resultType) {
this.setState({ isLoading: true });
@@ -118,18 +119,23 @@ export class DisplayQueryButton extends React.PureComponent {
});
});
}
+
changeFilterText(event) {
this.setState({ filterText: event.target.value });
}
+
redirectSQLLab() {
this.props.onOpenInEditor(this.props.latestQueryFormData);
}
+
openPropertiesModal() {
this.setState({ isPropertiesModalOpen: true });
}
+
closePropertiesModal() {
this.setState({ isPropertiesModalOpen: false });
}
+
renderQueryModalBody() {
if (this.state.isLoading) {
return ;
@@ -157,6 +163,7 @@ export class DisplayQueryButton extends React.PureComponent {
}
return null;
}
+
renderResultsModalBody() {
if (this.state.isLoading) {
return ;
@@ -172,6 +179,7 @@ export class DisplayQueryButton extends React.PureComponent {
}
return null;
}
+
renderDataTable(data) {
return (
@@ -213,6 +221,7 @@ export class DisplayQueryButton extends React.PureComponent {
);
}
+
renderSamplesModalBody() {
if (this.state.isLoading) {
return ;
@@ -225,6 +234,7 @@ export class DisplayQueryButton extends React.PureComponent {
}
return null;
}
+
render() {
const { animation, chartHeight, slice } = this.props;
return (
diff --git a/superset-frontend/src/explore/components/EmbedCodeButton.jsx b/superset-frontend/src/explore/components/EmbedCodeButton.jsx
index 0c7083e96..b28c32546 100644
--- a/superset-frontend/src/explore/components/EmbedCodeButton.jsx
+++ b/superset-frontend/src/explore/components/EmbedCodeButton.jsx
@@ -144,6 +144,7 @@ export default class EmbedCodeButton extends React.Component {
);
}
+
render() {
return (
ctrls[k].validationErrors && ctrls[k].validationErrors.length > 0,
);
}
+
renderErrorMessage() {
// Returns an error message as a node if any errors are in the store
const errors = [];
@@ -311,6 +313,7 @@ class ExploreViewContainer extends React.Component {
}
return errorMessage;
}
+
renderChartContainer() {
return (
{
const dashboardIds = this.props.dashboards.map(
@@ -72,18 +73,22 @@ class SaveModal extends React.Component {
}
});
}
+
onSliceNameChange(event) {
this.setState({ newSliceName: event.target.value });
}
+
onDashboardSelectChange(event) {
const newDashboardName = event ? event.label : null;
const saveToDashboardId =
event && typeof event.value === 'number' ? event.value : null;
this.setState({ saveToDashboardId, newDashboardName });
}
+
changeAction(action) {
this.setState({ action });
}
+
saveOrOverwrite(gotodash) {
this.setState({ alert: null });
this.props.actions.removeSaveModalAlert();
@@ -117,12 +122,14 @@ class SaveModal extends React.Component {
});
this.props.onHide();
}
+
removeAlert() {
if (this.props.alert) {
this.props.actions.removeSaveModalAlert();
}
this.setState({ alert: null });
}
+
render() {
return (
diff --git a/superset-frontend/src/explore/components/controls/BoundsControl.jsx b/superset-frontend/src/explore/components/controls/BoundsControl.jsx
index 0815495b3..f52f43055 100644
--- a/superset-frontend/src/explore/components/controls/BoundsControl.jsx
+++ b/superset-frontend/src/explore/components/controls/BoundsControl.jsx
@@ -45,6 +45,7 @@ export default class BoundsControl extends React.Component {
this.onMinChange = this.onMinChange.bind(this);
this.onMaxChange = this.onMaxChange.bind(this);
}
+
onMinChange(event) {
this.setState(
{
@@ -53,6 +54,7 @@ export default class BoundsControl extends React.Component {
this.onChange,
);
}
+
onMaxChange(event) {
this.setState(
{
@@ -61,6 +63,7 @@ export default class BoundsControl extends React.Component {
this.onChange,
);
}
+
onChange() {
const mm = this.state.minMax;
const errors = [];
@@ -76,6 +79,7 @@ export default class BoundsControl extends React.Component {
this.props.onChange([null, null], errors);
}
}
+
render() {
return (
diff --git a/superset-frontend/src/explore/components/controls/CheckboxControl.jsx b/superset-frontend/src/explore/components/controls/CheckboxControl.jsx
index 3d53e53fa..5b14f0d52 100644
--- a/superset-frontend/src/explore/components/controls/CheckboxControl.jsx
+++ b/superset-frontend/src/explore/components/controls/CheckboxControl.jsx
@@ -38,6 +38,7 @@ export default class CheckboxControl extends React.Component {
onChange() {
this.props.onChange(!this.props.value);
}
+
renderCheckbox() {
return (
);
}
+
render() {
if (this.props.label) {
return (
diff --git a/superset-frontend/src/explore/components/controls/CollectionControl.jsx b/superset-frontend/src/explore/components/controls/CollectionControl.jsx
index 1c113ae9a..198df6d5c 100644
--- a/superset-frontend/src/explore/components/controls/CollectionControl.jsx
+++ b/superset-frontend/src/explore/components/controls/CollectionControl.jsx
@@ -68,19 +68,24 @@ export default class CollectionControl extends React.Component {
super(props);
this.onAdd = this.onAdd.bind(this);
}
+
onChange(i, value) {
Object.assign(this.props.value[i], value);
this.props.onChange(this.props.value);
}
+
onAdd() {
this.props.onChange(this.props.value.concat([this.props.itemGenerator()]));
}
+
onSortEnd({ oldIndex, newIndex }) {
this.props.onChange(arrayMove(this.props.value, oldIndex, newIndex));
}
+
removeItem(i) {
this.props.onChange(this.props.value.filter((o, ix) => i !== ix));
}
+
renderList() {
if (this.props.value.length === 0) {
return
{this.props.placeholder}
;
@@ -126,6 +131,7 @@ export default class CollectionControl extends React.Component {
);
}
+
render() {
return (
diff --git a/superset-frontend/src/explore/components/controls/ColorPickerControl.jsx b/superset-frontend/src/explore/components/controls/ColorPickerControl.jsx
index 54cf3b3b3..20641d816 100644
--- a/superset-frontend/src/explore/components/controls/ColorPickerControl.jsx
+++ b/superset-frontend/src/explore/components/controls/ColorPickerControl.jsx
@@ -69,9 +69,11 @@ export default class ColorPickerControl extends React.Component {
super(props);
this.onChange = this.onChange.bind(this);
}
+
onChange(col) {
this.props.onChange(col.rgb);
}
+
renderPopover() {
const presetColors = getCategoricalSchemeRegistry()
.get()
@@ -86,6 +88,7 @@ export default class ColorPickerControl extends React.Component {
);
}
+
render() {
const c = this.props.value || { r: 0, g: 0, b: 0, a: 0 };
const colStyle = {
diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl.jsx b/superset-frontend/src/explore/components/controls/DateFilterControl.jsx
index 285770bb3..9682b7561 100644
--- a/superset-frontend/src/explore/components/controls/DateFilterControl.jsx
+++ b/superset-frontend/src/explore/components/controls/DateFilterControl.jsx
@@ -238,11 +238,13 @@ class DateFilterControl extends React.Component {
componentWillUnmount() {
document.removeEventListener('click', this.handleClick);
}
+
onEnter(event) {
if (event.key === 'Enter') {
this.close();
}
}
+
setCustomRange(key, value) {
const updatedState = { ...this.state, [key]: value };
const combinedValue = [
@@ -252,6 +254,7 @@ class DateFilterControl extends React.Component {
].join(' ');
this.setState(getStateFromCustomRange(combinedValue));
}
+
setCustomStartEnd(key, value) {
const closeCalendar =
(key === 'since' && this.state.sinceViewMode === 'days') ||
@@ -265,9 +268,11 @@ class DateFilterControl extends React.Component {
untilViewMode: closeCalendar ? 'days' : this.state.untilViewMode,
});
}
+
setTypeCustomRange() {
this.setState({ type: TYPES.CUSTOM_RANGE });
}
+
setTypeCustomStartEnd() {
this.setState({ type: TYPES.CUSTOM_START_END });
}
@@ -325,18 +330,21 @@ class DateFilterControl extends React.Component {
this.refs.trigger.hide();
this.setState({ showSinceCalendar: false, showUntilCalendar: false });
}
+
isValidSince(date) {
return (
!isValidMoment(this.state.until) ||
date <= moment(this.state.until, MOMENT_FORMAT)
);
}
+
isValidUntil(date) {
return (
!isValidMoment(this.state.since) ||
date >= moment(this.state.since, MOMENT_FORMAT)
);
}
+
toggleCalendar(key) {
const nextState = {};
if (key === 'showSinceCalendar') {
@@ -352,6 +360,7 @@ class DateFilterControl extends React.Component {
}
this.setState(nextState);
}
+
renderInput(props, key) {
return (
@@ -372,6 +381,7 @@ class DateFilterControl extends React.Component {
);
}
+
renderPopover() {
const grainOptions = TIME_GRAIN_OPTIONS.map(grain => (