mirror of
https://github.com/apache/superset.git
synced 2024-09-12 08:39:45 -04:00
feat: Custom filters control (#17006)
* fix:fix get permission function * feat: customize filter control * fix: fix types * fix: fix merge * refactor: update according CR * refactor: fix CR notes
This commit is contained in:
parent
69604c316f
commit
eebc953dd5
@ -59,6 +59,8 @@ const selectedMetricType = PropTypes.oneOfType([
|
||||
const propTypes = {
|
||||
label: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
|
||||
name: PropTypes.string,
|
||||
sections: PropTypes.arrayOf(PropTypes.string),
|
||||
operators: PropTypes.arrayOf(PropTypes.string),
|
||||
onChange: PropTypes.func,
|
||||
value: PropTypes.arrayOf(adhocFilterType),
|
||||
datasource: PropTypes.object,
|
||||
@ -107,6 +109,8 @@ class AdhocFilterControl extends React.Component {
|
||||
adhocFilter={adhocFilter}
|
||||
onFilterEdit={this.onFilterEdit}
|
||||
options={this.state.options}
|
||||
sections={this.props.sections}
|
||||
operators={this.props.operators}
|
||||
datasource={this.props.datasource}
|
||||
onRemoveFilter={() => this.onRemoveFilter(index)}
|
||||
onMoveLabel={this.moveLabel}
|
||||
@ -324,6 +328,8 @@ class AdhocFilterControl extends React.Component {
|
||||
addNewFilterPopoverTrigger(trigger) {
|
||||
return (
|
||||
<AdhocFilterPopoverTrigger
|
||||
operators={this.props.operators}
|
||||
sections={this.props.sections}
|
||||
adhocFilter={new AdhocFilter({})}
|
||||
datasource={this.props.datasource}
|
||||
options={this.state.options}
|
||||
|
@ -46,6 +46,8 @@ const propTypes = {
|
||||
datasource: PropTypes.object,
|
||||
partitionColumn: PropTypes.string,
|
||||
theme: PropTypes.object,
|
||||
sections: PropTypes.arrayOf(PropTypes.string),
|
||||
operators: PropTypes.arrayOf(PropTypes.string),
|
||||
};
|
||||
|
||||
const ResizeIcon = styled.i`
|
||||
@ -54,6 +56,11 @@ const ResizeIcon = styled.i`
|
||||
|
||||
const startingWidth = 320;
|
||||
const startingHeight = 240;
|
||||
const SectionWrapper = styled.div`
|
||||
.ant-select {
|
||||
margin-bottom: ${({ theme }) => theme.gridUnit * 4}px;
|
||||
}
|
||||
`;
|
||||
|
||||
const FilterPopoverContentContainer = styled.div`
|
||||
.adhoc-filter-edit-tabs > .nav-tabs {
|
||||
@ -166,15 +173,51 @@ export default class AdhocFilterEditPopover extends React.Component {
|
||||
onResize,
|
||||
datasource,
|
||||
partitionColumn,
|
||||
sections = ['SIMPLE', 'CUSTOM_SQL'],
|
||||
theme,
|
||||
operators,
|
||||
...popoverProps
|
||||
} = this.props;
|
||||
|
||||
const { adhocFilter } = this.state;
|
||||
|
||||
const resultSections =
|
||||
datasource?.type === 'druid'
|
||||
? sections.filter(s => s !== 'CUSTOM_SQL')
|
||||
: sections;
|
||||
|
||||
const stateIsValid = adhocFilter.isValid();
|
||||
const hasUnsavedChanges = !adhocFilter.equals(propsAdhocFilter);
|
||||
|
||||
const sectionRenders = {};
|
||||
|
||||
sectionRenders.CUSTOM_SQL = (
|
||||
<ErrorBoundary>
|
||||
<AdhocFilterEditPopoverSqlTabContent
|
||||
adhocFilter={this.state.adhocFilter}
|
||||
onChange={this.onAdhocFilterChange}
|
||||
options={this.props.options}
|
||||
height={this.state.height}
|
||||
activeKey={this.state.activeKey}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
|
||||
sectionRenders.SIMPLE = (
|
||||
<ErrorBoundary>
|
||||
<AdhocFilterEditPopoverSimpleTabContent
|
||||
operators={operators}
|
||||
adhocFilter={this.state.adhocFilter}
|
||||
onChange={this.onAdhocFilterChange}
|
||||
options={options}
|
||||
datasource={datasource}
|
||||
onHeightChange={this.adjustHeight}
|
||||
partitionColumn={partitionColumn}
|
||||
popoverRef={this.popoverContentRef.current}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
|
||||
return (
|
||||
<FilterPopoverContentContainer
|
||||
id="filter-edit-popover"
|
||||
@ -182,55 +225,38 @@ export default class AdhocFilterEditPopover extends React.Component {
|
||||
data-test="filter-edit-popover"
|
||||
ref={this.popoverContentRef}
|
||||
>
|
||||
<Tabs
|
||||
id="adhoc-filter-edit-tabs"
|
||||
defaultActiveKey={adhocFilter.expressionType}
|
||||
className="adhoc-filter-edit-tabs"
|
||||
data-test="adhoc-filter-edit-tabs"
|
||||
style={{ minHeight: this.state.height, width: this.state.width }}
|
||||
allowOverflow
|
||||
onChange={this.onTabChange}
|
||||
>
|
||||
<Tabs.TabPane
|
||||
className="adhoc-filter-edit-tab"
|
||||
key={EXPRESSION_TYPES.SIMPLE}
|
||||
tab={t('Simple')}
|
||||
{resultSections.length > 1 ? (
|
||||
<Tabs
|
||||
id="adhoc-filter-edit-tabs"
|
||||
defaultActiveKey={adhocFilter.expressionType}
|
||||
className="adhoc-filter-edit-tabs"
|
||||
data-test="adhoc-filter-edit-tabs"
|
||||
style={{ minHeight: this.state.height, width: this.state.width }}
|
||||
allowOverflow
|
||||
onChange={this.onTabChange}
|
||||
>
|
||||
<ErrorBoundary>
|
||||
<AdhocFilterEditPopoverSimpleTabContent
|
||||
adhocFilter={this.state.adhocFilter}
|
||||
onChange={this.onAdhocFilterChange}
|
||||
options={options}
|
||||
datasource={datasource}
|
||||
onHeightChange={this.adjustHeight}
|
||||
partitionColumn={partitionColumn}
|
||||
popoverRef={this.popoverContentRef.current}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane
|
||||
className="adhoc-filter-edit-tab"
|
||||
key={EXPRESSION_TYPES.SQL}
|
||||
tab={t('Custom SQL')}
|
||||
>
|
||||
<ErrorBoundary>
|
||||
{!this.props.datasource ||
|
||||
this.props.datasource.type !== 'druid' ? (
|
||||
<AdhocFilterEditPopoverSqlTabContent
|
||||
adhocFilter={this.state.adhocFilter}
|
||||
onChange={this.onAdhocFilterChange}
|
||||
options={this.props.options}
|
||||
height={this.state.height}
|
||||
activeKey={this.state.activeKey}
|
||||
/>
|
||||
) : (
|
||||
<div className="custom-sql-disabled-message">
|
||||
Custom SQL Filters are not available on druid datasources
|
||||
</div>
|
||||
)}
|
||||
</ErrorBoundary>
|
||||
</Tabs.TabPane>
|
||||
</Tabs>
|
||||
{resultSections.includes('SIMPLE') && (
|
||||
<Tabs.TabPane
|
||||
className="adhoc-filter-edit-tab"
|
||||
key={EXPRESSION_TYPES.SIMPLE}
|
||||
tab={t('Simple')}
|
||||
>
|
||||
{sectionRenders.SIMPLE}
|
||||
</Tabs.TabPane>
|
||||
)}
|
||||
{resultSections.includes('CUSTOM_SQL') && (
|
||||
<Tabs.TabPane
|
||||
className="adhoc-filter-edit-tab"
|
||||
key={EXPRESSION_TYPES.SQL}
|
||||
tab={t('Custom SQL')}
|
||||
>
|
||||
{sectionRenders.CUSTOM_SQL}
|
||||
</Tabs.TabPane>
|
||||
)}
|
||||
</Tabs>
|
||||
) : (
|
||||
<SectionWrapper>{sectionRenders[resultSections[0]]}</SectionWrapper>
|
||||
)}
|
||||
<div>
|
||||
<Button buttonSize="small" onClick={this.props.onClose} cta>
|
||||
{t('Close')}
|
||||
|
@ -38,6 +38,20 @@ import AdhocFilter, {
|
||||
} from 'src/explore/components/controls/FilterControl/AdhocFilter';
|
||||
import { Input } from 'src/common/components';
|
||||
|
||||
const StyledInput = styled(Input)`
|
||||
margin-bottom: ${({ theme }) => theme.gridUnit * 4}px;
|
||||
`;
|
||||
|
||||
const SelectWithLabel = styled(Select)<{ labelText: string }>`
|
||||
.ant-select-selector::after {
|
||||
content: ${({ labelText }) => labelText || '\\A0'};
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
color: ${({ theme }) => theme.colors.grayscale.light1};
|
||||
width: max-content;
|
||||
}
|
||||
`;
|
||||
|
||||
export interface SimpleColumnType {
|
||||
id: number;
|
||||
column_name: string;
|
||||
@ -81,6 +95,7 @@ export interface Props {
|
||||
filter_select: boolean;
|
||||
};
|
||||
partitionColumn: string;
|
||||
operators?: Operators[];
|
||||
}
|
||||
export const useSimpleTabFilterProps = (props: Props) => {
|
||||
const isOperatorRelevant = (operator: Operators, subject: string) => {
|
||||
@ -280,7 +295,9 @@ const AdhocFilterEditPopoverSimpleTabContent: React.FC<Props> = props => {
|
||||
const operatorSelectProps = {
|
||||
placeholder: t(
|
||||
'%s operator(s)',
|
||||
OPERATORS_OPTIONS.filter(op => isOperatorRelevant(op, subject)).length,
|
||||
(props.operators ?? OPERATORS_OPTIONS).filter(op =>
|
||||
isOperatorRelevant(op, subject),
|
||||
).length,
|
||||
),
|
||||
value: operatorId,
|
||||
onChange: onOperatorChange,
|
||||
@ -310,16 +327,6 @@ const AdhocFilterEditPopoverSimpleTabContent: React.FC<Props> = props => {
|
||||
const labelText =
|
||||
comparator && comparator.length > 0 && createSuggestionsPlaceholder();
|
||||
|
||||
const SelectWithLabel = styled(Select)`
|
||||
.ant-select-selector::after {
|
||||
content: ${() => labelText || '\\A0'};
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
color: ${({ theme }) => theme.colors.grayscale.light1};
|
||||
width: max-content;
|
||||
}
|
||||
`;
|
||||
|
||||
useEffect(() => {
|
||||
const refreshComparatorSuggestions = () => {
|
||||
const { datasource } = props;
|
||||
@ -380,17 +387,18 @@ const AdhocFilterEditPopoverSimpleTabContent: React.FC<Props> = props => {
|
||||
/>
|
||||
<Select
|
||||
css={theme => ({ marginBottom: theme.gridUnit * 4 })}
|
||||
options={OPERATORS_OPTIONS.filter(op =>
|
||||
isOperatorRelevant(op, subject),
|
||||
).map(option => ({
|
||||
value: option,
|
||||
label: OPERATOR_ENUM_TO_OPERATOR_TYPE[option].display,
|
||||
key: option,
|
||||
}))}
|
||||
options={(props.operators ?? OPERATORS_OPTIONS)
|
||||
.filter(op => isOperatorRelevant(op, subject))
|
||||
.map(option => ({
|
||||
value: option,
|
||||
label: OPERATOR_ENUM_TO_OPERATOR_TYPE[option].display,
|
||||
key: option,
|
||||
}))}
|
||||
{...operatorSelectProps}
|
||||
/>
|
||||
{MULTI_OPERATORS.has(operatorId) || suggestions.length > 0 ? (
|
||||
<SelectWithLabel
|
||||
labelText={labelText}
|
||||
options={suggestions.map((suggestion: string) => ({
|
||||
value: suggestion,
|
||||
label: String(suggestion),
|
||||
@ -398,7 +406,7 @@ const AdhocFilterEditPopoverSimpleTabContent: React.FC<Props> = props => {
|
||||
{...comparatorSelectProps}
|
||||
/>
|
||||
) : (
|
||||
<Input
|
||||
<StyledInput
|
||||
data-test="adhoc-filter-simple-value"
|
||||
name="filter-value"
|
||||
ref={ref => {
|
||||
|
@ -36,6 +36,8 @@ const propTypes = {
|
||||
adhocMetricType,
|
||||
]),
|
||||
).isRequired,
|
||||
sections: PropTypes.arrayOf(PropTypes.string),
|
||||
operators: PropTypes.arrayOf(PropTypes.string),
|
||||
datasource: PropTypes.object,
|
||||
partitionColumn: PropTypes.string,
|
||||
onMoveLabel: PropTypes.func,
|
||||
@ -53,8 +55,12 @@ const AdhocFilterOption = ({
|
||||
onMoveLabel,
|
||||
onDropLabel,
|
||||
index,
|
||||
sections,
|
||||
operators,
|
||||
}) => (
|
||||
<AdhocFilterPopoverTrigger
|
||||
sections={sections}
|
||||
operators={operators}
|
||||
adhocFilter={adhocFilter}
|
||||
options={options}
|
||||
datasource={datasource}
|
||||
|
@ -22,8 +22,11 @@ import { OptionSortType } from 'src/explore/types';
|
||||
import AdhocFilterEditPopover from 'src/explore/components/controls/FilterControl/AdhocFilterEditPopover';
|
||||
import AdhocFilter from 'src/explore/components/controls/FilterControl/AdhocFilter';
|
||||
import { ExplorePopoverContent } from 'src/explore/components/ExploreContentPopover';
|
||||
import { Operators } from 'src/explore/constants';
|
||||
|
||||
interface AdhocFilterPopoverTriggerProps {
|
||||
sections?: string[];
|
||||
operators?: Operators[];
|
||||
adhocFilter: AdhocFilter;
|
||||
options: OptionSortType[];
|
||||
datasource: Record<string, any>;
|
||||
@ -90,6 +93,8 @@ class AdhocFilterPopoverTrigger extends React.PureComponent<
|
||||
partitionColumn={this.props.partitionColumn}
|
||||
onResize={this.onPopoverResize}
|
||||
onClose={closePopover}
|
||||
sections={this.props.sections}
|
||||
operators={this.props.operators}
|
||||
onChange={this.props.onFilterEdit}
|
||||
/>
|
||||
</ExplorePopoverContent>
|
||||
|
Loading…
Reference in New Issue
Block a user