mirror of
https://github.com/apache/superset.git
synced 2024-09-06 22:07:34 -04:00
feat: support multiple time columns with time grain in Pivot Table v2 (#21537)
This commit is contained in:
parent
bbac67a2dc
commit
e671d80209
@ -45,6 +45,7 @@ import {
|
|||||||
ComparisionType,
|
ComparisionType,
|
||||||
isAdhocColumn,
|
isAdhocColumn,
|
||||||
isPhysicalColumn,
|
isPhysicalColumn,
|
||||||
|
ensureIsArray,
|
||||||
} from '@superset-ui/core';
|
} from '@superset-ui/core';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -57,7 +58,13 @@ import {
|
|||||||
DEFAULT_NUMBER_FORMAT,
|
DEFAULT_NUMBER_FORMAT,
|
||||||
} from '../utils';
|
} from '../utils';
|
||||||
import { TIME_FILTER_LABELS } from '../constants';
|
import { TIME_FILTER_LABELS } from '../constants';
|
||||||
import { SharedControlConfig, Dataset, ColumnMeta } from '../types';
|
import {
|
||||||
|
SharedControlConfig,
|
||||||
|
Dataset,
|
||||||
|
ColumnMeta,
|
||||||
|
ControlState,
|
||||||
|
ControlPanelState,
|
||||||
|
} from '../types';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
dndAdhocFilterControl,
|
dndAdhocFilterControl,
|
||||||
@ -340,6 +347,16 @@ const show_empty_columns: SharedControlConfig<'CheckboxControl'> = {
|
|||||||
description: t('Show empty columns'),
|
description: t('Show empty columns'),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const datetime_columns_lookup: SharedControlConfig<'HiddenControl'> = {
|
||||||
|
type: 'HiddenControl',
|
||||||
|
initialValue: (control: ControlState, state: ControlPanelState) =>
|
||||||
|
Object.fromEntries(
|
||||||
|
ensureIsArray<Record<string, any>>(state?.datasource?.columns)
|
||||||
|
.filter(option => option.is_dttm)
|
||||||
|
.map(option => [option.column_name ?? option.name, option.is_dttm]),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
metrics: dndAdhocMetricsControl,
|
metrics: dndAdhocMetricsControl,
|
||||||
metric: dndAdhocMetricControl,
|
metric: dndAdhocMetricControl,
|
||||||
@ -376,4 +393,5 @@ export default {
|
|||||||
truncate_metric,
|
truncate_metric,
|
||||||
x_axis: dndXAxisControl,
|
x_axis: dndXAxisControl,
|
||||||
show_empty_columns,
|
show_empty_columns,
|
||||||
|
datetime_columns_lookup,
|
||||||
};
|
};
|
||||||
|
@ -32,7 +32,8 @@
|
|||||||
"@ant-design/icons": "^4.2.2",
|
"@ant-design/icons": "^4.2.2",
|
||||||
"react": "^16.13.1",
|
"react": "^16.13.1",
|
||||||
"react-dom": "^16.13.1",
|
"react-dom": "^16.13.1",
|
||||||
"prop-types": "*"
|
"prop-types": "*",
|
||||||
|
"lodash": "^4.17.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/types": "^7.13.12",
|
"@babel/types": "^7.13.12",
|
||||||
|
@ -16,9 +16,15 @@
|
|||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
import omit from 'lodash/omit';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
AdhocColumn,
|
||||||
buildQueryContext,
|
buildQueryContext,
|
||||||
ensureIsArray,
|
ensureIsArray,
|
||||||
|
FeatureFlag,
|
||||||
|
isFeatureEnabled,
|
||||||
|
isPhysicalColumn,
|
||||||
QueryFormColumn,
|
QueryFormColumn,
|
||||||
QueryFormOrderBy,
|
QueryFormOrderBy,
|
||||||
} from '@superset-ui/core';
|
} from '@superset-ui/core';
|
||||||
@ -27,10 +33,29 @@ import { PivotTableQueryFormData } from '../types';
|
|||||||
export default function buildQuery(formData: PivotTableQueryFormData) {
|
export default function buildQuery(formData: PivotTableQueryFormData) {
|
||||||
const { groupbyColumns = [], groupbyRows = [] } = formData;
|
const { groupbyColumns = [], groupbyRows = [] } = formData;
|
||||||
// TODO: add deduping of AdhocColumns
|
// TODO: add deduping of AdhocColumns
|
||||||
const groupbySet = new Set([
|
const columns = Array.from(
|
||||||
|
new Set([
|
||||||
...ensureIsArray<QueryFormColumn>(groupbyColumns),
|
...ensureIsArray<QueryFormColumn>(groupbyColumns),
|
||||||
...ensureIsArray<QueryFormColumn>(groupbyRows),
|
...ensureIsArray<QueryFormColumn>(groupbyRows),
|
||||||
]);
|
]),
|
||||||
|
).map(col => {
|
||||||
|
if (
|
||||||
|
isPhysicalColumn(col) &&
|
||||||
|
formData.time_grain_sqla &&
|
||||||
|
isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) &&
|
||||||
|
formData?.datetime_columns_lookup?.[col]
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
timeGrain: formData.time_grain_sqla,
|
||||||
|
columnType: 'BASE_AXIS',
|
||||||
|
sqlExpression: col,
|
||||||
|
label: col,
|
||||||
|
expressionType: 'SQL',
|
||||||
|
} as AdhocColumn;
|
||||||
|
}
|
||||||
|
return col;
|
||||||
|
});
|
||||||
|
|
||||||
return buildQueryContext(formData, baseQueryObject => {
|
return buildQueryContext(formData, baseQueryObject => {
|
||||||
const { series_limit_metric, metrics, order_desc } = baseQueryObject;
|
const { series_limit_metric, metrics, order_desc } = baseQueryObject;
|
||||||
let orderBy: QueryFormOrderBy[] | undefined;
|
let orderBy: QueryFormOrderBy[] | undefined;
|
||||||
@ -41,9 +66,11 @@ export default function buildQuery(formData: PivotTableQueryFormData) {
|
|||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
...baseQueryObject,
|
...(isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
|
||||||
|
? omit(baseQueryObject, ['extras.time_grain_sqla'])
|
||||||
|
: baseQueryObject),
|
||||||
orderby: orderBy,
|
orderby: orderBy,
|
||||||
columns: [...groupbySet],
|
columns,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
@ -19,6 +19,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {
|
import {
|
||||||
ensureIsArray,
|
ensureIsArray,
|
||||||
|
FeatureFlag,
|
||||||
|
isAdhocColumn,
|
||||||
|
isFeatureEnabled,
|
||||||
|
isPhysicalColumn,
|
||||||
QueryFormMetric,
|
QueryFormMetric,
|
||||||
smartDateFormatter,
|
smartDateFormatter,
|
||||||
t,
|
t,
|
||||||
@ -38,7 +42,7 @@ import { MetricsLayoutEnum } from '../types';
|
|||||||
|
|
||||||
const config: ControlPanelConfig = {
|
const config: ControlPanelConfig = {
|
||||||
controlPanelSections: [
|
controlPanelSections: [
|
||||||
{ ...sections.legacyTimeseriesTime, expanded: false },
|
{ ...sections.genericTime, expanded: false },
|
||||||
{
|
{
|
||||||
label: t('Query'),
|
label: t('Query'),
|
||||||
expanded: true,
|
expanded: true,
|
||||||
@ -63,6 +67,41 @@ const config: ControlPanelConfig = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
|
||||||
|
? {
|
||||||
|
name: 'time_grain_sqla',
|
||||||
|
config: {
|
||||||
|
...sharedControls.time_grain_sqla,
|
||||||
|
visibility: ({ controls }) => {
|
||||||
|
const dttmLookup = Object.fromEntries(
|
||||||
|
ensureIsArray(controls?.groupbyColumns?.options).map(
|
||||||
|
option => [option.column_name, option.is_dttm],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return [
|
||||||
|
...ensureIsArray(controls?.groupbyColumns.value),
|
||||||
|
...ensureIsArray(controls?.groupbyRows.value),
|
||||||
|
]
|
||||||
|
.map(selection => {
|
||||||
|
if (isAdhocColumn(selection)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (isPhysicalColumn(selection)) {
|
||||||
|
return !!dttmLookup[selection];
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
.some(Boolean);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
|
||||||
|
? 'datetime_columns_lookup'
|
||||||
|
: null,
|
||||||
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
name: 'metrics',
|
name: 'metrics',
|
||||||
|
Loading…
Reference in New Issue
Block a user