mirror of
https://github.com/apache/superset.git
synced 2024-09-12 00:29:39 -04:00
chore: Improves the native filters UI/UX - iteration 5 (#14882)
This commit is contained in:
parent
fce8ac27f0
commit
8519a09086
@ -35,7 +35,7 @@ const StyledItem = styled(Form.Item)`
|
||||
&::after {
|
||||
display: inline-block;
|
||||
color: ${theme.colors.error.base};
|
||||
font-size: ${theme.typography.sizes.m}px;
|
||||
font-size: ${theme.typography.sizes.s}px;
|
||||
content: '*';
|
||||
}
|
||||
}
|
||||
|
@ -76,8 +76,8 @@ const addFilterFlow = async () => {
|
||||
userEvent.click(screen.getByTestId(getTestId('collapsable')));
|
||||
userEvent.click(screen.getByTestId(getTestId('create-filter')));
|
||||
// select filter
|
||||
userEvent.click(screen.getByText('Select filter'));
|
||||
userEvent.click(screen.getByText('Time filter'));
|
||||
userEvent.click(screen.getByText('Value'));
|
||||
userEvent.click(screen.getByText('Time range'));
|
||||
userEvent.type(screen.getByTestId(getModalTestId('name-input')), FILTER_NAME);
|
||||
userEvent.click(screen.getByText('Save'));
|
||||
await screen.findByText('All Filters (1)');
|
||||
|
@ -42,11 +42,9 @@ export const StyledFilterTitle = styled.span`
|
||||
|
||||
export const StyledAddFilterBox = styled.div`
|
||||
color: ${({ theme }) => theme.colors.primary.dark1};
|
||||
text-align: left;
|
||||
padding: ${({ theme }) => theme.gridUnit * 2}px 0;
|
||||
margin: ${({ theme }) => theme.gridUnit * 3}px 0 0
|
||||
${({ theme }) => -theme.gridUnit * 2}px;
|
||||
border-top: 1px solid ${({ theme }) => theme.colors.grayscale.light1};
|
||||
padding: ${({ theme }) => theme.gridUnit * 2}px;
|
||||
border-top: 1px solid ${({ theme }) => theme.colors.grayscale.light2};
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: ${({ theme }) => theme.colors.primary.base};
|
||||
@ -89,12 +87,19 @@ const FilterTabsContainer = styled(LineEditableTabs)`
|
||||
|
||||
& > .ant-tabs-content-holder {
|
||||
border-left: 1px solid ${theme.colors.grayscale.light2};
|
||||
margin-right: ${theme.gridUnit * 4}px;
|
||||
padding-right: ${theme.gridUnit * 4}px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
& > .ant-tabs-content-holder ~ .ant-tabs-content-holder {
|
||||
border: none;
|
||||
}
|
||||
|
||||
&.ant-tabs-card > .ant-tabs-nav .ant-tabs-ink-bar {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
&.ant-tabs-left
|
||||
> .ant-tabs-content-holder
|
||||
> .ant-tabs-content
|
||||
@ -104,9 +109,11 @@ const FilterTabsContainer = styled(LineEditableTabs)`
|
||||
}
|
||||
|
||||
.ant-tabs-nav-list {
|
||||
padding-top: ${theme.gridUnit * 4}px;
|
||||
padding-right: ${theme.gridUnit * 2}px;
|
||||
padding-bottom: ${theme.gridUnit * 4}px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
padding-top: ${theme.gridUnit * 2}px;
|
||||
padding-right: ${theme.gridUnit}px;
|
||||
padding-bottom: ${theme.gridUnit * 3}px;
|
||||
padding-left: ${theme.gridUnit * 3}px;
|
||||
}
|
||||
|
||||
@ -135,6 +142,24 @@ const FilterTabsContainer = styled(LineEditableTabs)`
|
||||
justify-content: space-between;
|
||||
text-transform: unset;
|
||||
}
|
||||
|
||||
.ant-tabs-nav-more {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ant-tabs-extra-content {
|
||||
width: 100%;
|
||||
}
|
||||
`}
|
||||
`;
|
||||
|
||||
const StyledHeader = styled.div`
|
||||
${({ theme }) => `
|
||||
color: ${theme.colors.grayscale.dark1};
|
||||
font-size: ${theme.typography.sizes.l}px;
|
||||
padding-top: ${theme.gridUnit * 4}px;
|
||||
padding-right: ${theme.gridUnit * 4}px;
|
||||
padding-left: ${theme.gridUnit * 4}px;
|
||||
`}
|
||||
`;
|
||||
|
||||
@ -164,14 +189,18 @@ const FilterTabs: FC<FilterTabsProps> = ({
|
||||
onChange={onChange}
|
||||
activeKey={currentFilterId}
|
||||
onEdit={onEdit}
|
||||
addIcon={
|
||||
<StyledAddFilterBox>
|
||||
hideAdd
|
||||
tabBarExtraContent={{
|
||||
left: <StyledHeader>{t('Filters')}</StyledHeader>,
|
||||
right: (
|
||||
<StyledAddFilterBox onClick={() => onEdit('', 'add')}>
|
||||
<PlusOutlined />{' '}
|
||||
<span data-test="add-filter-button" aria-label="Add filter">
|
||||
{t('Add filter')}
|
||||
</span>
|
||||
</StyledAddFilterBox>
|
||||
}
|
||||
),
|
||||
}}
|
||||
>
|
||||
{filterIds.map(id => (
|
||||
<LineEditableTabs.TabPane
|
||||
|
@ -41,7 +41,8 @@ import React, {
|
||||
useImperativeHandle,
|
||||
} from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { Checkbox, Form, Input } from 'src/common/components';
|
||||
import { FormItem } from 'src/components/Form';
|
||||
import { Checkbox, Input } from 'src/common/components';
|
||||
import { Select } from 'src/components/Select';
|
||||
import SupersetResourceSelect, {
|
||||
cachedSupersetGet,
|
||||
@ -91,22 +92,32 @@ const StyledRowContainer = styled.div`
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
export const StyledFormItem = styled(Form.Item)`
|
||||
export const StyledFormItem = styled(FormItem)`
|
||||
width: 49%;
|
||||
margin-bottom: ${({ theme }) => theme.gridUnit * 4}px;
|
||||
|
||||
& .ant-form-item-label {
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
& .ant-form-item-control-input {
|
||||
min-height: ${({ theme }) => theme.gridUnit * 10}px;
|
||||
}
|
||||
`;
|
||||
|
||||
export const StyledRowFormItem = styled(Form.Item)`
|
||||
export const StyledRowFormItem = styled(FormItem)`
|
||||
margin-bottom: 0px;
|
||||
padding-bottom: 0px;
|
||||
min-width: 50%;
|
||||
|
||||
& .ant-form-item-label {
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
.ant-form-item-control-input-content > div > div {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
& .ant-form-item-control-input {
|
||||
min-height: ${({ theme }) => theme.gridUnit * 10}px;
|
||||
}
|
||||
@ -118,7 +129,7 @@ export const StyledLabel = styled.span`
|
||||
text-transform: uppercase;
|
||||
`;
|
||||
|
||||
const CleanFormItem = styled(Form.Item)`
|
||||
const CleanFormItem = styled(FormItem)`
|
||||
margin-bottom: 0;
|
||||
`;
|
||||
|
||||
@ -151,6 +162,13 @@ const StyledCollapse = styled(Collapse)`
|
||||
`;
|
||||
|
||||
const StyledTabs = styled(Tabs)`
|
||||
.ant-tabs-nav {
|
||||
position: sticky;
|
||||
top: 0px;
|
||||
background: white;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.ant-tabs-nav-list {
|
||||
padding: 0px;
|
||||
}
|
||||
@ -164,6 +182,9 @@ const StyledAsterisk = styled.span`
|
||||
color: ${({ theme }) => theme.colors.error.base};
|
||||
font-family: SimSun, sans-serif;
|
||||
margin-right: ${({ theme }) => theme.gridUnit - 1}px;
|
||||
&:before {
|
||||
content: '*';
|
||||
}
|
||||
`;
|
||||
|
||||
const FilterTabs = {
|
||||
@ -208,6 +229,15 @@ const FILTERS_WITH_ADHOC_FILTERS = ['filter_select', 'filter_range'];
|
||||
|
||||
const BASIC_CONTROL_ITEMS = ['enableEmptyFilter', 'multiSelect'];
|
||||
|
||||
const FILTER_TYPE_NAME_MAPPING = {
|
||||
[t('Select filter')]: t('Value'),
|
||||
[t('Range filter')]: t('Numerical range'),
|
||||
[t('Time filter')]: t('Time range'),
|
||||
[t('Time column')]: t('Time column'),
|
||||
[t('Time grain')]: t('Time grain'),
|
||||
[t('Group By')]: t('Group by'),
|
||||
};
|
||||
|
||||
/**
|
||||
* The configuration form for a specific filter.
|
||||
* Assigns field values to `filters[filterId]` in the form.
|
||||
@ -418,7 +448,6 @@ const FiltersConfigForm = (
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledTabs
|
||||
defaultActiveKey={FilterTabs.configuration.key}
|
||||
activeKey={activeTabKey}
|
||||
@ -447,11 +476,17 @@ const FiltersConfigForm = (
|
||||
{...getFiltersConfigModalTestId('filter-type')}
|
||||
>
|
||||
<Select
|
||||
options={nativeFilterVizTypes.map(filterType => ({
|
||||
value: filterType,
|
||||
options={nativeFilterVizTypes.map(filterType => {
|
||||
// @ts-ignore
|
||||
label: nativeFilterItems[filterType]?.value.name,
|
||||
}))}
|
||||
const name = nativeFilterItems[filterType]?.value.name;
|
||||
const mappedName = name
|
||||
? FILTER_TYPE_NAME_MAPPING[name]
|
||||
: undefined;
|
||||
return {
|
||||
value: filterType,
|
||||
label: mappedName || name,
|
||||
};
|
||||
})}
|
||||
onChange={({ value }: { value: string }) => {
|
||||
setNativeFilterFieldValues(form, filterId, {
|
||||
filterType: value,
|
||||
@ -523,7 +558,10 @@ const FiltersConfigForm = (
|
||||
)}
|
||||
</StyledRowContainer>
|
||||
)}
|
||||
<StyledCollapse defaultActiveKey={FilterPanels.basic.key}>
|
||||
<StyledCollapse
|
||||
defaultActiveKey={FilterPanels.basic.key}
|
||||
expandIconPosition="right"
|
||||
>
|
||||
<Collapse.Panel
|
||||
header={FilterPanels.basic.name}
|
||||
key={FilterPanels.basic.key}
|
||||
@ -654,8 +692,7 @@ const FiltersConfigForm = (
|
||||
<CollapsibleControl
|
||||
title={t('Pre-filter available values')}
|
||||
checked={
|
||||
!!filterToEdit?.adhoc_filters ||
|
||||
!!filterToEdit?.time_range
|
||||
!!filterToEdit?.adhoc_filters || !!filterToEdit?.time_range
|
||||
}
|
||||
onChange={checked => {
|
||||
if (checked) {
|
||||
@ -677,7 +714,7 @@ const FiltersConfigForm = (
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: t('Adhoc filters is required'),
|
||||
message: t('Pre-filter is required'),
|
||||
},
|
||||
]}
|
||||
>
|
||||
@ -697,8 +734,8 @@ const FiltersConfigForm = (
|
||||
}}
|
||||
label={
|
||||
<span>
|
||||
<StyledAsterisk>*</StyledAsterisk>
|
||||
<StyledLabel>{t('Adhoc filters')}</StyledLabel>
|
||||
<StyledAsterisk />
|
||||
<StyledLabel>{t('Pre-filter')}</StyledLabel>
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
@ -807,7 +844,6 @@ const FiltersConfigForm = (
|
||||
/>
|
||||
</TabPane>
|
||||
</StyledTabs>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -231,7 +231,7 @@ export function FiltersConfigModal({
|
||||
<StyledModalWrapper
|
||||
visible={isOpen}
|
||||
maskClosable={false}
|
||||
title={t('Filters configuration and scoping')}
|
||||
title={t('Filters configuration')}
|
||||
width="50%"
|
||||
destroyOnClose
|
||||
onCancel={handleCancel}
|
||||
|
@ -64,7 +64,7 @@ export const validateForm = async (
|
||||
addValidationError(
|
||||
filterId,
|
||||
'isInstant',
|
||||
'For parent filters changes must be applied instantly',
|
||||
'For hierarchical filters changes must be applied instantly',
|
||||
);
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user