diff --git a/superset-frontend/src/explore/components/DatasourcePanel/index.tsx b/superset-frontend/src/explore/components/DatasourcePanel/index.tsx
index 9ce26d918e14..8e83bb090db1 100644
--- a/superset-frontend/src/explore/components/DatasourcePanel/index.tsx
+++ b/superset-frontend/src/explore/components/DatasourcePanel/index.tsx
@@ -16,14 +16,14 @@
* specific language governing permissions and limitations
* under the License.
*/
-import React, { useEffect, useState } from 'react';
+import React, { useEffect, useMemo, useState } from 'react';
import { styled, t } from '@superset-ui/core';
import Collapse from 'src/components/Collapse';
import { ControlConfig, DatasourceMeta } from '@superset-ui/chart-controls';
import { debounce } from 'lodash';
import { matchSorter, rankings } from 'match-sorter';
import { FAST_DEBOUNCE } from 'src/constants';
-import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags';
+import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
import { ExploreActions } from 'src/explore/actions/exploreActions';
import Control from 'src/explore/components/Control';
import DatasourcePanelDragWrapper from './DatasourcePanelDragWrapper';
@@ -120,7 +120,23 @@ export default function DataSourcePanel({
controls: { datasource: datasourceControl },
actions,
}: Props) {
- const { columns, metrics } = datasource;
+ const { columns: _columns, metrics } = datasource;
+
+ // display temporal column first
+ const columns = useMemo(
+ () =>
+ [..._columns].sort((col1, col2) => {
+ if (col1.is_dttm && !col2.is_dttm) {
+ return -1;
+ }
+ if (col2.is_dttm && !col1.is_dttm) {
+ return 1;
+ }
+ return 0;
+ }),
+ [_columns],
+ );
+
const [inputValue, setInputValue] = useState('');
const [lists, setList] = useState({
columns,
diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx
index 29cd738d6d2f..d677aa2104d8 100644
--- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx
+++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx
@@ -29,7 +29,14 @@ import { DndItemType } from 'src/explore/components/DndItemType';
import { StyledColumnOption } from 'src/explore/components/optionRenderers';
export const DndColumnSelect = (props: LabelProps) => {
- const { value, options, multi = true, onChange } = props;
+ const {
+ value,
+ options,
+ multi = true,
+ onChange,
+ canDelete = true,
+ ghostButtonText,
+ } = props;
const optionSelector = new OptionSelector(options, multi, value);
// synchronize values in case of dataset changes
@@ -66,9 +73,12 @@ export const DndColumnSelect = (props: LabelProps) => {
onChange(optionSelector.getValues());
};
- const canDrop = (item: DatasourcePanelDndItem) =>
- (multi || optionSelector.values.length === 0) &&
- !optionSelector.has((item.value as ColumnMeta).column_name);
+ const canDrop = (item: DatasourcePanelDndItem) => {
+ const columnName = (item.value as ColumnMeta).column_name;
+ return (
+ columnName in optionSelector.options && !optionSelector.has(columnName)
+ );
+ };
const onClickClose = (index: number) => {
optionSelector.del(index);
@@ -88,6 +98,7 @@ export const DndColumnSelect = (props: LabelProps) => {
clickClose={onClickClose}
onShiftOptions={onShiftOptions}
type={DndItemType.ColumnOption}
+ canDelete={canDelete}
>
@@ -100,7 +111,9 @@ export const DndColumnSelect = (props: LabelProps) => {
valuesRenderer={valuesRenderer}
accept={DndItemType.Column}
displayGhostButton={multi || optionSelector.values.length === 0}
- ghostButtonText={tn('Drop column', 'Drop columns', multi ? 2 : 1)}
+ ghostButtonText={
+ ghostButtonText || tn('Drop column', 'Drop columns', multi ? 2 : 1)
+ }
{...props}
/>
);
diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx
index a3daeaf70211..9b38c159ee81 100644
--- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx
+++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx
@@ -157,11 +157,11 @@ export const DndMetricSelect = (props: any) => {
const canDrop = (item: DatasourcePanelDndItem) => {
const isMetricAlreadyInValues =
item.type === 'metric' ? value.includes(item.value.metric_name) : false;
- return (props.multi || value.length === 0) && !isMetricAlreadyInValues;
+ return !isMetricAlreadyInValues;
};
const onNewMetric = (newMetric: Metric) => {
- const newValue = [...value, newMetric];
+ const newValue = props.isMulti ? [...value, newMetric] : [newMetric];
setValue(newValue);
handleChange(newValue);
};
diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/Option.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/Option.tsx
index 11c68a6373e4..50e1bfe0deec 100644
--- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/Option.tsx
+++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/Option.tsx
@@ -32,22 +32,28 @@ const StyledInfoTooltipWithTrigger = styled(InfoTooltipWithTrigger)`
margin: 0 ${({ theme }) => theme.gridUnit}px;
`;
-export default function Option(props: OptionProps) {
+export default function Option({
+ children,
+ index,
+ clickClose,
+ withCaret,
+ isExtra,
+ canDelete = true,
+}: OptionProps) {
const theme = useTheme();
return (
-
- props.clickClose(props.index)}
- >
-
-
-
- {props.isExtra && (
+
+ {canDelete && (
+ clickClose(index)}
+ >
+
+
+ )}
+
+ {isExtra && (
)}
- {props.withCaret && (
+ {withCaret && (
diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/OptionWrapper.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/OptionWrapper.tsx
index 40da4c4ff57a..62230c56f87b 100644
--- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/OptionWrapper.tsx
+++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/OptionWrapper.tsx
@@ -44,6 +44,7 @@ export default function OptionWrapper(
clickClose,
withCaret,
isExtra,
+ canDelete = true,
children,
...rest
} = props;
@@ -113,6 +114,7 @@ export default function OptionWrapper(
clickClose={clickClose}
withCaret={withCaret}
isExtra={isExtra}
+ canDelete={canDelete}
>
{children}
diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/types.ts b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/types.ts
index da2c51a1d5a6..2d7142e2d735 100644
--- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/types.ts
+++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/types.ts
@@ -28,6 +28,7 @@ export interface OptionProps {
clickClose: (index: number) => void;
withCaret?: boolean;
isExtra?: boolean;
+ canDelete?: boolean;
}
export interface OptionItemInterface {
@@ -41,6 +42,8 @@ export interface LabelProps {
onChange: (value?: T) => void;
options: { string: ColumnMeta };
multi?: boolean;
+ canDelete?: boolean;
+ ghostButtonText?: string;
}
export interface DndColumnSelectProps<