From 6aa10dc016455728c7da4dfabd849c59dc9f7f66 Mon Sep 17 00:00:00 2001 From: Daniel Vaz Gaspar Date: Wed, 28 Aug 2019 18:12:46 +0100 Subject: [PATCH 01/10] [setup] use new python requires metadata key (#8135) --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 8c074fc369d74..d4620d054b91d 100644 --- a/setup.py +++ b/setup.py @@ -112,6 +112,7 @@ def get_git_sha(): "presto": ["pyhive[presto]>=0.4.0"], "druid": ["pydruid==0.5.2", "requests==2.22.0"], }, + python_requires="~=3.6", author="Apache Software Foundation", author_email="dev@superset.incubator.apache.org", url="https://superset.apache.org/", From b150b3d5e6bb1340bd1802f96c106e2b51fd8cbb Mon Sep 17 00:00:00 2001 From: Krist Wongsuphasawat Date: Thu, 29 Aug 2019 15:19:05 -0700 Subject: [PATCH 02/10] remove unused files (#8140) --- superset/assets/src/query/Column.ts | 42 ------- superset/assets/src/query/DatasourceKey.ts | 47 ------- superset/assets/src/query/FormData.ts | 48 ------- superset/assets/src/query/Metric.ts | 118 ------------------ .../assets/src/query/buildQueryContext.ts | 33 ----- superset/assets/src/query/buildQueryObject.ts | 39 ------ superset/assets/src/query/index.ts | 21 ---- 7 files changed, 348 deletions(-) delete mode 100644 superset/assets/src/query/Column.ts delete mode 100644 superset/assets/src/query/DatasourceKey.ts delete mode 100644 superset/assets/src/query/FormData.ts delete mode 100644 superset/assets/src/query/Metric.ts delete mode 100644 superset/assets/src/query/buildQueryContext.ts delete mode 100644 superset/assets/src/query/buildQueryObject.ts delete mode 100644 superset/assets/src/query/index.ts diff --git a/superset/assets/src/query/Column.ts b/superset/assets/src/query/Column.ts deleted file mode 100644 index d627e94016524..0000000000000 --- a/superset/assets/src/query/Column.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -export enum ColumnType { - DOUBLE = 'DOUBLE', - FLOAT = 'FLOAT', - INT = 'INT', - BIGINT = 'BIGINT', - LONG = 'LONG', - REAL = 'REAL', - NUMERIC = 'NUMERIC', - DECIMAL = 'DECIMAL', - MONEY = 'MONEY', - DATE = 'DATE', - TIME = 'TIME', - DATETIME = 'DATETIME', - VARCHAR = 'VARCHAR', - STRING = 'STRING', - CHAR = 'CHAR', -} - -// TODO: fill out additional fields of the Column interface -export default interface Column { - id: number; - type: ColumnType; - columnName: string; -} diff --git a/superset/assets/src/query/DatasourceKey.ts b/superset/assets/src/query/DatasourceKey.ts deleted file mode 100644 index f0251f5b35d9c..0000000000000 --- a/superset/assets/src/query/DatasourceKey.ts +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -enum DatasourceType { - Table = 'table', - Druid = 'druid', -} - -export default interface DatasourceKey { - id: number; - type: DatasourceType; -} - -// Declaration merging with the interface above. No need to redeclare id and type. -export default class DatasourceKey { - constructor(key: string) { - const [ idStr, typeStr ] = key.split('__'); - this.id = parseInt(idStr, 10); - this.type = typeStr === 'table' ? DatasourceType.Table : DatasourceType.Druid; - } - - public toString() { - return `${this.id}__${this.type}`; - } - - public toObject() { - return { - id: this.id, - type: this.type, - }; - } -} diff --git a/superset/assets/src/query/FormData.ts b/superset/assets/src/query/FormData.ts deleted file mode 100644 index a282c6409b5f7..0000000000000 --- a/superset/assets/src/query/FormData.ts +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { AdhocMetric, MetricKey } from './Metric'; - -// Type signature and utility functions for formData shared by all viz types -// It will be gradually filled out as we build out the query object - -// Define mapped type separately to work around a limitation of TypeScript -// https://github.com/Microsoft/TypeScript/issues/13573 -// The Metrics in formData is either a string or a proper metric. It will be -// unified into a proper Metric type during buildQuery (see `/query/Metrics.ts`). -type Metrics = Partial>; - -type BaseFormData = { - datasource: string; -} & Metrics; - -// FormData is either sqla-based or druid-based -type SqlaFormData = { - granularity_sqla: string; -} & BaseFormData; - -type DruidFormData = { - granularity: string; -} & BaseFormData; - -type FormData = SqlaFormData | DruidFormData; -export default FormData; - -export function getGranularity(formData: FormData): string { - return 'granularity_sqla' in formData ? formData.granularity_sqla : formData.granularity; -} diff --git a/superset/assets/src/query/Metric.ts b/superset/assets/src/query/Metric.ts deleted file mode 100644 index 1ff6bccd8eaf4..0000000000000 --- a/superset/assets/src/query/Metric.ts +++ /dev/null @@ -1,118 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import Column from './Column'; -import FormData from './FormData'; - -export const LABEL_MAX_LENGTH = 43; - -// Note that the values of MetricKeys are lower_snake_case because they're -// used as keys of form data jsons. -export enum MetricKey { - METRIC = 'metric', - METRICS = 'metrics', - PERCENT_METRICS = 'percent_metrics', - RIGHT_AXIS_METRIC = 'metric_2', - SECONDARY_METRIC = 'secondary_metric', - X = 'x', - Y = 'y', - SIZE = 'size', -} - -export enum Aggregate { - AVG = 'AVG', - COUNT = 'COUNT ', - COUNT_DISTINCT = 'COUNT_DISTINCT', - MAX = 'MAX', - MIN = 'MIN', - SUM = 'SUM', -} - -export enum ExpressionType { - SIMPLE = 'SIMPLE', - SQL = 'SQL', -} - -interface AdhocMetricSimple { - expressionType: ExpressionType.SIMPLE; - column: Column; - aggregate: Aggregate; -} - -interface AdhocMetricSQL { - expressionType: ExpressionType.SQL; - sqlExpression: string; -} - -export type AdhocMetric = { - label?: string, - optionName?: string, -} & (AdhocMetricSimple | AdhocMetricSQL); - -type Metric = { - label: string; -} & Partial; - -export default Metric; - -export class Metrics { - // Use Array to maintain insertion order for metrics that are order sensitive - private metrics: Metric[]; - - constructor(formData: FormData) { - this.metrics = []; - for (const key of Object.keys(MetricKey)) { - const metric = formData[MetricKey[key] as MetricKey]; - if (metric) { - if (typeof metric === 'string') { - this.metrics.push({ - label: metric, - }); - } else { - // Note we further sanitize the metric label for BigQuery datasources - // TODO: move this logic to the client once client has more info on the - // the datasource - const label = metric.label || this.getDefaultLabel(metric); - this.metrics.push({ - ...metric, - label, - }); - } - } - } - } - - public getMetrics() { - return this.metrics; - } - - public getLabels() { - return this.metrics.map((m) => m.label); - } - - private getDefaultLabel(metric: AdhocMetric) { - let label: string; - if (metric.expressionType === ExpressionType.SIMPLE) { - label = `${metric.aggregate}(${(metric.column.columnName)})`; - } else { - label = metric.sqlExpression; - } - return label.length <= LABEL_MAX_LENGTH ? label : - `${label.substring(0, LABEL_MAX_LENGTH - 3)}...`; - } -} diff --git a/superset/assets/src/query/buildQueryContext.ts b/superset/assets/src/query/buildQueryContext.ts deleted file mode 100644 index f0f4c4f7c028a..0000000000000 --- a/superset/assets/src/query/buildQueryContext.ts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import buildQueryObject, { QueryObject } from './buildQueryObject'; -import DatasourceKey from './DatasourceKey'; -import FormData from './FormData'; - -const WRAP_IN_ARRAY = (baseQueryObject: QueryObject) => [baseQueryObject]; - -// Note: let TypeScript infer the return type -export default function buildQueryContext( - formData: FormData, - buildQuery: (baseQueryObject: QueryObject) => QueryObject[] = WRAP_IN_ARRAY) { - return { - datasource: new DatasourceKey(formData.datasource).toObject(), - queries: buildQuery(buildQueryObject(formData)), - }; -} diff --git a/superset/assets/src/query/buildQueryObject.ts b/superset/assets/src/query/buildQueryObject.ts deleted file mode 100644 index 8549955def1e1..0000000000000 --- a/superset/assets/src/query/buildQueryObject.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import FormData, { getGranularity } from './FormData'; -import Metric, { Metrics } from './Metric'; - -// TODO: fill out the rest of the query object -export interface QueryObject { - granularity: string; - groupby?: string[]; - metrics?: Metric[]; -} - -// Build the common segments of all query objects (e.g. the granularity field derived from -// either sql alchemy or druid). The segments specific to each viz type is constructed in the -// buildQuery method for each viz type (see `wordcloud/buildQuery.ts` for an example). -// Note the type of the formData argument passed in here is the type of the formData for a -// specific viz, which is a subtype of the generic formData shared among all viz types. -export default function buildQueryObject(formData: T): QueryObject { - return { - granularity: getGranularity(formData), - metrics: new Metrics(formData).getMetrics(), - }; -} diff --git a/superset/assets/src/query/index.ts b/superset/assets/src/query/index.ts deleted file mode 100644 index f9b4e1c5f34b5..0000000000000 --- a/superset/assets/src/query/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -// Public API of the query module -export { default } from './buildQueryContext'; -export { default as FormData } from './FormData'; From 149d6344acd421cede0ae03939c4c433379e727e Mon Sep 17 00:00:00 2001 From: Ville Brofeldt <33317356+villebro@users.noreply.github.com> Date: Fri, 30 Aug 2019 07:29:08 +0300 Subject: [PATCH 03/10] Add duration formatter for numeric data (#8136) * Add duration formatter * Remove sec and min formatters and add subMillisecond option --- superset/assets/src/explore/controls.jsx | 2 ++ superset/assets/src/setup/setupFormatters.js | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/superset/assets/src/explore/controls.jsx b/superset/assets/src/explore/controls.jsx index 449cccc06de8a..523a39037318c 100644 --- a/superset/assets/src/explore/controls.jsx +++ b/superset/assets/src/explore/controls.jsx @@ -88,6 +88,8 @@ const D3_FORMAT_OPTIONS = [ [',.3f', ',.3f (12345.432 => 12,345.432)'], ['+,', '+, (12345.432 => +12,345.432)'], ['$,.2f', '$,.2f (12345.432 => $12,345.43)'], + ['DURATION', 'Duration in ms (66000 => 1m 6s)'], + ['DURATION_SUB', 'Duration in ms (100.40008 => 100ms 400µs 80ns)'], ]; const ROW_LIMIT_OPTIONS = [10, 50, 100, 250, 500, 1000, 5000, 10000, 50000]; diff --git a/superset/assets/src/setup/setupFormatters.js b/superset/assets/src/setup/setupFormatters.js index 7d6bd2c6bfaeb..9972caeb3ed0a 100644 --- a/superset/assets/src/setup/setupFormatters.js +++ b/superset/assets/src/setup/setupFormatters.js @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { getNumberFormatter, getNumberFormatterRegistry, NumberFormats } from '@superset-ui/number-format'; +import { createDurationFormatter, getNumberFormatter, getNumberFormatterRegistry, NumberFormats } from '@superset-ui/number-format'; import { getTimeFormatterRegistry, smartDateFormatter, smartDateVerboseFormatter } from '@superset-ui/time-format'; export default function setupFormatters() { @@ -54,7 +54,9 @@ export default function setupFormatters() { .registerValue('.0%f', getNumberFormatter('.1%')) .registerValue('$,0', getNumberFormatter('$,.4f')) .registerValue('$,0f', getNumberFormatter('$,.4f')) - .registerValue('$,.f', getNumberFormatter('$,.4f')); + .registerValue('$,.f', getNumberFormatter('$,.4f')) + .registerValue('DURATION', createDurationFormatter()) + .registerValue('DURATION_SUB', createDurationFormatter({ formatSubMilliseconds: true })); getTimeFormatterRegistry() .registerValue('smart_date', smartDateFormatter) From 7f17ba7ee238516cd025031f31e39a1db8d89a9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CA=88=E1=B5=83=E1=B5=A2?= Date: Thu, 29 Aug 2019 21:29:34 -0700 Subject: [PATCH 04/10] removes unused state values and redundant presence checks (#8130) --- .../SqlLab/components/ScheduleQueryButton.jsx | 12 ++++++------ .../src/SqlLab/components/ShareSqlLabQuery.jsx | 10 ++++------ .../src/SqlLab/components/SqlEditorLeftBar.jsx | 18 +++++++----------- .../assets/src/components/ErrorBoundary.jsx | 11 +++++++---- .../components/gridComponents/Chart.jsx | 2 +- 5 files changed, 25 insertions(+), 28 deletions(-) diff --git a/superset/assets/src/SqlLab/components/ScheduleQueryButton.jsx b/superset/assets/src/SqlLab/components/ScheduleQueryButton.jsx index d8f82fba62428..09a7ddb3b22fb 100644 --- a/superset/assets/src/SqlLab/components/ScheduleQueryButton.jsx +++ b/superset/assets/src/SqlLab/components/ScheduleQueryButton.jsx @@ -125,8 +125,8 @@ class ScheduleQueryButton extends React.PureComponent { onDescriptionChange(e) { this.setState({ description: e.target.value }); } - toggleSchedule(e) { - this.setState({ target: e.target, showSchedule: !this.state.showSchedule }); + toggleSchedule() { + this.setState({ showSchedule: !this.state.showSchedule }); } renderModalBody() { return ( @@ -170,9 +170,7 @@ class ScheduleQueryButton extends React.PureComponent { {this.props.scheduleQueryWarning && ( - - {this.props.scheduleQueryWarning} - + {this.props.scheduleQueryWarning} )} @@ -183,7 +181,9 @@ class ScheduleQueryButton extends React.PureComponent { return ( { this.saveModal = ref; }} + ref={(ref) => { + this.saveModal = ref; + }} modalTitle={t('Schedule Query')} modalBody={this.renderModalBody()} triggerNode={ diff --git a/superset/assets/src/SqlLab/components/ShareSqlLabQuery.jsx b/superset/assets/src/SqlLab/components/ShareSqlLabQuery.jsx index dce572ecea926..176a4fc77dd1f 100644 --- a/superset/assets/src/SqlLab/components/ShareSqlLabQuery.jsx +++ b/superset/assets/src/SqlLab/components/ShareSqlLabQuery.jsx @@ -43,7 +43,6 @@ class ShareSqlLabQuery extends React.Component { super(props); this.state = { shortUrl: t('Loading ...'), - showOverlay: false, }; this.getCopyUrl = this.getCopyUrl.bind(this); } @@ -57,11 +56,10 @@ class ShareSqlLabQuery extends React.Component { this.setState({ shortUrl }); }) .catch((response) => { - getClientErrorObject(response) - .then(({ error }) => { - this.props.addDangerToast(error); - this.setState({ shortUrl: t('Error') }); - }); + getClientErrorObject(response).then(({ error }) => { + this.props.addDangerToast(error); + this.setState({ shortUrl: t('Error') }); + }); }); } diff --git a/superset/assets/src/SqlLab/components/SqlEditorLeftBar.jsx b/superset/assets/src/SqlLab/components/SqlEditorLeftBar.jsx index bc61f83de73f9..bf7afff727bc1 100644 --- a/superset/assets/src/SqlLab/components/SqlEditorLeftBar.jsx +++ b/superset/assets/src/SqlLab/components/SqlEditorLeftBar.jsx @@ -42,12 +42,6 @@ const defaultProps = { export default class SqlEditorLeftBar extends React.PureComponent { constructor(props) { super(props); - this.state = { - schemaLoading: false, - schemaOptions: [], - tableLoading: false, - tableOptions: [], - }; this.resetState = this.resetState.bind(this); this.onSchemaChange = this.onSchemaChange.bind(this); this.onSchemasLoad = this.onSchemasLoad.bind(this); @@ -76,7 +70,10 @@ export default class SqlEditorLeftBar extends React.PureComponent { } dbMutator(data) { - const options = data.result.map(db => ({ value: db.id, label: db.database_name })); + const options = data.result.map(db => ({ + value: db.id, + label: db.database_name, + })); this.props.actions.setDatabases(data.result); if (data.result.length === 0) { this.props.actions.addDangerToast(t("It seems you don't have access to any database")); @@ -89,12 +86,10 @@ export default class SqlEditorLeftBar extends React.PureComponent { } changeTable(tableOpt) { if (!tableOpt) { - this.setState({ tableName: '' }); return; } const schemaName = tableOpt.value.schema; const tableName = tableOpt.value.table; - this.setState({ tableName }); this.props.actions.queryEditorSetSchema(this.props.queryEditor, schemaName); this.props.actions.addTable(this.props.queryEditor, tableName, schemaName); } @@ -129,10 +124,11 @@ export default class SqlEditorLeftBar extends React.PureComponent { ))} - {shouldShowReset && + {shouldShowReset && ( } + + )} ); } diff --git a/superset/assets/src/components/ErrorBoundary.jsx b/superset/assets/src/components/ErrorBoundary.jsx index 0f1605a027e23..926109486e465 100644 --- a/superset/assets/src/components/ErrorBoundary.jsx +++ b/superset/assets/src/components/ErrorBoundary.jsx @@ -45,14 +45,17 @@ export default class ErrorBoundary extends React.Component { render() { const { error, info } = this.state; if (error) { - const firstLine = error ? error.toString() : null; + const firstLine = error.toString(); const message = ( - {t('Unexpected error')}{firstLine ? `: ${firstLine}` : ''} - ); + {t('Unexpected error')} + {firstLine ? `: ${firstLine}` : ''} + + ); if (this.props.showMessage) { return ( - ); + + ); } return null; } diff --git a/superset/assets/src/dashboard/components/gridComponents/Chart.jsx b/superset/assets/src/dashboard/components/gridComponents/Chart.jsx index 61412f3e308fa..330910bd2ce6a 100644 --- a/superset/assets/src/dashboard/components/gridComponents/Chart.jsx +++ b/superset/assets/src/dashboard/components/gridComponents/Chart.jsx @@ -225,7 +225,7 @@ class Chart extends React.Component { const { queryResponse, chartUpdateEndTime } = chart; const isCached = queryResponse && queryResponse.is_cached; const cachedDttm = queryResponse && queryResponse.cached_dttm; - const isOverflowable = OVERFLOWABLE_VIZ_TYPES.has(slice && slice.viz_type); + const isOverflowable = OVERFLOWABLE_VIZ_TYPES.has(slice.viz_type); return (
From 1b031fc7d770f3f2044f6b99527d958789eec2c3 Mon Sep 17 00:00:00 2001 From: Erik Ritter Date: Fri, 30 Aug 2019 14:11:46 -0700 Subject: [PATCH 05/10] Revert "Fixed Histogram visualization bug. (#8077)" (#8145) This reverts commit 7ac1a290eb013418091a58e92958971348f290e3. --- superset/viz.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/superset/viz.py b/superset/viz.py index 192c8fb5de02c..68d343ee8ca0e 100644 --- a/superset/viz.py +++ b/superset/viz.py @@ -1475,22 +1475,18 @@ def query_obj(self): numeric_columns = self.form_data.get("all_columns_x") if numeric_columns is None: raise Exception(_("Must have at least one numeric column specified")) - self.columns = [numeric_columns] - d["columns"] = [numeric_columns] + self.groupby + self.columns = numeric_columns + d["columns"] = numeric_columns + self.groupby # override groupby entry to avoid aggregation d["groupby"] = [] return d def labelify(self, keys, column): - if isinstance(keys, str) or isinstance(keys, int): + if isinstance(keys, str): keys = (keys,) - # removing undesirable characters - labels = [ - re.sub(r"\W+", r"_", k) if isinstance(k, str) else str(k) for k in keys - ] - - if len(self.columns) > 0 or not self.groupby: + labels = [re.sub(r"\W+", r"_", k) for k in keys] + if len(self.columns) > 1 or not self.groupby: # Only show numeric column in label if there are many labels = [column] + labels return "__".join(labels) From 96eb51f0e1ce1a66b12d760a7e0b6d39664ecab5 Mon Sep 17 00:00:00 2001 From: Erik Ritter Date: Fri, 30 Aug 2019 15:19:01 -0700 Subject: [PATCH 06/10] Revert "Allow resizing width of SQL Lab left bar / editor (#8099)" (#8146) This reverts commit ed3360b13510c95aca7b7ddd98681f965f13f76f. --- superset/assets/package-lock.json | 7 --- .../javascripts/sqllab/SqlEditor_spec.jsx | 12 ++-- .../src/SqlLab/components/SqlEditor.jsx | 60 +++++++------------ superset/assets/src/SqlLab/constants.js | 5 +- superset/assets/src/SqlLab/main.less | 33 ++++------ 5 files changed, 43 insertions(+), 74 deletions(-) diff --git a/superset/assets/package-lock.json b/superset/assets/package-lock.json index dbd47f09108e9..1df1124e2444b 100644 --- a/superset/assets/package-lock.json +++ b/superset/assets/package-lock.json @@ -3581,13 +3581,6 @@ "requires": { "@babel/runtime": "^7.1.2", "whatwg-fetch": "^3.0.0" - }, - "dependencies": { - "whatwg-fetch": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", - "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==" - } } }, "@superset-ui/core": { diff --git a/superset/assets/spec/javascripts/sqllab/SqlEditor_spec.jsx b/superset/assets/spec/javascripts/sqllab/SqlEditor_spec.jsx index 861ddaed971f4..dcf2609e885db 100644 --- a/superset/assets/spec/javascripts/sqllab/SqlEditor_spec.jsx +++ b/superset/assets/spec/javascripts/sqllab/SqlEditor_spec.jsx @@ -21,8 +21,8 @@ import { shallow } from 'enzyme'; import { defaultQueryEditor, initialState, queries, table } from './fixtures'; import { - SQL_EDITOR_VERTICAL_GUTTER_HEIGHT, - SQL_EDITOR_VERTICAL_GUTTER_MARGIN, + SQL_EDITOR_GUTTER_HEIGHT, + SQL_EDITOR_GUTTER_MARGIN, SQL_TOOLBAR_HEIGHT, } from '../../../src/SqlLab/constants'; import AceEditorWrapper from '../../../src/SqlLab/components/AceEditorWrapper'; @@ -73,8 +73,8 @@ describe('SqlEditor', () => { const totalSize = parseFloat(wrapper.find(AceEditorWrapper).props().height) + wrapper.find(SouthPane).props().height + SQL_TOOLBAR_HEIGHT - + (SQL_EDITOR_VERTICAL_GUTTER_MARGIN * 2) - + SQL_EDITOR_VERTICAL_GUTTER_HEIGHT; + + (SQL_EDITOR_GUTTER_MARGIN * 2) + + SQL_EDITOR_GUTTER_HEIGHT; expect(totalSize).toEqual(MOCKED_SQL_EDITOR_HEIGHT); }); it('does not overflow the editor window after resizing', () => { @@ -83,8 +83,8 @@ describe('SqlEditor', () => { const totalSize = parseFloat(wrapper.find(AceEditorWrapper).props().height) + wrapper.find(SouthPane).props().height + SQL_TOOLBAR_HEIGHT - + (SQL_EDITOR_VERTICAL_GUTTER_MARGIN * 2) - + SQL_EDITOR_VERTICAL_GUTTER_HEIGHT; + + (SQL_EDITOR_GUTTER_MARGIN * 2) + + SQL_EDITOR_GUTTER_HEIGHT; expect(totalSize).toEqual(450); }); it('render a LimitControl with default limit', () => { diff --git a/superset/assets/src/SqlLab/components/SqlEditor.jsx b/superset/assets/src/SqlLab/components/SqlEditor.jsx index c2c81807da2e3..8524daaea6483 100644 --- a/superset/assets/src/SqlLab/components/SqlEditor.jsx +++ b/superset/assets/src/SqlLab/components/SqlEditor.jsx @@ -46,10 +46,9 @@ import SqlEditorLeftBar from './SqlEditorLeftBar'; import AceEditorWrapper from './AceEditorWrapper'; import { STATE_BSSTYLE_MAP, - SQL_EDITOR_VERTICAL_GUTTER_HEIGHT, - SQL_EDITOR_VERTICAL_GUTTER_MARGIN, + SQL_EDITOR_GUTTER_HEIGHT, + SQL_EDITOR_GUTTER_MARGIN, SQL_TOOLBAR_HEIGHT, - SQL_EDITOR_HORIZONTAL_GUTTER_WIDTH, } from '../constants'; import RunQueryActionButton from './RunQueryActionButton'; import { FeatureFlag, isFeatureEnabled } from '../../featureFlags'; @@ -57,11 +56,8 @@ import { FeatureFlag, isFeatureEnabled } from '../../featureFlags'; const SQL_EDITOR_PADDING = 10; const INITIAL_NORTH_PERCENT = 30; const INITIAL_SOUTH_PERCENT = 70; -const INITIAL_WEST_PERCENT = 20; -const INITIAL_EAST_PERCENT = 80; const VALIDATION_DEBOUNCE_MS = 600; const WINDOW_RESIZE_THROTTLE_MS = 100; -const SQL_EDITOR_MIN_SIZE = 300; const propTypes = { actions: PropTypes.object.isRequired, @@ -107,7 +103,6 @@ class SqlEditor extends React.PureComponent { this.onSqlChanged = this.onSqlChanged.bind(this); this.setQueryEditorSql = this.setQueryEditorSql.bind(this); this.queryPane = this.queryPane.bind(this); - this.leftBar = this.leftBar.bind(this); this.getAceEditorAndSouthPaneHeights = this.getAceEditorAndSouthPaneHeights.bind(this); this.getSqlEditorHeight = this.getSqlEditorHeight.bind(this); this.requestValidation = debounce( @@ -169,10 +164,10 @@ class SqlEditor extends React.PureComponent { getAceEditorAndSouthPaneHeights(height, northPercent, southPercent) { return { aceEditorHeight: height * northPercent / 100 - - (SQL_EDITOR_VERTICAL_GUTTER_HEIGHT / 2 + SQL_EDITOR_VERTICAL_GUTTER_MARGIN) + - (SQL_EDITOR_GUTTER_HEIGHT / 2 + SQL_EDITOR_GUTTER_MARGIN) - SQL_TOOLBAR_HEIGHT, southPaneHeight: height * southPercent / 100 - - (SQL_EDITOR_VERTICAL_GUTTER_HEIGHT / 2 + SQL_EDITOR_VERTICAL_GUTTER_MARGIN), + - (SQL_EDITOR_GUTTER_HEIGHT / 2 + SQL_EDITOR_GUTTER_MARGIN), }; } getHotkeyConfig() { @@ -220,7 +215,7 @@ class SqlEditor extends React.PureComponent { } elementStyle(dimension, elementSize, gutterSize) { return { - [dimension]: `calc(${elementSize}% - ${gutterSize + SQL_EDITOR_VERTICAL_GUTTER_MARGIN}px)`, + [dimension]: `calc(${elementSize}% - ${gutterSize + SQL_EDITOR_GUTTER_MARGIN}px)`, }; } requestValidation() { @@ -292,7 +287,7 @@ class SqlEditor extends React.PureComponent { elementStyle={this.elementStyle} minSize={200} direction="vertical" - gutterSize={SQL_EDITOR_VERTICAL_GUTTER_HEIGHT} + gutterSize={SQL_EDITOR_GUTTER_HEIGHT} onDragStart={this.onResizeStart} onDragEnd={this.onResizeEnd} > @@ -321,22 +316,6 @@ class SqlEditor extends React.PureComponent { ); } - leftBar() { - return ( - - - - ); - } renderEditorBottomBar(hotkeys) { let ctasControls; if (this.props.database && this.props.database.allow_ctas) { @@ -476,18 +455,23 @@ class SqlEditor extends React.PureComponent { } render() { return ( - - {this.leftBar()} +
+ +
+ +
+
{this.queryPane()} - +
); } } diff --git a/superset/assets/src/SqlLab/constants.js b/superset/assets/src/SqlLab/constants.js index ce12611e2e392..c030ce2999783 100644 --- a/superset/assets/src/SqlLab/constants.js +++ b/superset/assets/src/SqlLab/constants.js @@ -45,10 +45,9 @@ export const TIME_OPTIONS = [ ]; // SqlEditor layout constants -export const SQL_EDITOR_VERTICAL_GUTTER_HEIGHT = 5; -export const SQL_EDITOR_VERTICAL_GUTTER_MARGIN = 3; +export const SQL_EDITOR_GUTTER_HEIGHT = 5; +export const SQL_EDITOR_GUTTER_MARGIN = 3; export const SQL_TOOLBAR_HEIGHT = 51; -export const SQL_EDITOR_HORIZONTAL_GUTTER_WIDTH = 5; // kilobyte storage export const KB_STORAGE = 1024; diff --git a/superset/assets/src/SqlLab/main.less b/superset/assets/src/SqlLab/main.less index 4df15bc6ceb43..2da95435bc559 100644 --- a/superset/assets/src/SqlLab/main.less +++ b/superset/assets/src/SqlLab/main.less @@ -229,7 +229,7 @@ div.Workspace { } } -.SqlEditor, .SqlEditor-expanded { +.SqlEditor { display: flex; flex-direction: row; height: 100%; @@ -241,11 +241,14 @@ div.Workspace { } .schemaPane { + flex: 0 0 300px; + max-width: 300px; transition: transform .3s ease-in-out; } .queryPane { flex: 1 1 auto; + padding-left: 10px; } .schemaPane-enter-done, .schemaPane-exit { @@ -270,29 +273,19 @@ div.Workspace { .schemaPane-exit-done + .queryPane { margin-left: 0; } -} - -.SqlEditor .gutter-horizontal { - border-left: 1px solid #ccc; - border-right: 1px solid #ccc; - height: 40px; - cursor: col-resize; - margin-right: 10px; -} -.SqlEditor-expanded .gutter-horizontal { - display: none; -} + .gutter { + border-top: 1px solid #ccc; + border-bottom: 1px solid #ccc; + width: 3%; + margin: 3px 47%; + } -.queryPane .gutter-vertical { - border-top: 1px solid #ccc; - border-bottom: 1px solid #ccc; - width: 3%; - margin: 3px 47%; - cursor: row-resize; + .gutter.gutter-vertical { + cursor: row-resize; + } } - .SqlEditorLeftBar { height: 100%; display: flex; From 96f21d3cb642ce7b2417d6b2b9ac24b433bc5947 Mon Sep 17 00:00:00 2001 From: Erik Ritter Date: Fri, 30 Aug 2019 15:25:37 -0700 Subject: [PATCH 07/10] Revert "Fix tooltips not visible for NVD3 charts on Firefox (#7822) (#7929)" (#8147) This reverts commit 6df2a713e4189dc19168cd7ace754451e9c38d01. --- superset/assets/stylesheets/less/index.less | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/superset/assets/stylesheets/less/index.less b/superset/assets/stylesheets/less/index.less index 680c134b59915..b1fc604323c0e 100644 --- a/superset/assets/stylesheets/less/index.less +++ b/superset/assets/stylesheets/less/index.less @@ -25,7 +25,11 @@ @stroke-primary: @brand-primary; body { - min-height: 100vh; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; display: flex; flex-direction: column; } From 2abec1908eb7edc52d181464ca339704650f93a2 Mon Sep 17 00:00:00 2001 From: Craig Rueda Date: Fri, 30 Aug 2019 15:43:30 -0700 Subject: [PATCH 08/10] Adding explicit include for version_info.json (#8148) --- MANIFEST.in | 1 + 1 file changed, 1 insertion(+) diff --git a/MANIFEST.in b/MANIFEST.in index 10872f48f5f7d..082b101f9ae6f 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -28,6 +28,7 @@ recursive-include superset/static/assets/dist * recursive-include superset/static/assets/images * recursive-exclude superset/static/images/viz_thumbnails_large * recursive-include superset/static/assets/stylesheets * +include superset/static/assets/version_info.json recursive-include superset/templates * recursive-include superset/translations * From 522e8015cf462def88d37aa300a560012c0770ce Mon Sep 17 00:00:00 2001 From: Maxim Sukharev Date: Mon, 2 Sep 2019 21:43:03 +0200 Subject: [PATCH 09/10] Forward SIGTERM signal to gunicorn (#8156) Currently docker entrypoint is a bash script. `docker stop` command (or restart in kubernetes) sends SIGTERM to the container but it isn't catched by gunicorn. So gunicorn can't start graceful shutdown which may lead to killing user's connection and also adds 10s (default value) delay for stopping until docker sends SIGKILL. Using `exec` replaces the shell with the process being opened and signals are propagated correctly. Ref: https://docs.docker.com/engine/reference/commandline/stop/ Ref: https://unix.stackexchange.com/questions/146756/forward-sigterm-to-child-in-bash --- contrib/docker/docker-entrypoint.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/docker/docker-entrypoint.sh b/contrib/docker/docker-entrypoint.sh index 474a5836b2604..03e4f96dc944a 100755 --- a/contrib/docker/docker-entrypoint.sh +++ b/contrib/docker/docker-entrypoint.sh @@ -27,7 +27,7 @@ elif [ "$SUPERSET_ENV" = "development" ]; then FLASK_ENV=development FLASK_APP=superset:app flask run -p 8088 --with-threads --reload --debugger --host=0.0.0.0 elif [ "$SUPERSET_ENV" = "production" ]; then celery worker --app=superset.sql_lab:celery_app --pool=gevent -Ofair & - gunicorn --bind 0.0.0.0:8088 \ + exec gunicorn --bind 0.0.0.0:8088 \ --workers $((2 * $(getconf _NPROCESSORS_ONLN) + 1)) \ --timeout 60 \ --limit-request-line 0 \ From ee24539bd2dc0c66a204015ebcb957a924a55452 Mon Sep 17 00:00:00 2001 From: Maxime Beauchemin Date: Mon, 2 Sep 2019 12:46:18 -0700 Subject: [PATCH 10/10] chore: remove PY3 conditional logic (#8149) --- superset/utils/core.py | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/superset/utils/core.py b/superset/utils/core.py index c341f0843ea8c..8e704551fad10 100644 --- a/superset/utils/core.py +++ b/superset/utils/core.py @@ -30,7 +30,6 @@ import os import signal import smtplib -import sys from time import struct_time import traceback from typing import List, NamedTuple, Optional, Tuple, Union @@ -68,7 +67,6 @@ logging.getLogger("MARKDOWN").setLevel(logging.INFO) -PY3K = sys.version_info >= (3, 0) DTTM_ALIAS = "__timestamp" ADHOC_METRIC_EXPRESSION_TYPES = {"SIMPLE": "SIMPLE", "SQL": "SQL"} @@ -796,10 +794,8 @@ def zlib_compress(data): >>> json_str = '{"test": 1}' >>> blob = zlib_compress(json_str) """ - if PY3K: - if isinstance(data, str): - return zlib.compress(bytes(data, "utf-8")) - return zlib.compress(data) + if isinstance(data, str): + return zlib.compress(bytes(data, "utf-8")) return zlib.compress(data) @@ -812,13 +808,11 @@ def zlib_decompress(blob: bytes, decode: Optional[bool] = True) -> Union[bytes, >>> got_str == json_str True """ - if PY3K: - if isinstance(blob, bytes): - decompressed = zlib.decompress(blob) - else: - decompressed = zlib.decompress(bytes(blob, "utf-8")) - return decompressed.decode("utf-8") if decode else decompressed - return zlib.decompress(blob) + if isinstance(blob, bytes): + decompressed = zlib.decompress(blob) + else: + decompressed = zlib.decompress(bytes(blob, "utf-8")) + return decompressed.decode("utf-8") if decode else decompressed _celery_app = None