You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by yj...@apache.org on 2020/09/18 16:06:22 UTC
[incubator-superset] branch master updated: ESLint:
no-restricted-syntax (#10889)
This is an automated email from the ASF dual-hosted git repository.
yjc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git
The following commit(s) were added to refs/heads/master by this push:
new ccfd293 ESLint: no-restricted-syntax (#10889)
ccfd293 is described below
commit ccfd293227105ae1a5a24999a3b75e3db724273b
Author: Kamil Gabryjelski <ka...@gmail.com>
AuthorDate: Fri Sep 18 18:05:57 2020 +0200
ESLint: no-restricted-syntax (#10889)
* Enable no-restricted syntax rule
* Fix webpack.config.js
* Remove unused function from utils/common.js
* Refactor triple nested for loop
* Fix loops in src/explore components
* Fix loops in SqlLab components
* Fix loops in AlteredSliceTag
* Fix loops in FilterableTable
* Add fixtures and uinit tests for findControlItem
* Add license
---
superset-frontend/.eslintrc.js | 2 -
.../spec/javascripts/explore/controlUtils_spec.jsx | 132 +++++++--------------
.../spec/javascripts/explore/fixtures.jsx | 104 ++++++++++++++++
.../src/SqlLab/components/TabbedSqlEditors.jsx | 9 +-
.../src/SqlLab/components/TableElement.jsx | 7 +-
superset-frontend/src/SqlLab/reducers/sqlLab.js | 5 +-
.../src/components/AlteredSliceTag.jsx | 18 ++-
.../components/FilterableTable/FilterableTable.tsx | 22 ++--
.../explore/components/ExploreViewContainer.jsx | 26 ++--
.../explore/components/controls/SelectControl.jsx | 4 +-
superset-frontend/src/explore/controlUtils.js | 29 ++---
superset-frontend/src/utils/common.js | 8 --
superset-frontend/webpack.config.js | 9 +-
13 files changed, 206 insertions(+), 169 deletions(-)
diff --git a/superset-frontend/.eslintrc.js b/superset-frontend/.eslintrc.js
index 0a3b7aa..95c687d 100644
--- a/superset-frontend/.eslintrc.js
+++ b/superset-frontend/.eslintrc.js
@@ -101,7 +101,6 @@ module.exports = {
'no-multi-spaces': 0,
'no-prototype-builtins': 0,
'no-restricted-properties': 0,
- 'no-restricted-syntax': 0,
'no-restricted-imports': [
'error',
{
@@ -215,7 +214,6 @@ module.exports = {
'no-multi-spaces': 0,
'no-prototype-builtins': 0,
'no-restricted-properties': 0,
- 'no-restricted-syntax': 0,
'no-restricted-imports': [
'error',
{
diff --git a/superset-frontend/spec/javascripts/explore/controlUtils_spec.jsx b/superset-frontend/spec/javascripts/explore/controlUtils_spec.jsx
index 02c683f..e52f70d 100644
--- a/superset-frontend/spec/javascripts/explore/controlUtils_spec.jsx
+++ b/superset-frontend/spec/javascripts/explore/controlUtils_spec.jsx
@@ -17,19 +17,20 @@
* under the License.
*/
-import React from 'react';
-import {
- getChartControlPanelRegistry,
- ColumnOption,
- t,
-} from '@superset-ui/core';
+import { getChartControlPanelRegistry, t } from '@superset-ui/core';
import {
getControlConfig,
getControlState,
getFormDataFromControls,
applyMapStateToPropsToControl,
getAllControlsState,
+ findControlItem,
} from 'src/explore/controlUtils';
+import {
+ controlPanelSectionsChartOptions,
+ controlPanelSectionsChartOptionsOnlyColorScheme,
+ controlPanelSectionsChartOptionsTable,
+} from 'spec/javascripts/explore/fixtures';
describe('controlUtils', () => {
const state = {
@@ -43,56 +44,10 @@ describe('controlUtils', () => {
beforeAll(() => {
getChartControlPanelRegistry()
.registerValue('test-chart', {
- controlPanelSections: [
- {
- label: t('Chart Options'),
- expanded: true,
- controlSetRows: [
- [
- 'color_scheme',
- {
- name: 'rose_area_proportion',
- config: {
- type: 'CheckboxControl',
- label: t('Use Area Proportions'),
- description: t(
- 'Check if the Rose Chart should use segment area instead of ' +
- 'segment radius for proportioning',
- ),
- default: false,
- renderTrigger: true,
- },
- },
- ],
- [
- {
- name: 'stacked_style',
- config: {
- type: 'SelectControl',
- label: t('Stacked Style'),
- renderTrigger: true,
- choices: [
- ['stack', 'stack'],
- ['stream', 'stream'],
- ['expand', 'expand'],
- ],
- default: 'stack',
- description: '',
- },
- },
- ],
- ],
- },
- ],
+ controlPanelSections: controlPanelSectionsChartOptions,
})
.registerValue('test-chart-override', {
- controlPanelSections: [
- {
- label: t('Chart Options'),
- expanded: true,
- controlSetRows: [['color_scheme']],
- },
- ],
+ controlPanelSections: controlPanelSectionsChartOptionsOnlyColorScheme,
controlOverrides: {
color_scheme: {
label: t('My beautiful colors'),
@@ -100,40 +55,7 @@ describe('controlUtils', () => {
},
})
.registerValue('table', {
- controlPanelSections: [
- {
- label: t('Chart Options'),
- expanded: true,
- controlSetRows: [
- [
- 'metric',
- 'metrics',
- {
- name: 'all_columns',
- config: {
- type: 'SelectControl',
- queryField: 'columns',
- multi: true,
- label: t('Columns'),
- default: [],
- description: t('Columns to display'),
- optionRenderer: c => <ColumnOption column={c} showType />,
- valueRenderer: c => <ColumnOption column={c} />,
- valueKey: 'column_name',
- allowAll: true,
- mapStateToProps: stateRef => ({
- options: stateRef.datasource
- ? stateRef.datasource.columns
- : [],
- }),
- commaChoosesOption: false,
- freeForm: true,
- },
- },
- ],
- ],
- },
- ],
+ controlPanelSections: controlPanelSectionsChartOptionsTable,
});
});
@@ -287,4 +209,38 @@ describe('controlUtils', () => {
});
});
});
+
+ describe('findControlItem', () => {
+ it('find control as a string', () => {
+ const controlItem = findControlItem(
+ controlPanelSectionsChartOptions,
+ 'color_scheme',
+ );
+ expect(controlItem).toEqual('color_scheme');
+ });
+
+ it('find control as a control object', () => {
+ let controlItem = findControlItem(
+ controlPanelSectionsChartOptions,
+ 'rose_area_proportion',
+ );
+ expect(controlItem.name).toEqual('rose_area_proportion');
+ expect(controlItem).toHaveProperty('config');
+
+ controlItem = findControlItem(
+ controlPanelSectionsChartOptions,
+ 'stacked_style',
+ );
+ expect(controlItem.name).toEqual('stacked_style');
+ expect(controlItem).toHaveProperty('config');
+ });
+
+ it('returns null when key is not found', () => {
+ const controlItem = findControlItem(
+ controlPanelSectionsChartOptions,
+ 'non_existing_key',
+ );
+ expect(controlItem).toBeNull();
+ });
+ });
});
diff --git a/superset-frontend/spec/javascripts/explore/fixtures.jsx b/superset-frontend/spec/javascripts/explore/fixtures.jsx
new file mode 100644
index 0000000..a434085
--- /dev/null
+++ b/superset-frontend/spec/javascripts/explore/fixtures.jsx
@@ -0,0 +1,104 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import React from 'react';
+import { ColumnOption, t } from '@superset-ui/core';
+
+export const controlPanelSectionsChartOptions = [
+ {
+ label: t('Chart Options'),
+ expanded: true,
+ controlSetRows: [
+ [
+ 'color_scheme',
+ {
+ name: 'rose_area_proportion',
+ config: {
+ type: 'CheckboxControl',
+ label: t('Use Area Proportions'),
+ description: t(
+ 'Check if the Rose Chart should use segment area instead of ' +
+ 'segment radius for proportioning',
+ ),
+ default: false,
+ renderTrigger: true,
+ },
+ },
+ ],
+ [
+ {
+ name: 'stacked_style',
+ config: {
+ type: 'SelectControl',
+ label: t('Stacked Style'),
+ renderTrigger: true,
+ choices: [
+ ['stack', 'stack'],
+ ['stream', 'stream'],
+ ['expand', 'expand'],
+ ],
+ default: 'stack',
+ description: '',
+ },
+ },
+ ],
+ ],
+ },
+];
+
+export const controlPanelSectionsChartOptionsOnlyColorScheme = [
+ {
+ label: t('Chart Options'),
+ expanded: true,
+ controlSetRows: [['color_scheme']],
+ },
+];
+
+export const controlPanelSectionsChartOptionsTable = [
+ {
+ label: t('Chart Options'),
+ expanded: true,
+ controlSetRows: [
+ [
+ 'metric',
+ 'metrics',
+ {
+ name: 'all_columns',
+ config: {
+ type: 'SelectControl',
+ queryField: 'columns',
+ multi: true,
+ label: t('Columns'),
+ default: [],
+ description: t('Columns to display'),
+ optionRenderer: c => <ColumnOption column={c} showType />,
+ valueRenderer: c => <ColumnOption column={c} />,
+ valueKey: 'column_name',
+ allowAll: true,
+ mapStateToProps: stateRef => ({
+ options: stateRef.datasource ? stateRef.datasource.columns : [],
+ }),
+ commaChoosesOption: false,
+ freeForm: true,
+ },
+ },
+ ],
+ ],
+ },
+];
diff --git a/superset-frontend/src/SqlLab/components/TabbedSqlEditors.jsx b/superset-frontend/src/SqlLab/components/TabbedSqlEditors.jsx
index b97d28d..3e07db3 100644
--- a/superset-frontend/src/SqlLab/components/TabbedSqlEditors.jsx
+++ b/superset-frontend/src/SqlLab/components/TabbedSqlEditors.jsx
@@ -173,12 +173,9 @@ class TabbedSqlEditors extends React.PureComponent {
UNSAFE_componentWillReceiveProps(nextProps) {
const nextActiveQeId =
nextProps.tabHistory[nextProps.tabHistory.length - 1];
- const queriesArray = [];
- for (const id in nextProps.queries) {
- if (nextProps.queries[id].sqlEditorId === nextActiveQeId) {
- queriesArray.push(nextProps.queries[id]);
- }
- }
+ const queriesArray = Object.values(nextProps.queries).filter(
+ query => query.sqlEditorId === nextActiveQeId,
+ );
if (!areArraysShallowEqual(queriesArray, this.state.queriesArray)) {
this.setState({ queriesArray });
}
diff --git a/superset-frontend/src/SqlLab/components/TableElement.jsx b/superset-frontend/src/SqlLab/components/TableElement.jsx
index c65afd4..f6bbabf 100644
--- a/superset-frontend/src/SqlLab/components/TableElement.jsx
+++ b/superset-frontend/src/SqlLab/components/TableElement.jsx
@@ -110,10 +110,9 @@ class TableElement extends React.PureComponent {
/>
);
}
- let latest = [];
- for (const k in table.partitions.latest) {
- latest.push(`${k}=${table.partitions.latest[k]}`);
- }
+ let latest = Object.entries(table.partitions.latest).map(
+ ([key, value]) => `${key}=${value}`,
+ );
latest = latest.join('/');
header = (
<Well bsSize="small">
diff --git a/superset-frontend/src/SqlLab/reducers/sqlLab.js b/superset-frontend/src/SqlLab/reducers/sqlLab.js
index a64a8b0..97f3267 100644
--- a/superset-frontend/src/SqlLab/reducers/sqlLab.js
+++ b/superset-frontend/src/SqlLab/reducers/sqlLab.js
@@ -493,8 +493,7 @@ export default function sqlLabReducer(state = {}, action) {
// Fetch the updates to the queries present in the store.
let change = false;
let { queriesLastUpdate } = state;
- for (const id in action.alteredQueries) {
- const changedQuery = action.alteredQueries[id];
+ Object.entries(action.alteredQueries).forEach(([id, changedQuery]) => {
if (
!state.queries.hasOwnProperty(id) ||
(state.queries[id].state !== 'stopped' &&
@@ -506,7 +505,7 @@ export default function sqlLabReducer(state = {}, action) {
newQueries[id] = { ...state.queries[id], ...changedQuery };
change = true;
}
- }
+ });
if (!change) {
newQueries = state.queries;
}
diff --git a/superset-frontend/src/components/AlteredSliceTag.jsx b/superset-frontend/src/components/AlteredSliceTag.jsx
index ace9694..34244e2 100644
--- a/superset-frontend/src/components/AlteredSliceTag.jsx
+++ b/superset-frontend/src/components/AlteredSliceTag.jsx
@@ -76,19 +76,17 @@ export default class AlteredSliceTag extends React.Component {
const fdKeys = Object.keys(cfd);
const diffs = {};
- for (const fdKey of fdKeys) {
- // Ignore values that are undefined/nonexisting in either
+ fdKeys.forEach(fdKey => {
if (!ofd[fdKey] && !cfd[fdKey]) {
- continue;
+ return;
}
- // Ignore obsolete legacy filters
if (['filters', 'having', 'having_filters', 'where'].includes(fdKey)) {
- continue;
+ return;
}
if (!this.isEqualish(ofd[fdKey], cfd[fdKey])) {
diffs[fdKey] = { before: ofd[fdKey], after: cfd[fdKey] };
}
- }
+ });
return diffs;
}
@@ -149,7 +147,7 @@ export default class AlteredSliceTag extends React.Component {
renderRows() {
const { diffs } = this.state;
const rows = [];
- for (const key in diffs) {
+ Object.entries(diffs).forEach(([key, diff]) => {
rows.push(
<Tr key={key}>
<Td
@@ -160,11 +158,11 @@ export default class AlteredSliceTag extends React.Component {
key
}
/>
- <Td column="before">{this.formatValue(diffs[key].before, key)}</Td>
- <Td column="after">{this.formatValue(diffs[key].after, key)}</Td>
+ <Td column="before">{this.formatValue(diff.before, key)}</Td>
+ <Td column="after">{this.formatValue(diff.after, key)}</Td>
</Tr>,
);
- }
+ });
return rows;
}
diff --git a/superset-frontend/src/components/FilterableTable/FilterableTable.tsx b/superset-frontend/src/components/FilterableTable/FilterableTable.tsx
index 2df936f..047698a 100644
--- a/superset-frontend/src/components/FilterableTable/FilterableTable.tsx
+++ b/superset-frontend/src/components/FilterableTable/FilterableTable.tsx
@@ -26,11 +26,11 @@ import {
Grid,
ScrollSync,
SortDirection,
+ SortDirectionType,
SortIndicator,
Table,
- SortDirectionType,
} from 'react-virtualized';
-import { t, getMultipleTextDimensions } from '@superset-ui/core';
+import { getMultipleTextDimensions, t } from '@superset-ui/core';
import Button from '../Button';
import CopyToClipboard from '../CopyToClipboard';
@@ -241,24 +241,22 @@ export default class FilterableTable extends PureComponent<
}
formatTableData(data: Record<string, unknown>[]): Datum[] {
- const formattedData = data.map(row => {
+ return data.map(row => {
const newRow = {};
- for (const k in row) {
- const val = row[k];
+ Object.entries(row).forEach(([key, val]) => {
if (['string', 'number'].indexOf(typeof val) >= 0) {
- newRow[k] = val;
+ newRow[key] = val;
} else {
- newRow[k] = val === null ? null : JSONbig.stringify(val);
+ newRow[key] = val === null ? null : JSONbig.stringify(val);
}
- }
+ });
return newRow;
});
- return formattedData;
}
hasMatch(text: string, row: Datum) {
- const values = [];
- for (const key in row) {
+ const values: string[] = [];
+ Object.keys(row).forEach(key => {
if (row.hasOwnProperty(key)) {
const cellValue = row[key];
if (typeof cellValue === 'string') {
@@ -270,7 +268,7 @@ export default class FilterableTable extends PureComponent<
values.push(cellValue.toString());
}
}
- }
+ });
const lowerCaseText = text.toLowerCase();
return values.some(v => v.includes(lowerCaseText));
}
diff --git a/superset-frontend/src/explore/components/ExploreViewContainer.jsx b/superset-frontend/src/explore/components/ExploreViewContainer.jsx
index 2282401..7d6b6d1 100644
--- a/superset-frontend/src/explore/components/ExploreViewContainer.jsx
+++ b/superset-frontend/src/explore/components/ExploreViewContainer.jsx
@@ -293,20 +293,18 @@ class ExploreViewContainer extends React.Component {
renderErrorMessage() {
// Returns an error message as a node if any errors are in the store
- const errors = [];
- const ctrls = this.props.controls;
- for (const controlName in this.props.controls) {
- const control = this.props.controls[controlName];
- if (control.validationErrors && control.validationErrors.length > 0) {
- errors.push(
- <div key={controlName}>
- {t('Control labeled ')}
- <strong>{` "${control.label}" `}</strong>
- {control.validationErrors.join('. ')}
- </div>,
- );
- }
- }
+ const errors = Object.entries(this.props.controls)
+ .filter(
+ ([, control]) =>
+ control.validationErrors && control.validationErrors.length > 0,
+ )
+ .map(([key, control]) => (
+ <div key={key}>
+ {t('Control labeled ')}
+ <strong>{` "${control.label}" `}</strong>
+ {control.validationErrors.join('. ')}
+ </div>
+ ));
let errorMessage;
if (errors.length > 0) {
errorMessage = <div style={{ textAlign: 'left' }}>{errors}</div>;
diff --git a/superset-frontend/src/explore/components/controls/SelectControl.jsx b/superset-frontend/src/explore/components/controls/SelectControl.jsx
index 3182434..7ec6c69 100644
--- a/superset-frontend/src/explore/components/controls/SelectControl.jsx
+++ b/superset-frontend/src/explore/components/controls/SelectControl.jsx
@@ -103,7 +103,7 @@ export default class SelectControl extends React.PureComponent {
if (opt) {
if (this.props.multi) {
optionValue = [];
- for (const o of opt) {
+ opt.forEach(o => {
// select all options
if (o.meta === true) {
this.props.onChange(
@@ -114,7 +114,7 @@ export default class SelectControl extends React.PureComponent {
return;
}
optionValue.push(o[this.props.valueKey] || o);
- }
+ });
} else if (opt.meta === true) {
return;
} else {
diff --git a/superset-frontend/src/explore/controlUtils.js b/superset-frontend/src/explore/controlUtils.js
index a273fd4..c05e4de 100644
--- a/superset-frontend/src/explore/controlUtils.js
+++ b/superset-frontend/src/explore/controlUtils.js
@@ -51,22 +51,19 @@ export function validateControl(control, processedState) {
/**
* Find control item from control panel config.
*/
-function findControlItem(controlPanelSections, controlKey) {
- for (const section of controlPanelSections) {
- for (const controlArr of section.controlSetRows) {
- for (const control of controlArr) {
- if (controlKey === control) return control;
- if (
- control !== null &&
- typeof control === 'object' &&
- control.name === controlKey
- ) {
- return control;
- }
- }
- }
- }
- return null;
+export function findControlItem(controlPanelSections, controlKey) {
+ return (
+ controlPanelSections
+ .map(section => section.controlSetRows)
+ .flat(2)
+ .find(
+ control =>
+ controlKey === control ||
+ (control !== null &&
+ typeof control === 'object' &&
+ control.name === controlKey),
+ ) ?? null
+ );
}
export const getControlConfig = memoizeOne(function getControlConfig(
diff --git a/superset-frontend/src/utils/common.js b/superset-frontend/src/utils/common.js
index 39a023b..0333822 100644
--- a/superset-frontend/src/utils/common.js
+++ b/superset-frontend/src/utils/common.js
@@ -82,14 +82,6 @@ export function getShortUrl(longUrl) {
);
}
-export function supersetURL(rootUrl, getParams = {}) {
- const url = new URL(rootUrl, window.location.origin);
- for (const k in getParams) {
- url.searchParams.set(k, getParams[k]);
- }
- return url.href;
-}
-
export function optionLabel(opt) {
if (opt === null) {
return NULL_STRING;
diff --git a/superset-frontend/webpack.config.js b/superset-frontend/webpack.config.js
index 081b98f..51e7eb2 100644
--- a/superset-frontend/webpack.config.js
+++ b/superset-frontend/webpack.config.js
@@ -78,7 +78,7 @@ const plugins = [
// }
// }
const entryFiles = {};
- for (const [entry, chunks] of Object.entries(entrypoints)) {
+ Object.entries(entrypoints).forEach(([entry, chunks]) => {
entryFiles[entry] = {
css: chunks
.filter(x => x.endsWith('.css'))
@@ -87,7 +87,8 @@ const plugins = [
.filter(x => x.endsWith('.js'))
.map(x => path.join(output.publicPath, x)),
};
- }
+ });
+
return {
...seed,
entrypoints: entryFiles,
@@ -430,7 +431,7 @@ if (isDevMode) {
// find all the symlinked plugins and use their source code for imports
let hasSymlink = false;
- for (const [pkg, version] of Object.entries(packageConfig.dependencies)) {
+ Object.entries(packageConfig.dependencies).forEach(([pkg, version]) => {
const srcPath = `./node_modules/${pkg}/src`;
if (/superset-ui/.test(pkg) && fs.existsSync(srcPath)) {
console.log(
@@ -441,7 +442,7 @@ if (isDevMode) {
config.resolve.alias[`${pkg}$`] = `${pkg}/src`;
hasSymlink = true;
}
- }
+ });
if (hasSymlink) {
console.log(''); // pure cosmetic new line
}