diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx b/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx
index c68b436a0e497..ce4c32191d0d2 100644
--- a/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx
+++ b/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx
@@ -16,11 +16,17 @@
* specific language governing permissions and limitations
* under the License.
*/
-import React, { useState, useEffect, useMemo } from 'react';
-import { css, styled, t, useTheme, NO_TIME_RANGE } from '@superset-ui/core';
+import React, { ReactNode, useState, useEffect, useMemo } from 'react';
+import {
+ css,
+ styled,
+ t,
+ useTheme,
+ NO_TIME_RANGE,
+ SupersetTheme,
+} from '@superset-ui/core';
import Button from 'src/components/Button';
import ControlHeader from 'src/explore/components/ControlHeader';
-import Label from 'src/components/Label';
import Modal from 'src/components/Modal';
import { Divider } from 'src/components';
import Icons from 'src/components/Icons';
@@ -29,6 +35,7 @@ import { Tooltip } from 'src/components/Tooltip';
import { useDebouncedEffect } from 'src/explore/exploreUtils';
import { SLOW_DEBOUNCE } from 'src/constants';
import { noOp } from 'src/utils/common';
+import { useCSSTextTruncation } from 'src/hooks/useTruncation';
import ControlPopover from '../ControlPopover/ControlPopover';
import { DateFilterControlProps, FrameType } from './types';
@@ -44,6 +51,7 @@ import {
CalendarFrame,
CustomFrame,
AdvancedFrame,
+ DateLabel,
} from './components';
const StyledRangeType = styled(Select)`
@@ -120,6 +128,28 @@ const IconWrapper = styled.span`
}
`;
+const getTooltipTitle = (
+ isLabelTruncated: boolean,
+ label: string | undefined,
+ range: string | undefined,
+) =>
+ isLabelTruncated ? (
+
+ {label &&
{label}}
+ {range && (
+
css`
+ margin-top: ${theme.gridUnit}px;
+ `}
+ >
+ {range}
+
+ )}
+
+ ) : (
+ range || null
+ );
+
export default function DateFilterLabel(props: DateFilterControlProps) {
const {
onChange,
@@ -139,13 +169,14 @@ export default function DateFilterLabel(props: DateFilterControlProps) {
const [timeRangeValue, setTimeRangeValue] = useState(value);
const [validTimeRange, setValidTimeRange] = useState(false);
const [evalResponse, setEvalResponse] = useState(value);
- const [tooltipTitle, setTooltipTitle] = useState(value);
+ const [tooltipTitle, setTooltipTitle] = useState(value);
const theme = useTheme();
+ const [labelRef, labelIsTruncated] = useCSSTextTruncation();
useEffect(() => {
if (value === NO_TIME_RANGE) {
setActualTimeRange(NO_TIME_RANGE);
- setTooltipTitle(NO_TIME_RANGE);
+ setTooltipTitle(null);
setValidTimeRange(true);
return;
}
@@ -153,7 +184,7 @@ export default function DateFilterLabel(props: DateFilterControlProps) {
if (error) {
setEvalResponse(error || '');
setValidTimeRange(false);
- setTooltipTitle(value || '');
+ setTooltipTitle(value || null);
} else {
/*
HRT == human readable text
@@ -172,16 +203,21 @@ export default function DateFilterLabel(props: DateFilterControlProps) {
guessedFrame === 'No filter'
) {
setActualTimeRange(value);
+ setTooltipTitle(
+ getTooltipTitle(labelIsTruncated, value, actualRange),
+ );
} else {
setActualTimeRange(actualRange || '');
- setTooltipTitle(value || '');
+ setTooltipTitle(
+ getTooltipTitle(labelIsTruncated, actualRange, value),
+ );
}
setValidTimeRange(true);
}
setLastFetchedTimeRange(value);
setEvalResponse(actualRange || value);
});
- }, [value]);
+ }, [guessedFrame, labelIsTruncated, labelRef, value]);
useDebouncedEffect(
() => {
@@ -322,12 +358,13 @@ export default function DateFilterLabel(props: DateFilterControlProps) {
overlayStyle={{ width: '600px' }}
>
-
+ ref={labelRef}
+ />
);
@@ -335,13 +372,14 @@ export default function DateFilterLabel(props: DateFilterControlProps) {
const modalContent = (
<>
-
+ ref={labelRef}
+ />
{/* the zIndex value is from trying so that the Modal doesn't overlay the AdhocFilter when GENERIC_CHART_AXES is enabled */}
void;
+};
+
+// This is the color that antd components (such as Select or Input) use on hover
+// TODO: use theme.colors.primary.base here and in antd components
+const ACTIVE_BORDER_COLOR = '#45BED6';
+
+const LabelContainer = styled.div<{
+ isActive?: boolean;
+ isPlaceholder?: boolean;
+}>`
+ ${({ theme, isActive, isPlaceholder }) => css`
+ width: 100%;
+ height: ${theme.gridUnit * 8}px;
+
+ display: flex;
+ align-items: center;
+ flex-wrap: nowrap;
+
+ padding: 0 ${theme.gridUnit * 3}px;
+
+ background-color: ${theme.colors.grayscale.light5};
+
+ border: 1px solid
+ ${isActive ? ACTIVE_BORDER_COLOR : theme.colors.grayscale.light2};
+ border-radius: ${theme.borderRadius}px;
+
+ cursor: pointer;
+
+ transition: border-color 0.3s cubic-bezier(0.65, 0.05, 0.36, 1);
+ :hover,
+ :focus {
+ border-color: ${ACTIVE_BORDER_COLOR};
+ }
+
+ .date-label-content {
+ color: ${isPlaceholder
+ ? theme.colors.grayscale.light1
+ : theme.colors.grayscale.dark1};
+ overflow: hidden;
+ text-overflow: ellipsis;
+ min-width: 0;
+ flex-shrink: 1;
+ white-space: nowrap;
+ }
+
+ span[role='img'] {
+ margin-left: auto;
+ padding-left: ${theme.gridUnit}px;
+
+ & > span[role='img'] {
+ line-height: 0;
+ }
+ }
+ `}
+`;
+
+export const DateLabel = forwardRef(
+ (props: DateLabelProps, ref: RefObject) => {
+ const theme = useTheme();
+ return (
+
+
+ {props.label}
+
+
+
+ );
+ },
+);
diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/components/index.ts b/superset-frontend/src/explore/components/controls/DateFilterControl/components/index.ts
index 0bec821065627..0d46ee7a97d19 100644
--- a/superset-frontend/src/explore/components/controls/DateFilterControl/components/index.ts
+++ b/superset-frontend/src/explore/components/controls/DateFilterControl/components/index.ts
@@ -20,3 +20,4 @@ export { CommonFrame } from './CommonFrame';
export { CalendarFrame } from './CalendarFrame';
export { CustomFrame } from './CustomFrame';
export { AdvancedFrame } from './AdvancedFrame';
+export { DateLabel } from './DateLabel';
diff --git a/superset-frontend/src/filters/components/Time/TimeFilterPlugin.tsx b/superset-frontend/src/filters/components/Time/TimeFilterPlugin.tsx
index 0d4185b7592e6..0e0678d890dbf 100644
--- a/superset-frontend/src/filters/components/Time/TimeFilterPlugin.tsx
+++ b/superset-frontend/src/filters/components/Time/TimeFilterPlugin.tsx
@@ -38,28 +38,11 @@ const ControlContainer = styled.div<{
display: flex;
height: 100%;
max-width: 100%;
- padding: 2px;
- & > span,
- & > span:hover {
- border: 2px solid transparent;
- display: inline-block;
- border: ${({ theme, validateStatus }) =>
- validateStatus && `2px solid ${theme.colors[validateStatus]?.base}`};
- }
- &:focus {
- & > span {
- border: 2px solid
- ${({ theme, validateStatus }) =>
- validateStatus
- ? theme.colors[validateStatus]?.base
- : theme.colors.primary.base};
- outline: 0;
- box-shadow: 0 0 0 2px
- ${({ validateStatus }) =>
- validateStatus
- ? 'rgba(224, 67, 85, 12%)'
- : 'rgba(32, 167, 201, 0.2)'};
- }
+ width: 100%;
+ & > div,
+ & > div:hover {
+ ${({ validateStatus, theme }) =>
+ validateStatus && `border-color: ${theme.colors[validateStatus]?.base}`}
}
`;
@@ -99,7 +82,6 @@ export default function TimeFilterPlugin(props: PluginFilterTimeProps) {
return props.formData?.inView ? (