From 0f29c03c3eb298a7103c19896f58096fd1ba0483 Mon Sep 17 00:00:00 2001 From: Gabe Lyons Date: Thu, 31 May 2018 21:00:20 -0700 Subject: [PATCH 1/5] adding null checks to adhoc filter popover (#5111) (cherry picked from commit 40fadfcb4f7decc364f3f875fcd5723d81145ad8) --- .../components/AdhocFilterEditPopoverSimpleTabContent.jsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/superset/assets/src/explore/components/AdhocFilterEditPopoverSimpleTabContent.jsx b/superset/assets/src/explore/components/AdhocFilterEditPopoverSimpleTabContent.jsx index b35da710128bd..36b7683cec75d 100644 --- a/superset/assets/src/explore/components/AdhocFilterEditPopoverSimpleTabContent.jsx +++ b/superset/assets/src/explore/components/AdhocFilterEditPopoverSimpleTabContent.jsx @@ -139,8 +139,10 @@ export default class AdhocFilterEditPopoverSimpleTabContent extends React.Compon handleMultiComparatorInputHeightChange() { if (this.multiComparatorComponent) { - // eslint-disable-next-line no-underscore-dangle - const multiComparatorDOMNode = this.multiComparatorComponent._selectRef.select.control; + /* eslint-disable no-underscore-dangle */ + const multiComparatorDOMNode = this.multiComparatorComponent._selectRef && + this.multiComparatorComponent._selectRef.select && + this.multiComparatorComponent._selectRef.select.control; if (multiComparatorDOMNode) { if (multiComparatorDOMNode.clientHeight !== this.state.multiComparatorHeight) { this.props.onHeightChange(( From 0b6c806dc0527d3ececa47b16375674164f8d87c Mon Sep 17 00:00:00 2001 From: michellethomas Date: Thu, 31 May 2018 13:53:26 -0700 Subject: [PATCH 2/5] Fixing time table viz for adhoc metrics (#5117) (cherry picked from commit ff4b103025841424495fdcdbed2b67a006746ecf) --- .../assets/src/components/MetricOption.jsx | 2 +- .../assets/src/visualizations/time_table.jsx | 20 ++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/superset/assets/src/components/MetricOption.jsx b/superset/assets/src/components/MetricOption.jsx index 81838f0d0a6ce..77596ea0aafa1 100644 --- a/superset/assets/src/components/MetricOption.jsx +++ b/superset/assets/src/components/MetricOption.jsx @@ -17,7 +17,7 @@ const defaultProps = { }; export default function MetricOption({ metric, openInNewWindow, showFormula, showType, url }) { - const verbose = metric.verbose_name || metric.metric_name; + const verbose = metric.verbose_name || metric.metric_name || metric.label; const link = url ? {verbose} : verbose; return (
diff --git a/superset/assets/src/visualizations/time_table.jsx b/superset/assets/src/visualizations/time_table.jsx index bcf2f0dca03cb..a00aa36b99c37 100644 --- a/superset/assets/src/visualizations/time_table.jsx +++ b/superset/assets/src/visualizations/time_table.jsx @@ -64,26 +64,28 @@ function viz(slice, payload) { let leftCell; const context = { ...fd, metric }; const url = fd.url ? Mustache.render(fd.url, context) : null; + const metricLabel = metric.label || metric; + const metricData = typeof metric === 'object' ? metric : metricMap[metric]; if (!payload.data.is_group_by) { leftCell = ( - + ); } else { - leftCell = url ? {metric} : metric; + leftCell = url ? {metricLabel} : metric; } const row = { metric: leftCell }; fd.column_collection.forEach((column) => { if (column.colType === 'spark') { let sparkData; if (!column.timeRatio) { - sparkData = data.map(d => d[metric]); + sparkData = data.map(d => d[metricLabel]); } else { // Period ratio sparkline sparkData = []; for (let i = column.timeRatio; i < data.length; i++) { - const prevData = data[i - column.timeRatio][metric]; + const prevData = data[i - column.timeRatio][metricLabel]; if (prevData && prevData !== 0) { - sparkData.push(data[i][metric] / prevData); + sparkData.push(data[i][metricLabel] / prevData); } else { sparkData.push(null); } @@ -105,7 +107,7 @@ function viz(slice, payload) { > {({ onMouseLeave, onMouseMove, tooltipData }) => ( totalLag) { errorMsg = `The time lag set at ${timeLag} exceeds the length of data at ${reversedData.length}. No data available.`; } else { - v = reversedData[timeLag][metric]; + v = reversedData[timeLag][metricLabel]; } if (column.comparisonType === 'diff') { v = recent - v; @@ -162,7 +164,7 @@ function viz(slice, payload) { } else if (column.colType === 'avg') { // Average over the last {timeLag} v = reversedData - .map((k, i) => i < column.timeLag ? k[metric] : 0) + .map((k, i) => i < column.timeLag ? k[metricLabel] : 0) .reduce((a, b) => a + b) / column.timeLag; } let color; From 5c6733445f2c0686fb4e028f2ba4ac494227dc83 Mon Sep 17 00:00:00 2001 From: John Bodley <4567245+john-bodley@users.noreply.github.com> Date: Tue, 5 Jun 2018 17:24:19 -0700 Subject: [PATCH 3/5] [crud] Improving performance (#5136) (cherry picked from commit f102eab33ce3a7246da267786ec07c391c6662d6) --- superset/connectors/sqla/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/superset/connectors/sqla/views.py b/superset/connectors/sqla/views.py index f0f5afb79f102..0be3cbf8c1d57 100644 --- a/superset/connectors/sqla/views.py +++ b/superset/connectors/sqla/views.py @@ -169,14 +169,14 @@ class TableModelView(DatasourceModelView, DeleteMixin, YamlExportMixin): # noqa order_columns = ['modified'] add_columns = ['database', 'schema', 'table_name'] edit_columns = [ - 'table_name', 'sql', 'filter_select_enabled', 'slices', + 'table_name', 'sql', 'filter_select_enabled', 'fetch_values_predicate', 'database', 'schema', 'description', 'owner', 'main_dttm_col', 'default_endpoint', 'offset', 'cache_timeout', 'is_sqllab_view', 'template_params', ] base_filters = [['id', DatasourceFilter, lambda: []]] - show_columns = edit_columns + ['perm'] + show_columns = edit_columns + ['perm', 'slices'] related_views = [TableColumnInlineView, SqlMetricInlineView] base_order = ('changed_on', 'desc') search_columns = ( From ff1de7a8c511a94c215ded13c4fd594263e8d3ed Mon Sep 17 00:00:00 2001 From: Gabe Lyons Date: Thu, 31 May 2018 11:34:51 -0700 Subject: [PATCH 4/5] fixing LIKE constant name (#5110) (cherry picked from commit f3778c3c81b1e9a04869708b8206daf7734a0fa7) --- .../AdhocFilterEditPopoverSimpleTabContent_spec.jsx | 4 ++-- superset/assets/src/explore/AdhocFilter.js | 2 +- .../components/AdhocFilterEditPopoverSimpleTabContent.jsx | 2 ++ superset/assets/src/explore/constants.js | 4 ++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/superset/assets/spec/javascripts/explore/components/AdhocFilterEditPopoverSimpleTabContent_spec.jsx b/superset/assets/spec/javascripts/explore/components/AdhocFilterEditPopoverSimpleTabContent_spec.jsx index 74ac96701e951..2014bbc7c9f3e 100644 --- a/superset/assets/spec/javascripts/explore/components/AdhocFilterEditPopoverSimpleTabContent_spec.jsx +++ b/superset/assets/spec/javascripts/explore/components/AdhocFilterEditPopoverSimpleTabContent_spec.jsx @@ -113,13 +113,13 @@ describe('AdhocFilterEditPopoverSimpleTabContent', () => { it('will filter operators for table datasources', () => { const { wrapper } = setup({ datasource: { type: 'table' } }); expect(wrapper.instance().isOperatorRelevant('regex')).to.be.false; - expect(wrapper.instance().isOperatorRelevant('like')).to.be.true; + expect(wrapper.instance().isOperatorRelevant('LIKE')).to.be.true; }); it('will filter operators for druid datasources', () => { const { wrapper } = setup({ datasource: { type: 'druid' } }); expect(wrapper.instance().isOperatorRelevant('regex')).to.be.true; - expect(wrapper.instance().isOperatorRelevant('like')).to.be.false; + expect(wrapper.instance().isOperatorRelevant('LIKE')).to.be.false; }); it('expands when its multi comparator input field expands', () => { diff --git a/superset/assets/src/explore/AdhocFilter.js b/superset/assets/src/explore/AdhocFilter.js index ba9651528c3d7..675cc27f613eb 100644 --- a/superset/assets/src/explore/AdhocFilter.js +++ b/superset/assets/src/explore/AdhocFilter.js @@ -19,7 +19,7 @@ const OPERATORS_TO_SQL = { '<=': '<=', in: 'in', 'not in': 'not in', - like: 'like', + LIKE: 'like', }; function translateToSql(adhocMetric, { useSimple } = {}) { diff --git a/superset/assets/src/explore/components/AdhocFilterEditPopoverSimpleTabContent.jsx b/superset/assets/src/explore/components/AdhocFilterEditPopoverSimpleTabContent.jsx index 36b7683cec75d..222772a464bf3 100644 --- a/superset/assets/src/explore/components/AdhocFilterEditPopoverSimpleTabContent.jsx +++ b/superset/assets/src/explore/components/AdhocFilterEditPopoverSimpleTabContent.jsx @@ -42,6 +42,8 @@ function translateOperator(operator) { return 'equals'; } else if (operator === OPERATORS['!=']) { return 'not equal to'; + } else if (operator === OPERATORS.LIKE) { + return 'like'; } return operator; } diff --git a/superset/assets/src/explore/constants.js b/superset/assets/src/explore/constants.js index d5dce01998f1d..39d70637829e4 100644 --- a/superset/assets/src/explore/constants.js +++ b/superset/assets/src/explore/constants.js @@ -16,11 +16,11 @@ export const OPERATORS = { '<=': '<=', in: 'in', 'not in': 'not in', - like: 'like', + LIKE: 'LIKE', regex: 'regex', }; -export const TABLE_ONLY_OPERATORS = [OPERATORS.like]; +export const TABLE_ONLY_OPERATORS = [OPERATORS.LIKE]; export const DRUID_ONLY_OPERATORS = [OPERATORS.regex]; export const HAVING_OPERATORS = [ OPERATORS['=='], From f43e460cda505124137c069c7df28a35b8f383aa Mon Sep 17 00:00:00 2001 From: John Bodley <4567245+john-bodley@users.noreply.github.com> Date: Wed, 6 Jun 2018 16:56:39 -0700 Subject: [PATCH 5/5] [migrations] Fix time grain SQLA (#5135) (cherry picked from commit 0545d11a2243e6982622288e9113620e1a203789) --- .../versions/c5756bec8b47_time_grain_sqla.py | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 superset/migrations/versions/c5756bec8b47_time_grain_sqla.py diff --git a/superset/migrations/versions/c5756bec8b47_time_grain_sqla.py b/superset/migrations/versions/c5756bec8b47_time_grain_sqla.py new file mode 100644 index 0000000000000..06ce632de31b9 --- /dev/null +++ b/superset/migrations/versions/c5756bec8b47_time_grain_sqla.py @@ -0,0 +1,65 @@ +"""Time grain SQLA + +Revision ID: c5756bec8b47 +Revises: e502db2af7be +Create Date: 2018-06-04 11:12:59.878742 + +""" + +# revision identifiers, used by Alembic. +revision = 'c5756bec8b47' +down_revision = 'e502db2af7be' + +from alembic import op +import json +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy import Column, Integer, String, Text + +from superset import db + +Base = declarative_base() + + +class Slice(Base): + __tablename__ = 'slices' + + id = Column(Integer, primary_key=True) + datasource_type = Column(String(200)) + slice_name = Column(String(250)) + params = Column(Text) + + +def upgrade(): + bind = op.get_bind() + session = db.Session(bind=bind) + + for slc in session.query(Slice).all(): + try: + params = json.loads(slc.params) + + if params.get('time_grain_sqla') == 'Time Column': + params['time_grain_sqla'] = None + slc.params = json.dumps(params, sort_keys=True) + except Exception: + pass + + session.commit() + session.close() + + +def downgrade(): + bind = op.get_bind() + session = db.Session(bind=bind) + + for slc in session.query(Slice).all(): + try: + params = json.loads(slc.params) + + if params.get('time_grain_sqla') is None: + params['time_grain_sqla'] = 'Time Column' + slc.params = json.dumps(params, sort_keys=True) + except Exception: + pass + + session.commit() + session.close()