Compare commits

...

6 Commits

Author SHA1 Message Date
Elizabeth Thompson
1f104a0c50 update changelog 2023-08-17 17:02:10 -07:00
Elizabeth Thompson
c03cfa6485 lint 2023-08-17 16:57:44 -07:00
Elizabeth Thompson
d0588f7668 fix: update permalink schema (#24970) 2023-08-17 16:57:44 -07:00
Elizabeth Thompson
2f19b12a22 fix: Revert "fix(chart): Time Series set showMaxLabel as null for time xAxis (#20627) (#24995) 2023-08-17 16:57:44 -07:00
Ville Brofeldt
dd3877a2d3 fix(sqllab): normalize changedOn timestamp (#24513) 2023-08-17 16:57:44 -07:00
Geido
4be3fa218f fix: Dashboard not loading with default first value in filter (#23512) 2023-08-17 16:57:44 -07:00
14 changed files with 3530 additions and 472 deletions

View File

@@ -19,7 +19,7 @@ under the License.
## Change Log
- [2.1.1](#211-sun-apr-23-154421-2023--0100)
- [2.1.1](#211-sun-apr-23-154421-2023-0100)
- [2.1.0](#210-thu-mar-16-211305-2023--0700)
- [2.0.1](#201-fri-nov-4-103402-2022--0400)
- [2.0.0](#200-tue-jun-28-085302-2022--0400)
@@ -34,14 +34,26 @@ under the License.
### 2.1.1 (Sun Apr 23 15:44:21 2023 +0100)
**Database Migrations**
- [##23980](https://github.com/apache/superset/pull/23980) fix(migration): handle permalink edge cases correctly (@villebro)
- [23888](https://github.com/apache/superset/pull/23888) chore(key-value): use json serialization for main resources (@villebro)
- [#23980](https://github.com/apache/superset/pull/23980) fix(migration): handle permalink edge cases correctly (@villebro)
- [#23888](https://github.com/apache/superset/pull/23888) chore(key-value): use json serialization for main resources (@villebro)
**Fixes**
- [#23723](https://github.com/apache/superset/pull/23723) fix: add enforce URI query params with a specific for MySQL (@dpgaspar)
- [#24970](https://github.com/apache/superset/pull/24970) fix: update permalink schema (@eschutho)
- [#24995](https://github.com/apache/superset/pull/24995) fix: Revert "fix(chart): Time Series set showMaxLabel as null for time xAxis (#20627) (@eschutho)
- [#24513](https://github.com/apache/superset/pull/24513) fix(sqllab): normalize changedOn timestamp (@villebro)
- [#23512](https://github.com/apache/superset/pull/23512) fix: Dashboard not loading with default first value in filter (@geido)
- [#24482](https://github.com/apache/superset/pull/24482) fix(permalink): Incorrect component schema reference (@Nisden)
- [#24166](https://github.com/apache/superset/pull/24166) fix(permalink): migrate to marshmallow codec (@villebro)
- [#24697](https://github.com/apache/superset/pull/24697) fix: import database engine validation (@dpgaspar)
- [#24390](https://github.com/apache/superset/pull/24390) fix: FAB CSS on Superset (@dpgaspar)
- [#24249](https://github.com/apache/superset/pull/24249) fix: dashboard ownership check (@betodealmeida)
- [#23801](https://github.com/apache/superset/pull/23801) fix(plugin-chart-handlebars): Fix TypeError when using handlebars columns raw mode (@fmannhardt)
- [#23566](https://github.com/apache/superset/pull/23566) fix: Filter values are not updating when dependencies are set (@michael-s-molina)
- [#23400](https://github.com/apache/superset/pull/23400) fix: Select all issue with "Dynamically search all filter values" in FilterBar (@geido)
- [#23865](https://github.com/apache/superset/pull/23865) fix: Native time range filter in legacy charts (@kgabryje)
- [#24054](https://github.com/apache/superset/pull/24054) fix: handle temporal columns in presto partitions (@giftig)
- [#23882](https://github.com/apache/superset/pull/23882) fix: handle comments in `has_table_query` (@betodealmeida)
- [#24256](https://github.com/apache/superset/pull/24256) fix: enable strong session protection by default (@dpgaspar)
- [#24137](https://github.com/apache/superset/pull/24137) fix: disable SHOW_STACKTRACE by default (@dpgaspar)
- [#24185](https://github.com/apache/superset/pull/24185) fix: db validate parameters permission (@dpgaspar)
- [#23769](https://github.com/apache/superset/pull/23769) fix: allow db driver distinction on enforced URI params (@dpgaspar)
@@ -58,7 +70,8 @@ under the License.
- [#22851](https://github.com/apache/superset/pull/22851) fix: Validate jinja rendered query (@geido)
**Others**
- [#23723](https://github.com/apache/superset/pull/23723) chore: add enforce URI query params with a specific for MySQL (@dpgaspar)
- [#24586](https://github.com/apache/superset/pull/24586) chore(metastore-cache): add codec support (@villebro)
- [#23113](https://github.com/apache/superset/pull/23113) chore(sqla): Address performance tradeoff with eager loading (@john-bodley)
- [#24294](https://github.com/apache/superset/pull/24294) chore: update UPDATING for 2.1.0 (@eschutho)
- [#24056](https://github.com/apache/superset/pull/24056) chore: Remove unnecessary information from response (@geido)

File diff suppressed because it is too large Load Diff

View File

@@ -36,4 +36,7 @@ export { default as smartDateFormatter } from './formatters/smartDate';
export { default as smartDateDetailedFormatter } from './formatters/smartDateDetailed';
export { default as smartDateVerboseFormatter } from './formatters/smartDateVerbose';
export { default as normalizeTimestamp } from './utils/normalizeTimestamp';
export { default as denormalizeTimestamp } from './utils/denormalizeTimestamp';
export * from './types';

View File

@@ -0,0 +1,28 @@
/*
* 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 { TS_REGEX } from './normalizeTimestamp';
export default function normalizeTimestamp(value: string): string {
const match = value.match(TS_REGEX);
if (match) {
return `${match[1]}T${match[2]}`;
}
return value;
}

View File

@@ -0,0 +1,28 @@
/*
* 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 const TS_REGEX = /(\d{4}-\d{2}-\d{2})[\sT](\d{2}:\d{2}:\d{2}\.?\d*).*/;
export default function normalizeTimestamp(value: string): string {
const match = value.match(TS_REGEX);
if (match) {
return `${match[1]}T${match[2]}Z`;
}
return value;
}

View File

@@ -0,0 +1,43 @@
/*
* 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 denormalizeTimestamp from '../../../src/time-format/utils/denormalizeTimestamp';
test('denormalizeTimestamp should normalize typical timestamps', () => {
expect(denormalizeTimestamp('2023-03-11 08:26:52.695 UTC')).toEqual(
'2023-03-11T08:26:52.695',
);
expect(
denormalizeTimestamp('2023-03-11 08:26:52.695 Europe/Helsinki'),
).toEqual('2023-03-11T08:26:52.695');
expect(denormalizeTimestamp('2023-03-11T08:26:52.695 UTC')).toEqual(
'2023-03-11T08:26:52.695',
);
expect(denormalizeTimestamp('2023-03-11T08:26:52.695')).toEqual(
'2023-03-11T08:26:52.695',
);
expect(denormalizeTimestamp('2023-03-11 08:26:52')).toEqual(
'2023-03-11T08:26:52',
);
});
test('denormalizeTimestamp should return unmatched timestamps as-is', () => {
expect(denormalizeTimestamp('abcd')).toEqual('abcd');
expect(denormalizeTimestamp('03/11/2023')).toEqual('03/11/2023');
});

View File

@@ -28,7 +28,6 @@ import {
isTimeseriesAnnotationLayer,
TimeseriesChartDataResponseResult,
t,
AxisType,
getXAxisLabel,
isPhysicalColumn,
isDefined,
@@ -339,23 +338,13 @@ export default function transformProps(
rotate: xAxisLabelRotation,
},
minInterval:
xAxisType === AxisType.time && timeGrainSqla
xAxisType === 'time' && timeGrainSqla
? TIMEGRAIN_TO_TIMESTAMP[timeGrainSqla]
: 0,
};
if (xAxisType === AxisType.time) {
/**
* Overriding default behavior (false) for time axis regardless of the granilarity.
* Not including this in the initial declaration above so if echarts changes the default
* behavior for other axist types we won't unintentionally override it
*/
xAxis.axisLabel.showMaxLabel = null;
}
let yAxis: any = {
...defaultYAxis,
type: logAxis ? AxisType.log : AxisType.value,
type: logAxis ? 'log' : 'value',
min,
max,
minorTick: { show: true },

View File

@@ -20,6 +20,8 @@
import { t, ChartMetadata } from '@superset-ui/core';
import thumbnail from './images/thumbnail.png';
export const TS_REGEX = /(\d{4}-\d{2}-\d{2})[\sT](\d{2}:\d{2}:\d{2}\.?\d*).*/;
export default function createMetadata(useLegacyApi = false) {
return new ChartMetadata({
description: '',

View File

@@ -24,6 +24,7 @@ import SouthPane from 'src/SqlLab/components/SouthPane';
import '@testing-library/jest-dom/extend-expect';
import { STATUS_OPTIONS } from 'src/SqlLab/constants';
import { initialState, table, defaultQueryEditor } from 'src/SqlLab/fixtures';
import { denormalizeTimestamp } from '@superset-ui/core';
const mockedProps = {
queryEditorId: defaultQueryEditor.id,
@@ -61,7 +62,7 @@ const store = mockStore({
queries: {
LCly_kkIN: {
cached: false,
changedOn: Date.now(),
changed_on: denormalizeTimestamp(new Date().toISOString()),
db: 'main',
dbId: 1,
id: 'LCly_kkIN',
@@ -71,7 +72,7 @@ const store = mockStore({
},
lXJa7F9_r: {
cached: false,
changedOn: 1559238500401,
changed_on: denormalizeTimestamp(new Date(1559238500401).toISOString()),
db: 'main',
dbId: 1,
id: 'lXJa7F9_r',
@@ -80,7 +81,7 @@ const store = mockStore({
},
'2g2_iRFMl': {
cached: false,
changedOn: 1559238506925,
changed_on: denormalizeTimestamp(new Date(1559238506925).toISOString()),
db: 'main',
dbId: 1,
id: '2g2_iRFMl',
@@ -89,7 +90,7 @@ const store = mockStore({
},
erWdqEWPm: {
cached: false,
changedOn: 1559238516395,
changed_on: denormalizeTimestamp(new Date(1559238516395).toISOString()),
db: 'main',
dbId: 1,
id: 'erWdqEWPm',

View File

@@ -19,7 +19,12 @@
import sinon from 'sinon';
import * as actions from 'src/SqlLab/actions/sqlLab';
import { ColumnKeyTypeType } from 'src/SqlLab/components/ColumnElement';
import { DatasourceType, QueryResponse, QueryState } from '@superset-ui/core';
import {
DatasourceType,
denormalizeTimestamp,
QueryResponse,
QueryState,
} from '@superset-ui/core';
import { ISaveableDatasource } from 'src/SqlLab/components/SaveDatasetModal';
export const mockedActions = sinon.stub({ ...actions });
@@ -721,7 +726,7 @@ export const mockdatasets = [...new Array(3)].map((_, i) => ({
kind: i === 0 ? 'virtual' : 'physical', // ensure there is 1 virtual
changed_by_url: 'changed_by_url',
changed_by: 'user',
changed_on: new Date().toISOString(),
changed_on: denormalizeTimestamp(new Date().toISOString()),
database_name: `db ${i}`,
explore_url: `/explore/?datasource_type=table&datasource_id=${i}`,
id: i,

View File

@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
import { QueryState, t } from '@superset-ui/core';
import { normalizeTimestamp, QueryState, t } from '@superset-ui/core';
import getInitialState from './getInitialState';
import * as actions from '../actions/sqlLab';
import { now } from '../../utils/dates';
@@ -729,8 +729,10 @@ export default function sqlLabReducer(state = {}, action) {
(state.queries[id].state !== QueryState.STOPPED &&
state.queries[id].state !== QueryState.FAILED)
) {
if (changedQuery.changedOn > queriesLastUpdate) {
queriesLastUpdate = changedQuery.changedOn;
const changedOn = normalizeTimestamp(changedQuery.changed_on);
const timestamp = Date.parse(changedOn);
if (timestamp > queriesLastUpdate) {
queriesLastUpdate = timestamp;
}
const prevState = state.queries[id]?.state;
const currentState = changedQuery.state;

View File

@@ -18,7 +18,6 @@
*/
import sqlLabReducer from 'src/SqlLab/reducers/sqlLab';
import * as actions from 'src/SqlLab/actions/sqlLab';
import { now } from 'src/utils/dates';
import { table, initialState as mockState } from '../fixtures';
const initialState = mockState.sqlLab;
@@ -272,6 +271,8 @@ describe('sqlLabReducer', () => {
});
});
describe('Run Query', () => {
const DENORMALIZED_CHANGED_ON = '2023-06-26T07:53:05.439';
const CHANGED_ON_TIMESTAMP = 1687765985439;
let newState;
let query;
beforeEach(() => {
@@ -279,7 +280,8 @@ describe('sqlLabReducer', () => {
query = {
id: 'abcd',
progress: 0,
startDttm: now(),
changed_on: DENORMALIZED_CHANGED_ON,
startDttm: CHANGED_ON_TIMESTAMP,
state: 'running',
cached: false,
sqlEditorId: 'dfsadfs',
@@ -291,7 +293,8 @@ describe('sqlLabReducer', () => {
query: {
id: 'abcd',
progress: 0,
startDttm: now(),
changed_on: DENORMALIZED_CHANGED_ON,
startDttm: CHANGED_ON_TIMESTAMP,
state: 'running',
cached: false,
sqlEditorId: 'dfsadfs',
@@ -327,6 +330,19 @@ describe('sqlLabReducer', () => {
newState = sqlLabReducer(newState, removeQueryAction);
expect(Object.keys(newState.queries)).toHaveLength(0);
});
it('should refresh queries when polling returns new results', () => {
newState = sqlLabReducer(
{
...newState,
queries: { abcd: {} },
},
actions.refreshQueries({
abcd: query,
}),
);
expect(newState.queries.abcd.changed_on).toBe(DENORMALIZED_CHANGED_ON);
expect(newState.queriesLastUpdate).toBe(CHANGED_ON_TIMESTAMP);
});
it('should refresh queries when polling returns empty', () => {
newState = sqlLabReducer(newState, actions.refreshQueries({}));
});

View File

@@ -128,7 +128,6 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) {
enableEmptyFilter && !inverseSelection && !values?.length;
const suffix = inverseSelection && values?.length ? t(' (excluded)') : '';
dispatchDataMask({
type: 'filterState',
__cache: filterState,
@@ -289,13 +288,9 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) {
updateDataMask,
data,
groupby,
JSON.stringify(filterState),
JSON.stringify(filterState.value),
]);
useEffect(() => {
updateDataMask(filterState.value);
}, [JSON.stringify(filterState.value)]);
useEffect(() => {
setDataMask(dataMask);
}, [JSON.stringify(dataMask)]);

View File

@@ -69,7 +69,7 @@ class ExplorePermalinkRestApi(BaseSupersetApi):
content:
application/json:
schema:
$ref: '#/components/schemas/ExplorePermalinkPostSchema'
$ref: '#/components/schemas/ExplorePermalinkStateSchema'
responses:
201:
description: The permanent link was stored successfully.