mirror of
https://github.com/apache/superset.git
synced 2026-05-19 06:45:15 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f104a0c50 | ||
|
|
c03cfa6485 | ||
|
|
d0588f7668 | ||
|
|
2f19b12a22 | ||
|
|
dd3877a2d3 | ||
|
|
4be3fa218f |
23
CHANGELOG.md
23
CHANGELOG.md
@@ -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)
|
||||
|
||||
|
||||
3803
docs/static/resources/openapi.json
vendored
3803
docs/static/resources/openapi.json
vendored
File diff suppressed because it is too large
Load Diff
@@ -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';
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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');
|
||||
});
|
||||
@@ -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 },
|
||||
|
||||
@@ -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: '',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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({}));
|
||||
});
|
||||
|
||||
@@ -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)]);
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user