This is an automated email from the ASF dual-hosted git repository.
villebro pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/master by this push:
new b28d7ea fix(native-filters): default value checkbox in config modal
(#15257)
b28d7ea is described below
commit b28d7eace3db98bbd825ecb212be28abfce9237e
Author: Ville Brofeldt <[email protected]>
AuthorDate: Mon Jun 21 15:58:30 2021 +0300
fix(native-filters): default value checkbox in config modal (#15257)
* fix(native-filters): default value checkbox in config modal
* disable checkbox if required
* simplify styling logic
* make default value mandatory if checked
* address comments
---
.../FiltersConfigForm/CollapsibleControl.tsx | 13 +++++-
.../FiltersConfigForm/FiltersConfigForm.tsx | 54 ++++++++++++++--------
.../FiltersConfigForm/getControlItemsMap.tsx | 2 +-
.../FiltersConfigModal/FiltersConfigForm/state.ts | 46 ++++++++++++++----
.../components/Select/SelectFilterPlugin.tsx | 2 +-
.../src/filters/components/Select/controlPanel.ts | 3 +-
6 files changed, 86 insertions(+), 34 deletions(-)
diff --git
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/CollapsibleControl.tsx
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/CollapsibleControl.tsx
index 13b115b..68f3ad5 100644
---
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/CollapsibleControl.tsx
+++
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/CollapsibleControl.tsx
@@ -19,11 +19,14 @@
import React, { ReactNode, useEffect, useState } from 'react';
import { styled } from '@superset-ui/core';
import { Checkbox } from 'src/common/components';
+import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
interface CollapsibleControlProps {
initialValue?: boolean;
+ disabled?: boolean;
checked?: boolean;
title: string;
+ tooltip?: string;
children: ReactNode;
onChange?: (checked: boolean) => void;
}
@@ -48,7 +51,9 @@ const StyledContainer = styled.div<{ checked: boolean }>`
const CollapsibleControl = (props: CollapsibleControlProps) => {
const {
checked,
+ disabled,
title,
+ tooltip,
children,
onChange = () => {},
initialValue = false,
@@ -68,6 +73,7 @@ const CollapsibleControl = (props: CollapsibleControlProps)
=> {
<Checkbox
className="checkbox"
checked={isChecked}
+ disabled={disabled}
onChange={e => {
const value = e.target.checked;
// external `checked` value has more priority then local state
@@ -78,7 +84,12 @@ const CollapsibleControl = (props: CollapsibleControlProps)
=> {
onChange(value);
}}
>
- {title}
+ <>
+ {title}
+ {tooltip && (
+ <InfoTooltipWithTrigger placement="top" tooltip={tooltip} />
+ )}
+ </>
</Checkbox>
{isChecked && children}
</StyledContainer>
diff --git
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
index aa83b8b..32d0204 100644
---
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
+++
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
@@ -129,6 +129,20 @@ export const StyledRowFormItem = styled(FormItem)`
}
`;
+export const StyledRowSubFormItem = styled(FormItem)`
+ & .ant-form-item-label {
+ padding-bottom: 0;
+ }
+
+ .ant-form-item-control-input-content > div > div {
+ height: auto;
+ }
+
+ & .ant-form-item-control-input {
+ height: auto;
+ }
+`;
+
export const StyledLabel = styled.span`
color: ${({ theme }) => theme.colors.grayscale.base};
font-size: ${({ theme }) => theme.typography.sizes.s}px;
@@ -454,10 +468,12 @@ const FiltersConfigForm = (
...formFilter,
});
- const [hasDefaultValue, setHasDefaultValue] = useDefaultValue(
- formFilter,
- filterToEdit,
- );
+ const [
+ hasDefaultValue,
+ isRequired,
+ defaultValueTooltip,
+ setHasDefaultValue,
+ ] = useDefaultValue(formFilter, filterToEdit);
useEffect(() => {
if (hasDataset && hasFilledDataset && hasDefaultValue && isDataDirty) {
@@ -540,6 +556,8 @@ const FiltersConfigForm = (
const hasAdhoc = formFilter?.adhoc_filters?.length > 0;
+ const defaultToFirstItem = formFilter?.controlValues?.defaultToFirstItem;
+
const preFilterValidator = () => {
if (hasTimeRange || hasAdhoc) {
return Promise.resolve();
@@ -713,26 +731,22 @@ const FiltersConfigForm = (
<CollapsibleControl
title={t('Filter has default value')}
initialValue={hasDefaultValue}
+ disabled={isRequired || defaultToFirstItem}
+ tooltip={defaultValueTooltip}
checked={hasDefaultValue}
onChange={value => setHasDefaultValue(value)}
>
- <StyledRowFormItem
+ <StyledRowSubFormItem
name={['filters', filterId, 'defaultDataMask']}
initialValue={filterToEdit?.defaultDataMask}
data-test="default-input"
label={<StyledLabel>{t('Default Value')}</StyledLabel>}
- required={formFilter?.controlValues?.enableEmptyFilter}
+ required={hasDefaultValue}
rules={[
{
validator: (rule, value) => {
const hasValue = !!value?.filterState?.value;
- if (
- hasValue ||
- // TODO: do more generic
- formFilter.controlValues?.defaultToFirstItem ||
- // Not marked as required
- !formFilter.controlValues?.enableEmptyFilter
- ) {
+ if (hasValue) {
return Promise.resolve();
}
return Promise.reject(
@@ -775,7 +789,7 @@ const FiltersConfigForm = (
) : (
t('Fill all required fields to enable "Default Value"')
)}
- </StyledRowFormItem>
+ </StyledRowSubFormItem>
</CollapsibleControl>
{Object.keys(controlItems)
.filter(key => BASIC_CONTROL_ITEMS.includes(key))
@@ -814,7 +828,7 @@ const FiltersConfigForm = (
}
}}
>
- <StyledRowFormItem
+ <StyledRowSubFormItem
name={['filters', filterId, 'parentFilter']}
label={<StyledLabel>{t('Parent filter')}</StyledLabel>}
initialValue={parentFilter}
@@ -832,7 +846,7 @@ const FiltersConfigForm = (
options={parentFilterOptions}
isClearable
/>
- </StyledRowFormItem>
+ </StyledRowSubFormItem>
</CollapsibleControl>
)}
{Object.keys(controlItems)
@@ -848,7 +862,7 @@ const FiltersConfigForm = (
}
}}
>
- <StyledRowFormItem
+ <StyledRowSubFormItem
name={['filters', filterId, 'adhoc_filters']}
initialValue={filterToEdit?.adhoc_filters}
required
@@ -880,7 +894,7 @@ const FiltersConfigForm = (
</span>
}
/>
- </StyledRowFormItem>
+ </StyledRowSubFormItem>
{showTimeRangePicker && (
<StyledRowFormItem
name={['filters', filterId, 'time_range']}
@@ -976,7 +990,7 @@ const FiltersConfigForm = (
/>
</StyledFormItem>
{hasMetrics && (
- <StyledRowFormItem
+ <StyledRowSubFormItem
name={['filters', filterId, 'sortMetric']}
initialValue={filterToEdit?.sortMetric}
label={
@@ -1009,7 +1023,7 @@ const FiltersConfigForm = (
}
}}
/>
- </StyledRowFormItem>
+ </StyledRowSubFormItem>
)}
</CollapsibleControl>
)}
diff --git
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx
index 097d80b..fd220e4 100644
---
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx
+++
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx
@@ -116,7 +116,7 @@ export default function getControlItemsMap({
forceUpdate();
}}
>
- {controlItem.config.label}{' '}
+ {controlItem.config.label}
{controlItem.config.description && (
<InfoTooltipWithTrigger
placement="top"
diff --git
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts
index b0c00b9..6cb292d 100644
---
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts
+++
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts
@@ -18,6 +18,7 @@
*/
import { useCallback, useEffect, useState } from 'react';
import { FormInstance } from 'antd/lib/form';
+import { t } from '@superset-ui/core';
import { NativeFiltersForm, NativeFiltersFormItem } from '../types';
import { setNativeFilterFieldValues, useForceUpdate } from './utils';
import { Filter } from '../../types';
@@ -56,20 +57,47 @@ export const useDefaultValue = (
!!filterToEdit?.defaultDataMask?.filterState?.value ||
formFilter?.controlValues?.enableEmptyFilter,
);
+ const [isRequired, setisRequired] = useState(
+ formFilter?.controlValues?.enableEmptyFilter,
+ );
+
+ const [defaultValueTooltip, setDefaultValueTooltip] = useState('');
+
+ const defaultToFirstItem = formFilter?.controlValues?.defaultToFirstItem;
+
const setHasDefaultValue = useCallback(
(value?) => {
- setHasPartialDefaultValue(
- value || formFilter?.controlValues?.enableEmptyFilter
- ? true
- : undefined,
- );
+ const required =
+ !!formFilter?.controlValues?.enableEmptyFilter && !defaultToFirstItem;
+ setisRequired(required);
+ setHasPartialDefaultValue(required ? true : value);
},
- [formFilter?.controlValues?.enableEmptyFilter],
+ [formFilter?.controlValues?.enableEmptyFilter, defaultToFirstItem],
);
useEffect(() => {
- setHasDefaultValue();
- }, [setHasDefaultValue]);
+ setHasDefaultValue(
+ defaultToFirstItem
+ ? false
+ : !!formFilter?.defaultDataMask?.filterState?.value,
+ );
+ }, [setHasDefaultValue, defaultToFirstItem]);
+
+ useEffect(() => {
+ let tooltip = '';
+ if (defaultToFirstItem) {
+ tooltip = t(
+ 'Default value set automatically when "Default to first item" is
checked',
+ );
+ } else if (isRequired) {
+ tooltip = t('Default value must be set when "Required" is checked');
+ } else if (hasDefaultValue) {
+ tooltip = t(
+ 'Default value must be set when "Filter has default value" is checked',
+ );
+ }
+ setDefaultValueTooltip(tooltip);
+ }, [hasDefaultValue, isRequired, defaultToFirstItem]);
- return [hasDefaultValue, setHasDefaultValue];
+ return [hasDefaultValue, isRequired, defaultValueTooltip,
setHasDefaultValue];
};
diff --git
a/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx
b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx
index 8b01d0f..23fd0f3 100644
--- a/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx
+++ b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx
@@ -284,7 +284,7 @@ export default function PluginFilterSelect(props:
PluginFilterSelectProps) {
extra={<Error>{filterState.validateMessage}</Error>}
>
<StyledSelect
- allowClear={!enableEmptyFilter}
+ allowClear
// @ts-ignore
value={filterState.value || []}
disabled={isDisabled}
diff --git a/superset-frontend/src/filters/components/Select/controlPanel.ts
b/superset-frontend/src/filters/components/Select/controlPanel.ts
index 74891b0..80aad2c 100644
--- a/superset-frontend/src/filters/components/Select/controlPanel.ts
+++ b/superset-frontend/src/filters/components/Select/controlPanel.ts
@@ -77,8 +77,7 @@ const config: ControlPanelConfig = {
default: enableEmptyFilter,
renderTrigger: true,
description: t(
- 'User must select a value for this filter when filter is in
single select mode. ' +
- 'If selection is empty, an always false filter is emitted.',
+ 'User must select a value before applying the filter',
),
},
},