mirror of
https://github.com/apache/superset.git
synced 2026-04-20 00:24:38 +00:00
feat(filters-set): basic implementation for managing user filter sets (#13031)
* feat: POC adding filters set feature * lint: fix TS * fix: fix FF name * refactor: fix CR notes * fix: fix update values in filter bar
This commit is contained in:
@@ -19,6 +19,7 @@
|
|||||||
import { NativeFiltersState } from 'src/dashboard/reducers/types';
|
import { NativeFiltersState } from 'src/dashboard/reducers/types';
|
||||||
|
|
||||||
export const nativeFilters: NativeFiltersState = {
|
export const nativeFilters: NativeFiltersState = {
|
||||||
|
filterSets: {},
|
||||||
filters: {
|
filters: {
|
||||||
'NATIVE_FILTER-e7Q8zKixx': {
|
'NATIVE_FILTER-e7Q8zKixx': {
|
||||||
id: 'NATIVE_FILTER-e7Q8zKixx',
|
id: 'NATIVE_FILTER-e7Q8zKixx',
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ describe('getFormDataWithExtraFilters', () => {
|
|||||||
},
|
},
|
||||||
sliceId: chartId,
|
sliceId: chartId,
|
||||||
nativeFilters: {
|
nativeFilters: {
|
||||||
|
filterSets: {},
|
||||||
filters: {
|
filters: {
|
||||||
[filterId]: ({
|
[filterId]: ({
|
||||||
id: filterId,
|
id: filterId,
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import {
|
|||||||
FilterConfiguration,
|
FilterConfiguration,
|
||||||
} from 'src/dashboard/components/nativeFilters/types';
|
} from 'src/dashboard/components/nativeFilters/types';
|
||||||
import { dashboardInfoChanged } from './dashboardInfo';
|
import { dashboardInfoChanged } from './dashboardInfo';
|
||||||
import { CurrentFilterState } from '../reducers/types';
|
import { CurrentFilterState, NativeFilterState } from '../reducers/types';
|
||||||
import { SelectedValues } from '../components/nativeFilters/FilterConfigModal/types';
|
import { SelectedValues } from '../components/nativeFilters/FilterConfigModal/types';
|
||||||
|
|
||||||
export const SET_FILTER_CONFIG_BEGIN = 'SET_FILTER_CONFIG_BEGIN';
|
export const SET_FILTER_CONFIG_BEGIN = 'SET_FILTER_CONFIG_BEGIN';
|
||||||
@@ -103,6 +103,20 @@ export interface SetExtraFormData {
|
|||||||
currentState: CurrentFilterState;
|
currentState: CurrentFilterState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const SAVE_FILTER_SETS = 'SAVE_FILTER_SETS';
|
||||||
|
export interface SaveFilterSets {
|
||||||
|
type: typeof SAVE_FILTER_SETS;
|
||||||
|
name: string;
|
||||||
|
filtersState: NativeFilterState;
|
||||||
|
filtersSetId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SET_FILTERS_STATE = 'SET_FILTERS_STATE';
|
||||||
|
export interface SetFiltersState {
|
||||||
|
type: typeof SET_FILTERS_STATE;
|
||||||
|
filtersState: NativeFilterState;
|
||||||
|
}
|
||||||
|
|
||||||
export function setFilterState(
|
export function setFilterState(
|
||||||
selectedValues: SelectedValues,
|
selectedValues: SelectedValues,
|
||||||
filter: Filter,
|
filter: Filter,
|
||||||
@@ -134,9 +148,33 @@ export function setExtraFormData(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function saveFilterSets(
|
||||||
|
name: string,
|
||||||
|
filtersSetId: string,
|
||||||
|
filtersState: NativeFilterState,
|
||||||
|
): SaveFilterSets {
|
||||||
|
return {
|
||||||
|
type: SAVE_FILTER_SETS,
|
||||||
|
name,
|
||||||
|
filtersSetId,
|
||||||
|
filtersState,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setFiltersState(
|
||||||
|
filtersState: NativeFilterState,
|
||||||
|
): SetFiltersState {
|
||||||
|
return {
|
||||||
|
type: SET_FILTERS_STATE,
|
||||||
|
filtersState,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export type AnyFilterAction =
|
export type AnyFilterAction =
|
||||||
| SetFilterConfigBegin
|
| SetFilterConfigBegin
|
||||||
| SetFilterConfigComplete
|
| SetFilterConfigComplete
|
||||||
| SetFilterConfigFail
|
| SetFilterConfigFail
|
||||||
|
| SetFiltersState
|
||||||
| SetExtraFormData
|
| SetExtraFormData
|
||||||
|
| SaveFilterSets
|
||||||
| SetFilterState;
|
| SetFilterState;
|
||||||
|
|||||||
@@ -16,18 +16,34 @@
|
|||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import { styled, t, ExtraFormData } from '@superset-ui/core';
|
import { styled, t, tn, ExtraFormData } from '@superset-ui/core';
|
||||||
import React, { useState, useEffect, useMemo } from 'react';
|
import React, { useState, useEffect, useMemo, ChangeEvent } from 'react';
|
||||||
import { useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
import Button from 'src/components/Button';
|
import Button from 'src/components/Button';
|
||||||
import Icon from 'src/components/Icon';
|
import Icon from 'src/components/Icon';
|
||||||
import { CurrentFilterState } from 'src/dashboard/reducers/types';
|
import { CurrentFilterState } from 'src/dashboard/reducers/types';
|
||||||
|
import { Input, Select } from 'src/common/components';
|
||||||
|
import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
|
||||||
|
import {
|
||||||
|
saveFilterSets,
|
||||||
|
setFiltersState,
|
||||||
|
} from 'src/dashboard/actions/nativeFilters';
|
||||||
|
import { SelectValue } from 'antd/lib/select';
|
||||||
import FilterConfigurationLink from './FilterConfigurationLink';
|
import FilterConfigurationLink from './FilterConfigurationLink';
|
||||||
import { useFilters, useSetExtraFormData } from './state';
|
import {
|
||||||
|
useFilters,
|
||||||
|
useFilterSets,
|
||||||
|
useFiltersState,
|
||||||
|
useSetExtraFormData,
|
||||||
|
} from './state';
|
||||||
import { useFilterConfiguration } from '../state';
|
import { useFilterConfiguration } from '../state';
|
||||||
import { Filter } from '../types';
|
import { Filter } from '../types';
|
||||||
import { buildCascadeFiltersTree, mapParentFiltersToChildren } from './utils';
|
import {
|
||||||
|
buildCascadeFiltersTree,
|
||||||
|
generateFiltersSetId,
|
||||||
|
mapParentFiltersToChildren,
|
||||||
|
} from './utils';
|
||||||
import CascadePopover from './CascadePopover';
|
import CascadePopover from './CascadePopover';
|
||||||
|
|
||||||
const barWidth = `250px`;
|
const barWidth = `250px`;
|
||||||
@@ -65,6 +81,17 @@ const Bar = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const StyledTitle = styled.h4`
|
||||||
|
width: 100%;
|
||||||
|
font-size: ${({ theme }) => theme.typography.sizes.s}px;
|
||||||
|
color: ${({ theme }) => theme.colors.grayscale.dark1};
|
||||||
|
margin: 0;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
& > .ant-select {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
const CollapsedBar = styled.div`
|
const CollapsedBar = styled.div`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
@@ -102,6 +129,15 @@ const StyledCollapseIcon = styled(Icon)`
|
|||||||
margin-bottom: ${({ theme }) => theme.gridUnit * 3}px;
|
margin-bottom: ${({ theme }) => theme.gridUnit * 3}px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const FilterSet = styled.div`
|
||||||
|
display: grid;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-gap: 10px;
|
||||||
|
padding-top: 10px;
|
||||||
|
`;
|
||||||
|
|
||||||
const TitleArea = styled.h4`
|
const TitleArea = styled.h4`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@@ -152,9 +188,13 @@ const FilterBar: React.FC<FiltersBarProps> = ({
|
|||||||
currentState: CurrentFilterState;
|
currentState: CurrentFilterState;
|
||||||
};
|
};
|
||||||
}>({});
|
}>({});
|
||||||
|
const dispatch = useDispatch();
|
||||||
const setExtraFormData = useSetExtraFormData();
|
const setExtraFormData = useSetExtraFormData();
|
||||||
|
const filtersState = useFiltersState();
|
||||||
|
const filterSets = useFilterSets();
|
||||||
const filterConfigs = useFilterConfiguration();
|
const filterConfigs = useFilterConfiguration();
|
||||||
const filters = useFilters();
|
const filters = useFilters();
|
||||||
|
const [filtersSetName, setFiltersSetName] = useState('');
|
||||||
const canEdit = useSelector<any, boolean>(
|
const canEdit = useSelector<any, boolean>(
|
||||||
({ dashboardInfo }) => dashboardInfo.dash_edit_perm,
|
({ dashboardInfo }) => dashboardInfo.dash_edit_perm,
|
||||||
);
|
);
|
||||||
@@ -218,6 +258,17 @@ const FilterBar: React.FC<FiltersBarProps> = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSaveFilterSets = () => {
|
||||||
|
dispatch(
|
||||||
|
saveFilterSets(
|
||||||
|
filtersSetName.trim(),
|
||||||
|
generateFiltersSetId(),
|
||||||
|
filtersState,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
setFiltersSetName('');
|
||||||
|
};
|
||||||
|
|
||||||
const handleResetAll = () => {
|
const handleResetAll = () => {
|
||||||
filterConfigs.forEach(filter => {
|
filterConfigs.forEach(filter => {
|
||||||
setExtraFormData(filter.id, filterData[filter.id]?.extraFormData, {
|
setExtraFormData(filter.id, filterData[filter.id]?.extraFormData, {
|
||||||
@@ -227,6 +278,10 @@ const FilterBar: React.FC<FiltersBarProps> = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const takeFiltersSet = (value: SelectValue) => {
|
||||||
|
dispatch(setFiltersState(filterSets[String(value)]?.filtersState));
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BarWrapper data-test="filter-bar" className={cx({ open: filtersOpen })}>
|
<BarWrapper data-test="filter-bar" className={cx({ open: filtersOpen })}>
|
||||||
<CollapsedBar
|
<CollapsedBar
|
||||||
@@ -269,6 +324,50 @@ const FilterBar: React.FC<FiltersBarProps> = ({
|
|||||||
{t('Apply')}
|
{t('Apply')}
|
||||||
</Button>
|
</Button>
|
||||||
</ActionButtons>
|
</ActionButtons>
|
||||||
|
{isFeatureEnabled(FeatureFlag.DASHBOARD_NATIVE_FILTERS_SET) && (
|
||||||
|
<ActionButtons>
|
||||||
|
<FilterSet>
|
||||||
|
<StyledTitle>
|
||||||
|
<div>{t('Choose filters set')}</div>
|
||||||
|
<Select
|
||||||
|
size="small"
|
||||||
|
allowClear
|
||||||
|
placeholder={tn(
|
||||||
|
'Available %d sets',
|
||||||
|
Object.keys(filterSets).length,
|
||||||
|
)}
|
||||||
|
onChange={takeFiltersSet}
|
||||||
|
>
|
||||||
|
{Object.values(filterSets).map(({ name, id }) => (
|
||||||
|
<Select.Option value={id}>{name}</Select.Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</StyledTitle>
|
||||||
|
<StyledTitle>
|
||||||
|
<div>{t('Name')}</div>
|
||||||
|
<Input
|
||||||
|
size="small"
|
||||||
|
placeholder={t('Enter filter set name')}
|
||||||
|
value={filtersSetName}
|
||||||
|
onChange={({
|
||||||
|
target: { value },
|
||||||
|
}: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setFiltersSetName(value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</StyledTitle>
|
||||||
|
<Button
|
||||||
|
buttonStyle="secondary"
|
||||||
|
buttonSize="small"
|
||||||
|
disabled={filtersSetName.trim() === ''}
|
||||||
|
onClick={handleSaveFilterSets}
|
||||||
|
data-test="filter-save-filters-set-button"
|
||||||
|
>
|
||||||
|
{t('Save Filters Set')}
|
||||||
|
</Button>
|
||||||
|
</FilterSet>
|
||||||
|
</ActionButtons>
|
||||||
|
)}
|
||||||
<FilterControls>
|
<FilterControls>
|
||||||
{cascadeFilters.map(filter => (
|
{cascadeFilters.map(filter => (
|
||||||
<CascadePopover
|
<CascadePopover
|
||||||
|
|||||||
@@ -66,12 +66,12 @@ const FilterValue: React.FC<FilterProps> = ({
|
|||||||
const [loading, setLoading] = useState<boolean>(hasDataSource);
|
const [loading, setLoading] = useState<boolean>(hasDataSource);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const newFormData = getFormData({
|
const newFormData = getFormData({
|
||||||
|
...filter,
|
||||||
datasetId,
|
datasetId,
|
||||||
cascadingFilters,
|
cascadingFilters,
|
||||||
groupby,
|
groupby,
|
||||||
currentValue,
|
currentValue,
|
||||||
inputRef,
|
inputRef,
|
||||||
...filter,
|
|
||||||
});
|
});
|
||||||
if (!areObjectsEqual(formData || {}, newFormData)) {
|
if (!areObjectsEqual(formData || {}, newFormData)) {
|
||||||
setFormData(newFormData);
|
setFormData(newFormData);
|
||||||
|
|||||||
@@ -25,12 +25,24 @@ import {
|
|||||||
CurrentFilterState,
|
CurrentFilterState,
|
||||||
NativeFilterState,
|
NativeFilterState,
|
||||||
NativeFiltersState,
|
NativeFiltersState,
|
||||||
|
FilterSets,
|
||||||
} from 'src/dashboard/reducers/types';
|
} from 'src/dashboard/reducers/types';
|
||||||
import { mergeExtraFormData } from '../utils';
|
import { mergeExtraFormData } from '../utils';
|
||||||
|
import { Filter } from '../types';
|
||||||
|
|
||||||
export function useFilters() {
|
export function useFilters() {
|
||||||
|
return useSelector<any, Filter>(state => state.nativeFilters.filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useFiltersState() {
|
||||||
return useSelector<any, NativeFilterState>(
|
return useSelector<any, NativeFilterState>(
|
||||||
state => state.nativeFilters.filters,
|
state => state.nativeFilters.filtersState,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useFilterSets() {
|
||||||
|
return useSelector<any, FilterSets>(
|
||||||
|
state => state.nativeFilters.filterSets ?? {},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import shortid from 'shortid';
|
||||||
import { Filter } from '../types';
|
import { Filter } from '../types';
|
||||||
import { CascadeFilter } from './types';
|
import { CascadeFilter } from './types';
|
||||||
|
|
||||||
@@ -51,3 +52,5 @@ export function buildCascadeFiltersTree(filters: Filter[]): CascadeFilter[] {
|
|||||||
.filter(filter => !filter.cascadeParentIds?.length)
|
.filter(filter => !filter.cascadeParentIds?.length)
|
||||||
.map(getCascadeFilter);
|
.map(getCascadeFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const generateFiltersSetId = () => `FILTERS_SET-${shortid.generate()}`;
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ export const getFormData = ({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
...controlValues,
|
||||||
|
...otherProps,
|
||||||
adhoc_filters: [],
|
adhoc_filters: [],
|
||||||
extra_filters: [],
|
extra_filters: [],
|
||||||
extra_form_data: cascadingFilters,
|
extra_form_data: cascadingFilters,
|
||||||
@@ -66,8 +68,6 @@ export const getFormData = ({
|
|||||||
url_params: {},
|
url_params: {},
|
||||||
viz_type: filterType,
|
viz_type: filterType,
|
||||||
inputRef,
|
inputRef,
|
||||||
...controlValues,
|
|
||||||
...otherProps,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,11 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import {
|
import {
|
||||||
SET_EXTRA_FORM_DATA,
|
|
||||||
AnyFilterAction,
|
AnyFilterAction,
|
||||||
|
SAVE_FILTER_SETS,
|
||||||
|
SET_EXTRA_FORM_DATA,
|
||||||
SET_FILTER_CONFIG_COMPLETE,
|
SET_FILTER_CONFIG_COMPLETE,
|
||||||
|
SET_FILTERS_STATE,
|
||||||
} from 'src/dashboard/actions/nativeFilters';
|
} from 'src/dashboard/actions/nativeFilters';
|
||||||
import { NativeFiltersState, NativeFilterState } from './types';
|
import { NativeFiltersState, NativeFilterState } from './types';
|
||||||
import { FilterConfiguration } from '../components/nativeFilters/types';
|
import { FilterConfiguration } from '../components/nativeFilters/types';
|
||||||
@@ -33,27 +35,33 @@ export function getInitialFilterState(id: string): NativeFilterState {
|
|||||||
|
|
||||||
export function getInitialState(
|
export function getInitialState(
|
||||||
filterConfig: FilterConfiguration,
|
filterConfig: FilterConfiguration,
|
||||||
prevFiltersState: { [filterId: string]: NativeFilterState },
|
prevState: NativeFiltersState,
|
||||||
): NativeFiltersState {
|
): NativeFiltersState {
|
||||||
const filters = {};
|
const filters = {};
|
||||||
const filtersState = {};
|
const filtersState = {};
|
||||||
const state = { filters, filtersState };
|
const state = {
|
||||||
|
filters,
|
||||||
|
filtersState,
|
||||||
|
filterSets: prevState?.filterSets ?? {},
|
||||||
|
};
|
||||||
filterConfig.forEach(filter => {
|
filterConfig.forEach(filter => {
|
||||||
const { id } = filter;
|
const { id } = filter;
|
||||||
filters[id] = filter;
|
filters[id] = filter;
|
||||||
filtersState[id] = prevFiltersState?.[id] || getInitialFilterState(id);
|
filtersState[id] =
|
||||||
|
prevState?.filtersState?.[id] || getInitialFilterState(id);
|
||||||
});
|
});
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function nativeFilterReducer(
|
export default function nativeFilterReducer(
|
||||||
state: NativeFiltersState = { filters: {}, filtersState: {} },
|
state: NativeFiltersState = { filters: {}, filtersState: {}, filterSets: {} },
|
||||||
action: AnyFilterAction,
|
action: AnyFilterAction,
|
||||||
) {
|
) {
|
||||||
const { filters, filtersState } = state;
|
const { filters, filtersState, filterSets } = state;
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case SET_EXTRA_FORM_DATA:
|
case SET_EXTRA_FORM_DATA:
|
||||||
return {
|
return {
|
||||||
|
...state,
|
||||||
filters,
|
filters,
|
||||||
filtersState: {
|
filtersState: {
|
||||||
...filtersState,
|
...filtersState,
|
||||||
@@ -64,9 +72,29 @@ export default function nativeFilterReducer(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
case SAVE_FILTER_SETS:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
filterSets: {
|
||||||
|
...filterSets,
|
||||||
|
[action.filtersSetId]: {
|
||||||
|
id: action.filtersSetId,
|
||||||
|
name: action.name,
|
||||||
|
filtersState: action.filtersState,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
case SET_FILTERS_STATE:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
filtersState: {
|
||||||
|
...filtersState,
|
||||||
|
...action.filtersState,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
case SET_FILTER_CONFIG_COMPLETE:
|
case SET_FILTER_CONFIG_COMPLETE:
|
||||||
return getInitialState(action.filterConfig, filtersState);
|
return getInitialState(action.filterConfig, state);
|
||||||
|
|
||||||
// TODO handle SET_FILTER_CONFIG_FAIL action
|
// TODO handle SET_FILTER_CONFIG_FAIL action
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -79,10 +79,21 @@ export type NativeFilterState = {
|
|||||||
currentState?: CurrentFilterState;
|
currentState?: CurrentFilterState;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type FiltersSet = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
filtersState: NativeFilterState;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type FilterSets = {
|
||||||
|
[filtersSetId: string]: FiltersSet;
|
||||||
|
};
|
||||||
|
|
||||||
export type NativeFiltersState = {
|
export type NativeFiltersState = {
|
||||||
filters: {
|
filters: {
|
||||||
[filterId: string]: Filter;
|
[filterId: string]: Filter;
|
||||||
};
|
};
|
||||||
|
filterSets: FilterSets;
|
||||||
filtersState: {
|
filtersState: {
|
||||||
[filterId: string]: NativeFilterState;
|
[filterId: string]: NativeFilterState;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ export enum FeatureFlag {
|
|||||||
ESCAPE_MARKDOWN_HTML = 'ESCAPE_MARKDOWN_HTML',
|
ESCAPE_MARKDOWN_HTML = 'ESCAPE_MARKDOWN_HTML',
|
||||||
DASHBOARD_NATIVE_FILTERS = 'DASHBOARD_NATIVE_FILTERS',
|
DASHBOARD_NATIVE_FILTERS = 'DASHBOARD_NATIVE_FILTERS',
|
||||||
DASHBOARD_CROSS_FILTERS = 'DASHBOARD_CROSS_FILTERS',
|
DASHBOARD_CROSS_FILTERS = 'DASHBOARD_CROSS_FILTERS',
|
||||||
|
DASHBOARD_NATIVE_FILTERS_SET = 'DASHBOARD_NATIVE_FILTERS_SET',
|
||||||
VERSIONED_EXPORT = 'VERSIONED_EXPORT',
|
VERSIONED_EXPORT = 'VERSIONED_EXPORT',
|
||||||
GLOBAL_ASYNC_QUERIES = 'GLOBAL_ASYNC_QUERIES',
|
GLOBAL_ASYNC_QUERIES = 'GLOBAL_ASYNC_QUERIES',
|
||||||
ENABLE_TEMPLATE_PROCESSING = 'ENABLE_TEMPLATE_PROCESSING',
|
ENABLE_TEMPLATE_PROCESSING = 'ENABLE_TEMPLATE_PROCESSING',
|
||||||
|
|||||||
@@ -329,6 +329,7 @@ DEFAULT_FEATURE_FLAGS: Dict[str, bool] = {
|
|||||||
"ESCAPE_MARKDOWN_HTML": False,
|
"ESCAPE_MARKDOWN_HTML": False,
|
||||||
"DASHBOARD_NATIVE_FILTERS": False,
|
"DASHBOARD_NATIVE_FILTERS": False,
|
||||||
"DASHBOARD_CROSS_FILTERS": False,
|
"DASHBOARD_CROSS_FILTERS": False,
|
||||||
|
"DASHBOARD_NATIVE_FILTERS_SET": False,
|
||||||
"GLOBAL_ASYNC_QUERIES": False,
|
"GLOBAL_ASYNC_QUERIES": False,
|
||||||
"VERSIONED_EXPORT": False,
|
"VERSIONED_EXPORT": False,
|
||||||
# Note that: RowLevelSecurityFilter is only given by default to the Admin role
|
# Note that: RowLevelSecurityFilter is only given by default to the Admin role
|
||||||
|
|||||||
Reference in New Issue
Block a user