Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(explore): adhoc column expressions [ID-3] #17379

Merged
merged 48 commits into from
Nov 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
e7943e3
add support for adhoc columns to api and sqla model
villebro Sep 1, 2021
0da5b0b
fix some types
villebro Sep 2, 2021
1ad9e80
Merge branch 'master' into hack2020/adhoc-columns
villebro Sep 2, 2021
7368ed2
fix duplicates in column names
villebro Sep 2, 2021
e2b1d5d
fix more lint
villebro Sep 2, 2021
634ddbf
fix schema and dedup
villebro Sep 2, 2021
43ee0ed
clean up some logic
villebro Sep 3, 2021
71981bc
first pass at fixing viz.py
villebro Sep 3, 2021
ee38f54
Add frontend support for adhoc columns
kgabryje Sep 3, 2021
3c4d6be
Add title edit
kgabryje Sep 3, 2021
9bafd93
Fix showing custom title
kgabryje Sep 3, 2021
9215821
Use column name as default value in sql editor
kgabryje Sep 6, 2021
d5a655c
fix: Adds a loading message when needed in the Select component (#16531)
michael-s-molina Sep 2, 2021
661e499
fix(tests): make parquet select deterministic with order by (#16570)
villebro Sep 2, 2021
793c027
bump emotion to help with cache clobbering (#16559)
eschutho Sep 2, 2021
e7262bf
fix: Support Jinja template functions in global async queries (#16412)
robdiciuccio Sep 3, 2021
1acd0f4
fix: impersonate user label/tooltip (#16573)
betodealmeida Sep 3, 2021
14c025c
docs: update for small typos (#16568)
joeADSP Sep 3, 2021
d92ba0f
feat: Add Aurora Data API engine spec (#16535)
betodealmeida Sep 4, 2021
f007f05
refactor: sql_json view endpoint: encapsulate ctas parameters (#16548)
ofekisr Sep 5, 2021
f2c42f3
refactor sql_json view endpoint: separate concern into ad hod method …
ofekisr Sep 5, 2021
64043f2
feat: Experimental cross-filter plugins (#16594)
simcha90 Sep 6, 2021
ab4388e
chore(deps): bump superset-ui to 0.18.2 (#16601)
villebro Sep 6, 2021
f501b70
update type guard references
villebro Sep 6, 2021
470ad60
fix imports
villebro Sep 6, 2021
81f1527
Merge branch 'master' into hack2021/adhoc-columns
villebro Nov 8, 2021
ee3cc61
update series_columns schema
villebro Nov 8, 2021
b97da4e
Add changes that got lost in rebase
kgabryje Nov 9, 2021
837815c
Use current columns name or expression as sql editor init value
kgabryje Nov 10, 2021
bb9c7ec
add integration test and do minor fixes
villebro Nov 10, 2021
2bacbcf
Bump superset-ui
kgabryje Nov 10, 2021
2c5390b
Merge branch 'master' into hack2021/adhoc-columns
villebro Nov 10, 2021
50cece0
fix linting issue
villebro Nov 10, 2021
a1b076d
bump superset-ui to 0.18.22
villebro Nov 11, 2021
2aa84d0
Merge branch 'master' into hack2021/adhoc-columns
villebro Nov 11, 2021
c701d90
resolve merge conflict
villebro Nov 11, 2021
4245a78
lint
villebro Nov 11, 2021
7f25bdd
Merge branch 'master' into hack2021/adhoc-columns
villebro Nov 11, 2021
3861280
fix select filter infinite loop
villebro Nov 11, 2021
e290bfa
Merge branch 'master' into hack2021/adhoc-columns
villebro Nov 12, 2021
df8fb3c
bump superset-ui to 0.18.23
villebro Nov 12, 2021
916becb
Fix auto setting column popover title
kgabryje Nov 12, 2021
2631f7d
Enable adhoc columns only if UX_BETA enabled
kgabryje Nov 12, 2021
9dd2f75
put back removed test
villebro Nov 12, 2021
f0f87e2
Move popover height and width to constants
kgabryje Nov 12, 2021
7db4c1d
Refactor big ternary expression
kgabryje Nov 12, 2021
177ce6e
Merge branch 'master' into hack2021/adhoc-columns
villebro Nov 13, 2021
d426d2f
Merge branch 'master' into hack2021/adhoc-columns
villebro Nov 15, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
772 changes: 386 additions & 386 deletions superset-frontend/package-lock.json

Large diffs are not rendered by default.

56 changes: 28 additions & 28 deletions superset-frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,35 +68,35 @@
"@emotion/cache": "^11.4.0",
"@emotion/react": "^11.4.1",
"@emotion/styled": "^11.3.0",
"@superset-ui/chart-controls": "^0.18.20",
"@superset-ui/core": "^0.18.20",
"@superset-ui/legacy-plugin-chart-calendar": "^0.18.20",
"@superset-ui/legacy-plugin-chart-chord": "^0.18.20",
"@superset-ui/legacy-plugin-chart-country-map": "^0.18.20",
"@superset-ui/legacy-plugin-chart-event-flow": "^0.18.20",
"@superset-ui/legacy-plugin-chart-force-directed": "^0.18.20",
"@superset-ui/legacy-plugin-chart-heatmap": "^0.18.20",
"@superset-ui/legacy-plugin-chart-histogram": "^0.18.20",
"@superset-ui/legacy-plugin-chart-horizon": "^0.18.20",
"@superset-ui/legacy-plugin-chart-map-box": "^0.18.20",
"@superset-ui/legacy-plugin-chart-paired-t-test": "^0.18.20",
"@superset-ui/legacy-plugin-chart-parallel-coordinates": "^0.18.20",
"@superset-ui/legacy-plugin-chart-partition": "^0.18.20",
"@superset-ui/legacy-plugin-chart-pivot-table": "^0.18.20",
"@superset-ui/legacy-plugin-chart-rose": "^0.18.20",
"@superset-ui/legacy-plugin-chart-sankey": "^0.18.20",
"@superset-ui/legacy-plugin-chart-sankey-loop": "^0.18.20",
"@superset-ui/legacy-plugin-chart-sunburst": "^0.18.20",
"@superset-ui/legacy-plugin-chart-treemap": "^0.18.20",
"@superset-ui/legacy-plugin-chart-world-map": "^0.18.20",
"@superset-ui/legacy-preset-chart-big-number": "^0.18.20",
"@superset-ui/chart-controls": "^0.18.23",
"@superset-ui/core": "^0.18.23",
"@superset-ui/legacy-plugin-chart-calendar": "^0.18.23",
"@superset-ui/legacy-plugin-chart-chord": "^0.18.23",
"@superset-ui/legacy-plugin-chart-country-map": "^0.18.23",
"@superset-ui/legacy-plugin-chart-event-flow": "^0.18.23",
"@superset-ui/legacy-plugin-chart-force-directed": "^0.18.23",
"@superset-ui/legacy-plugin-chart-heatmap": "^0.18.23",
"@superset-ui/legacy-plugin-chart-histogram": "^0.18.23",
"@superset-ui/legacy-plugin-chart-horizon": "^0.18.23",
"@superset-ui/legacy-plugin-chart-map-box": "^0.18.23",
"@superset-ui/legacy-plugin-chart-paired-t-test": "^0.18.23",
"@superset-ui/legacy-plugin-chart-parallel-coordinates": "^0.18.23",
"@superset-ui/legacy-plugin-chart-partition": "^0.18.23",
"@superset-ui/legacy-plugin-chart-pivot-table": "^0.18.23",
"@superset-ui/legacy-plugin-chart-rose": "^0.18.23",
"@superset-ui/legacy-plugin-chart-sankey": "^0.18.23",
"@superset-ui/legacy-plugin-chart-sankey-loop": "^0.18.23",
"@superset-ui/legacy-plugin-chart-sunburst": "^0.18.23",
"@superset-ui/legacy-plugin-chart-treemap": "^0.18.23",
"@superset-ui/legacy-plugin-chart-world-map": "^0.18.23",
"@superset-ui/legacy-preset-chart-big-number": "^0.18.23",
"@superset-ui/legacy-preset-chart-deckgl": "^0.4.13",
"@superset-ui/legacy-preset-chart-nvd3": "^0.18.20",
"@superset-ui/plugin-chart-echarts": "^0.18.20",
"@superset-ui/plugin-chart-pivot-table": "^0.18.20",
"@superset-ui/plugin-chart-table": "^0.18.20",
"@superset-ui/plugin-chart-word-cloud": "^0.18.20",
"@superset-ui/preset-chart-xy": "^0.18.20",
"@superset-ui/legacy-preset-chart-nvd3": "^0.18.23",
"@superset-ui/plugin-chart-echarts": "^0.18.23",
"@superset-ui/plugin-chart-pivot-table": "^0.18.23",
"@superset-ui/plugin-chart-table": "^0.18.23",
"@superset-ui/plugin-chart-word-cloud": "^0.18.23",
"@superset-ui/preset-chart-xy": "^0.18.23",
"@vx/responsive": "^0.0.195",
"abortcontroller-polyfill": "^1.1.9",
"antd": "^4.9.4",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,27 @@
* under the License.
*/
/* eslint-disable camelcase */
import React, { useCallback, useMemo, useState } from 'react';
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import { AdhocColumn, t, styled, css } from '@superset-ui/core';
import {
ColumnMeta,
isAdhocColumn,
isSavedExpression,
} from '@superset-ui/chart-controls';
import Tabs from 'src/components/Tabs';
import Button from 'src/components/Button';
import { Select } from 'src/components';
import { t, styled } from '@superset-ui/core';

import { Form, FormItem } from 'src/components/Form';
import { SQLEditor } from 'src/components/AsyncAceEditor';
import { StyledColumnOption } from 'src/explore/components/optionRenderers';
import { ColumnMeta } from '@superset-ui/chart-controls';
import { POPOVER_INITIAL_HEIGHT } from 'src/explore/constants';

const StyledSelect = styled(Select)`
.metric-option {
Expand All @@ -41,29 +53,58 @@ const StyledSelect = styled(Select)`

interface ColumnSelectPopoverProps {
columns: ColumnMeta[];
editedColumn?: ColumnMeta;
onChange: (column: ColumnMeta) => void;
editedColumn?: ColumnMeta | AdhocColumn;
onChange: (column: ColumnMeta | AdhocColumn) => void;
onClose: () => void;
setLabel: (title: string) => void;
getCurrentTab: (tab: string) => void;
label: string;
isAdhocColumnsEnabled: boolean;
}

const getInitialColumnValues = (
editedColumn?: ColumnMeta | AdhocColumn,
): [AdhocColumn?, ColumnMeta?, ColumnMeta?] => {
if (!editedColumn) {
return [undefined, undefined, undefined];
}
if (isAdhocColumn(editedColumn)) {
return [editedColumn, undefined, undefined];
}
if (isSavedExpression(editedColumn)) {
return [undefined, editedColumn, undefined];
}
return [undefined, undefined, editedColumn];
};

const ColumnSelectPopover = ({
columns,
editedColumn,
onChange,
onClose,
setLabel,
getCurrentTab,
label,
isAdhocColumnsEnabled,
}: ColumnSelectPopoverProps) => {
const [initialLabel] = useState(label);
const [
initialAdhocColumn,
initialCalculatedColumn,
initialSimpleColumn,
] = editedColumn?.expression
? [editedColumn, undefined]
: [undefined, editedColumn];
const [selectedCalculatedColumn, setSelectedCalculatedColumn] = useState(
initialCalculatedColumn,
);
const [selectedSimpleColumn, setSelectedSimpleColumn] = useState(
initialSimpleColumn,
] = getInitialColumnValues(editedColumn);

const [adhocColumn, setAdhocColumn] = useState<AdhocColumn | undefined>(
initialAdhocColumn,
);
const [selectedCalculatedColumn, setSelectedCalculatedColumn] = useState<
ColumnMeta | undefined
>(initialCalculatedColumn);
const [selectedSimpleColumn, setSelectedSimpleColumn] = useState<
ColumnMeta | undefined
>(initialSimpleColumn);

const sqlEditorRef = useRef(null);

const [calculatedColumns, simpleColumns] = useMemo(
() =>
Expand All @@ -81,15 +122,28 @@ const ColumnSelectPopover = ({
[columns],
);

const onSqlExpressionChange = useCallback(
sqlExpression => {
setAdhocColumn({ label, sqlExpression } as AdhocColumn);
setSelectedSimpleColumn(undefined);
setSelectedCalculatedColumn(undefined);
},
[label],
);

const onCalculatedColumnChange = useCallback(
selectedColumnName => {
const selectedColumn = calculatedColumns.find(
col => col.column_name === selectedColumnName,
);
setSelectedCalculatedColumn(selectedColumn);
setSelectedSimpleColumn(undefined);
setAdhocColumn(undefined);
setLabel(
selectedColumn?.verbose_name || selectedColumn?.column_name || '',
);
},
[calculatedColumns],
[calculatedColumns, setLabel],
);

const onSimpleColumnChange = useCallback(
Expand All @@ -99,33 +153,79 @@ const ColumnSelectPopover = ({
);
setSelectedCalculatedColumn(undefined);
setSelectedSimpleColumn(selectedColumn);
setAdhocColumn(undefined);
setLabel(
selectedColumn?.verbose_name || selectedColumn?.column_name || '',
);
},
[simpleColumns],
[setLabel, simpleColumns],
);

const defaultActiveTabKey =
initialSimpleColumn || calculatedColumns.length === 0 ? 'simple' : 'saved';
const defaultActiveTabKey = initialAdhocColumn
? 'sqlExpression'
: initialSimpleColumn || calculatedColumns.length === 0
? 'simple'
: 'saved';

useEffect(() => {
getCurrentTab(defaultActiveTabKey);
}, [defaultActiveTabKey, getCurrentTab]);

const onSave = useCallback(() => {
const selectedColumn = selectedCalculatedColumn || selectedSimpleColumn;
if (adhocColumn && adhocColumn.label !== label) {
adhocColumn.label = label;
}
const selectedColumn =
adhocColumn || selectedCalculatedColumn || selectedSimpleColumn;
if (!selectedColumn) {
return;
}
onChange(selectedColumn);
onClose();
}, [onChange, onClose, selectedCalculatedColumn, selectedSimpleColumn]);
}, [
adhocColumn,
label,
onChange,
onClose,
selectedCalculatedColumn,
selectedSimpleColumn,
]);

const onResetStateAndClose = useCallback(() => {
setSelectedCalculatedColumn(initialCalculatedColumn);
setSelectedSimpleColumn(initialSimpleColumn);
setAdhocColumn(initialAdhocColumn);
onClose();
}, [initialCalculatedColumn, initialSimpleColumn, onClose]);
}, [
initialAdhocColumn,
initialCalculatedColumn,
initialSimpleColumn,
onClose,
]);

const stateIsValid = selectedCalculatedColumn || selectedSimpleColumn;
const onTabChange = useCallback(
tab => {
getCurrentTab(tab);
// @ts-ignore
sqlEditorRef.current?.editor.focus();
},
[getCurrentTab],
);

const onSqlEditorFocus = useCallback(() => {
// @ts-ignore
sqlEditorRef.current?.editor.resize();
}, []);

const stateIsValid =
adhocColumn || selectedCalculatedColumn || selectedSimpleColumn;
const hasUnsavedChanges =
initialLabel !== label ||
selectedCalculatedColumn?.column_name !==
initialCalculatedColumn?.column_name ||
selectedSimpleColumn?.column_name !== initialSimpleColumn?.column_name;
selectedSimpleColumn?.column_name !== initialSimpleColumn?.column_name ||
adhocColumn?.sqlExpression !== initialAdhocColumn?.sqlExpression;

const savedExpressionsLabel = t('Saved expressions');
const simpleColumnsLabel = t('Column');

Expand All @@ -134,8 +234,12 @@ const ColumnSelectPopover = ({
<Tabs
id="adhoc-metric-edit-tabs"
defaultActiveKey={defaultActiveTabKey}
onChange={onTabChange}
className="adhoc-metric-edit-tabs"
allowOverflow
css={css`
height: ${POPOVER_INITIAL_HEIGHT}px;
`}
>
<Tabs.TabPane key="saved" tab={t('Saved')}>
<FormItem label={savedExpressionsLabel}>
Expand Down Expand Up @@ -178,6 +282,28 @@ const ColumnSelectPopover = ({
/>
</FormItem>
</Tabs.TabPane>
{isAdhocColumnsEnabled && (
<Tabs.TabPane key="sqlExpression" tab={t('Custom SQL')}>
<SQLEditor
value={
adhocColumn?.sqlExpression ||
selectedSimpleColumn?.column_name ||
selectedCalculatedColumn?.expression
}
onFocus={onSqlEditorFocus}
showLoadingForImport
onChange={onSqlExpressionChange}
width="100%"
height={`${POPOVER_INITIAL_HEIGHT - 80}px`}
showGutter={false}
editorProps={{ $blockScrolling: true }}
enableLiveAutocompletion
className="filter-sql-editor"
wrapEnabled
ref={sqlEditorRef}
/>
</Tabs.TabPane>
)}
</Tabs>
<div>
<Button buttonSize="small" onClick={onResetStateAndClose} cta>
Expand Down
Loading