mirror of https://github.com/apache/superset.git
feat: Dynamic dashboard component (#17208)
* fix:fix get permission function * feat: dynamic loading of dashboard components * fix: revert image * fix: fix py * fix: fix py * fix: pass state to dynamic component * lint: add typing * lint: fix lint * lint: fix lint * refactor: re-run pipeline * fix: fix CR notes * fix: fix CR notes * move types and interfaces to core * reorder exports * rename Scope and Target Co-authored-by: Ville Brofeldt <ville.v.brofeldt@gmail.com>
This commit is contained in:
parent
5ee070c402
commit
bcad1acec2
|
@ -16,14 +16,5 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { DataMask } from '@superset-ui/core';
|
||||
|
||||
export enum DataMaskType {
|
||||
NativeFilters = 'nativeFilters',
|
||||
CrossFilters = 'crossFilters',
|
||||
}
|
||||
|
||||
export type DataMaskState = { [id: string]: DataMask };
|
||||
|
||||
export type DataMaskWithId = { id: string } & DataMask;
|
||||
export type DataMaskStateWithId = { [filterId: string]: DataMaskWithId };
|
||||
export * from './types/Base';
|
|
@ -19,20 +19,20 @@
|
|||
|
||||
import { AdhocFilter, DataMask } from '@superset-ui/core';
|
||||
|
||||
export interface Column {
|
||||
export interface NativeFilterColumn {
|
||||
name: string;
|
||||
displayName?: string;
|
||||
}
|
||||
|
||||
export interface Scope {
|
||||
export interface NativeFilterScope {
|
||||
rootPath: string[];
|
||||
excluded: number[];
|
||||
}
|
||||
|
||||
/** The target of a filter is the datasource/column being filtered */
|
||||
export interface Target {
|
||||
export interface NativeFilterTarget {
|
||||
datasetId: number;
|
||||
column: Column;
|
||||
column: NativeFilterColumn;
|
||||
|
||||
// maybe someday support this?
|
||||
// show values from these columns in the filter options selector
|
||||
|
@ -44,16 +44,37 @@ export enum NativeFilterType {
|
|||
DIVIDER = 'DIVIDER',
|
||||
}
|
||||
|
||||
export enum DataMaskType {
|
||||
NativeFilters = 'nativeFilters',
|
||||
CrossFilters = 'crossFilters',
|
||||
}
|
||||
|
||||
export type DataMaskState = { [id: string]: DataMask };
|
||||
|
||||
export type DataMaskWithId = { id: string } & DataMask;
|
||||
export type DataMaskStateWithId = { [filterId: string]: DataMaskWithId };
|
||||
|
||||
export type FilterSet = {
|
||||
id: number;
|
||||
name: string;
|
||||
nativeFilters: Filters;
|
||||
dataMask: DataMaskStateWithId;
|
||||
};
|
||||
|
||||
export type FilterSets = {
|
||||
[filtersSetId: string]: FilterSet;
|
||||
};
|
||||
|
||||
export interface Filter {
|
||||
cascadeParentIds: string[];
|
||||
defaultDataMask: DataMask;
|
||||
id: string; // randomly generated at filter creation
|
||||
name: string;
|
||||
scope: Scope;
|
||||
scope: NativeFilterScope;
|
||||
filterType: string;
|
||||
// for now there will only ever be one target
|
||||
// when multiple targets are supported, change this to Target[]
|
||||
targets: [Partial<Target>];
|
||||
targets: [Partial<NativeFilterTarget>];
|
||||
controlValues: {
|
||||
[key: string]: any;
|
||||
};
|
||||
|
@ -70,6 +91,7 @@ export interface Filter {
|
|||
type: typeof NativeFilterType.NATIVE_FILTER;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export interface Divider {
|
||||
id: string;
|
||||
title: string;
|
||||
|
@ -78,3 +100,18 @@ export interface Divider {
|
|||
}
|
||||
|
||||
export type FilterConfiguration = Array<Filter | Divider>;
|
||||
|
||||
export type Filters = {
|
||||
[filterId: string]: Filter;
|
||||
};
|
||||
|
||||
export type NativeFiltersState = {
|
||||
filters: Filters;
|
||||
filterSets: FilterSets;
|
||||
focusedFilterId?: string;
|
||||
};
|
||||
|
||||
export type DashboardComponentMetadata = {
|
||||
nativeFilters: NativeFiltersState;
|
||||
dataMask: DataMaskStateWithId;
|
||||
};
|
|
@ -16,11 +16,13 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
export * from './models';
|
||||
export * from './utils';
|
||||
export * from './types';
|
||||
export * from './translation';
|
||||
export * from './connection';
|
||||
export * from './dashboard';
|
||||
export * from './dynamic-plugins';
|
||||
export * from './query';
|
||||
export * from './number-format';
|
||||
|
|
|
@ -16,10 +16,12 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { ExtraFormData } from '@superset-ui/core';
|
||||
import { NativeFilterType } from 'src/dashboard/components/nativeFilters/types';
|
||||
import { NativeFiltersState } from 'src/dashboard/reducers/types';
|
||||
import { DataMaskStateWithId } from '../../src/dataMask/types';
|
||||
import {
|
||||
DataMaskStateWithId,
|
||||
ExtraFormData,
|
||||
NativeFiltersState,
|
||||
NativeFilterType,
|
||||
} from '@superset-ui/core';
|
||||
|
||||
export const nativeFilters: NativeFiltersState = {
|
||||
filterSets: {},
|
||||
|
|
|
@ -17,21 +17,21 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { makeApi } from '@superset-ui/core';
|
||||
import {
|
||||
FilterConfiguration,
|
||||
Filters,
|
||||
FilterSet,
|
||||
FilterSets,
|
||||
makeApi,
|
||||
} from '@superset-ui/core';
|
||||
import { Dispatch } from 'redux';
|
||||
import { FilterConfiguration } from 'src/dashboard/components/nativeFilters/types';
|
||||
import {
|
||||
SET_DATA_MASK_FOR_FILTER_CONFIG_FAIL,
|
||||
setDataMaskForFilterConfigComplete,
|
||||
} from 'src/dataMask/actions';
|
||||
import { HYDRATE_DASHBOARD } from './hydrate';
|
||||
import { dashboardInfoChanged } from './dashboardInfo';
|
||||
import {
|
||||
Filters,
|
||||
FilterSet,
|
||||
FilterSetFullData,
|
||||
FilterSets,
|
||||
} from '../reducers/types';
|
||||
import { FilterSetFullData } from '../reducers/types';
|
||||
import { DashboardInfo, RootState } from '../types';
|
||||
|
||||
export const SET_FILTER_CONFIG_BEGIN = 'SET_FILTER_CONFIG_BEGIN';
|
||||
|
|
|
@ -31,6 +31,8 @@ import NewRow from './gridComponents/new/NewRow';
|
|||
import NewTabs from './gridComponents/new/NewTabs';
|
||||
import NewMarkdown from './gridComponents/new/NewMarkdown';
|
||||
import SliceAdder from '../containers/SliceAdder';
|
||||
import dashboardComponents from '../../visualizations/presets/dashboardComponents';
|
||||
import NewDynamicComponent from './gridComponents/new/NewDynamicComponent';
|
||||
|
||||
export interface BCPProps {
|
||||
isStandalone: boolean;
|
||||
|
@ -106,6 +108,14 @@ const BuilderComponentPane: React.FC<BCPProps> = ({
|
|||
<NewHeader />
|
||||
<NewMarkdown />
|
||||
<NewDivider />
|
||||
{dashboardComponents
|
||||
.getAll()
|
||||
.map(({ key: componentKey, metadata }) => (
|
||||
<NewDynamicComponent
|
||||
metadata={metadata}
|
||||
componentKey={componentKey}
|
||||
/>
|
||||
))}
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane
|
||||
key={2}
|
||||
|
|
|
@ -18,15 +18,15 @@
|
|||
*/
|
||||
import React, { FC } from 'react';
|
||||
import { FormInstance } from 'antd/lib/form';
|
||||
import { NativeFilterScope } from '@superset-ui/core';
|
||||
import FilterScope from 'src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope';
|
||||
import { setCrossFilterFieldValues } from 'src/dashboard/components/CrossFilterScopingModal/utils';
|
||||
import { Scope } from 'src/dashboard/components/nativeFilters/types';
|
||||
import { useForceUpdate } from 'src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/utils';
|
||||
import { CrossFilterScopingFormType } from 'src/dashboard/components/CrossFilterScopingModal/types';
|
||||
|
||||
type CrossFilterScopingFormProps = {
|
||||
chartId: number;
|
||||
scope: Scope;
|
||||
scope: NativeFilterScope;
|
||||
form: FormInstance<CrossFilterScopingFormType>;
|
||||
};
|
||||
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { Scope } from '../nativeFilters/types';
|
||||
import { NativeFilterScope } from '@superset-ui/core';
|
||||
|
||||
export type CrossFilterScopingFormType = {
|
||||
scope: Scope;
|
||||
scope: NativeFilterScope;
|
||||
};
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
// when its container size changes, due to e.g., builder side panel opening
|
||||
import React, { FC, useEffect, useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { FeatureFlag, isFeatureEnabled } from '@superset-ui/core';
|
||||
import { FeatureFlag, Filters, isFeatureEnabled } from '@superset-ui/core';
|
||||
import { ParentSize } from '@vx/responsive';
|
||||
import Tabs from 'src/components/Tabs';
|
||||
import DashboardGrid from 'src/dashboard/containers/DashboardGrid';
|
||||
|
@ -31,7 +31,6 @@ import {
|
|||
DASHBOARD_ROOT_DEPTH,
|
||||
} from 'src/dashboard/util/constants';
|
||||
import { getRootLevelTabIndex, getRootLevelTabsComponent } from './utils';
|
||||
import { Filters } from '../../reducers/types';
|
||||
import { getChartIdsInFilterScope } from '../../util/activeDashboardFilters';
|
||||
import findTabIndexByComponentId from '../../util/findTabIndexByComponentId';
|
||||
import { findTabsWithChartsInScope } from '../nativeFilters/utils';
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
import { useSelector } from 'react-redux';
|
||||
import { Filter } from '@superset-ui/core';
|
||||
import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
|
||||
import { useCallback, useEffect, useState, useContext } from 'react';
|
||||
import { URL_PARAMS } from 'src/constants';
|
||||
|
@ -27,7 +28,6 @@ import {
|
|||
useFilters,
|
||||
useNativeFiltersDataMask,
|
||||
} from '../nativeFilters/FilterBar/state';
|
||||
import { Filter } from '../nativeFilters/types';
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export const useNativeFilters = () => {
|
||||
|
|
|
@ -20,9 +20,9 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { uniqWith } from 'lodash';
|
||||
import cx from 'classnames';
|
||||
import { DataMaskStateWithId, Filters } from '@superset-ui/core';
|
||||
import Icons from 'src/components/Icons';
|
||||
import { usePrevious } from 'src/hooks/usePrevious';
|
||||
import { DataMaskStateWithId } from 'src/dataMask/types';
|
||||
import DetailsPanelPopover from './DetailsPanel';
|
||||
import { Pill } from './Styles';
|
||||
import {
|
||||
|
@ -38,7 +38,6 @@ import {
|
|||
DashboardLayout,
|
||||
RootState,
|
||||
} from '../../types';
|
||||
import { Filters } from '../../reducers/types';
|
||||
|
||||
export interface FiltersBadgeProps {
|
||||
chartId: number;
|
||||
|
|
|
@ -17,19 +17,21 @@
|
|||
* under the License.
|
||||
*/
|
||||
import {
|
||||
DataMaskStateWithId,
|
||||
DataMaskType,
|
||||
ensureIsArray,
|
||||
FeatureFlag,
|
||||
Filters,
|
||||
FilterState,
|
||||
isFeatureEnabled,
|
||||
NativeFilterType,
|
||||
} from '@superset-ui/core';
|
||||
import { NO_TIME_RANGE, TIME_FILTER_MAP } from 'src/explore/constants';
|
||||
import { getChartIdsInFilterScope } from 'src/dashboard/util/activeDashboardFilters';
|
||||
import { ChartConfiguration, Filters } from 'src/dashboard/reducers/types';
|
||||
import { DataMaskStateWithId, DataMaskType } from 'src/dataMask/types';
|
||||
import { ChartConfiguration } from 'src/dashboard/reducers/types';
|
||||
import { areObjectsEqual } from 'src/reduxUtils';
|
||||
import { Layout } from '../../types';
|
||||
import { getTreeCheckedItems } from '../nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/utils';
|
||||
import { NativeFilterType } from '../nativeFilters/types';
|
||||
|
||||
export enum IndicatorStatus {
|
||||
Unset = 'UNSET',
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import React, { FC, Suspense } from 'react';
|
||||
import { DashboardComponentMetadata, JsonObject, t } from '@superset-ui/core';
|
||||
import backgroundStyleOptions from 'src/dashboard/util/backgroundStyleOptions';
|
||||
import cx from 'classnames';
|
||||
import { useSelector } from 'react-redux';
|
||||
import DragDroppable from '../dnd/DragDroppable';
|
||||
import { COLUMN_TYPE, ROW_TYPE } from '../../util/componentTypes';
|
||||
import WithPopoverMenu from '../menu/WithPopoverMenu';
|
||||
import ResizableContainer from '../resizable/ResizableContainer';
|
||||
import {
|
||||
BACKGROUND_TRANSPARENT,
|
||||
GRID_BASE_UNIT,
|
||||
GRID_MIN_COLUMN_COUNT,
|
||||
} from '../../util/constants';
|
||||
import HoverMenu from '../menu/HoverMenu';
|
||||
import DeleteComponentButton from '../DeleteComponentButton';
|
||||
import BackgroundStyleDropdown from '../menu/BackgroundStyleDropdown';
|
||||
import dashboardComponents from '../../../visualizations/presets/dashboardComponents';
|
||||
import { RootState } from '../../types';
|
||||
|
||||
type FilterSummaryType = {
|
||||
component: JsonObject;
|
||||
parentComponent: JsonObject;
|
||||
index: number;
|
||||
depth: number;
|
||||
handleComponentDrop: (...args: any[]) => any;
|
||||
editMode: boolean;
|
||||
columnWidth: number;
|
||||
availableColumnCount: number;
|
||||
onResizeStart: Function;
|
||||
onResizeStop: Function;
|
||||
onResize: Function;
|
||||
deleteComponent: Function;
|
||||
updateComponents: Function;
|
||||
parentId: number;
|
||||
id: number;
|
||||
};
|
||||
|
||||
const DynamicComponent: FC<FilterSummaryType> = ({
|
||||
component,
|
||||
parentComponent,
|
||||
index,
|
||||
depth,
|
||||
handleComponentDrop,
|
||||
editMode,
|
||||
columnWidth,
|
||||
availableColumnCount,
|
||||
onResizeStart,
|
||||
onResizeStop,
|
||||
onResize,
|
||||
deleteComponent,
|
||||
parentId,
|
||||
updateComponents,
|
||||
id,
|
||||
}) => {
|
||||
// inherit the size of parent columns
|
||||
const widthMultiple =
|
||||
parentComponent.type === COLUMN_TYPE
|
||||
? parentComponent.meta.width || GRID_MIN_COLUMN_COUNT
|
||||
: component.meta.width || GRID_MIN_COLUMN_COUNT;
|
||||
|
||||
const handleDeleteComponent = () => {
|
||||
deleteComponent(id, parentId);
|
||||
};
|
||||
|
||||
const rowStyle = backgroundStyleOptions.find(
|
||||
opt => opt.value === (component.meta.background || BACKGROUND_TRANSPARENT),
|
||||
);
|
||||
|
||||
const updateMeta = (metaKey: string, nextValue: string | number) => {
|
||||
updateComponents({
|
||||
[component.id]: {
|
||||
...component,
|
||||
meta: {
|
||||
...component.meta,
|
||||
[metaKey]: nextValue,
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const { Component } = dashboardComponents.get(component.meta.componentKey);
|
||||
const dashboardData = useSelector<RootState, DashboardComponentMetadata>(
|
||||
({ nativeFilters, dataMask }) => ({
|
||||
nativeFilters,
|
||||
dataMask,
|
||||
}),
|
||||
);
|
||||
|
||||
return (
|
||||
<DragDroppable
|
||||
// @ts-ignore
|
||||
component={component}
|
||||
// @ts-ignore
|
||||
parentComponent={parentComponent}
|
||||
orientation={parentComponent.type === ROW_TYPE ? 'column' : 'row'}
|
||||
index={index}
|
||||
depth={depth}
|
||||
onDrop={handleComponentDrop}
|
||||
editMode={editMode}
|
||||
>
|
||||
{({ dropIndicatorProps, dragSourceRef }) => (
|
||||
<WithPopoverMenu
|
||||
menuItems={[
|
||||
<BackgroundStyleDropdown
|
||||
id={`${component.id}-background`}
|
||||
value={component.meta.background}
|
||||
onChange={value => updateMeta('background', value)}
|
||||
/>,
|
||||
]}
|
||||
editMode={editMode}
|
||||
>
|
||||
<div
|
||||
data-test={`dashboard-${component.componentKey}`}
|
||||
className={cx(
|
||||
'dashboard-component',
|
||||
`dashboard-${component.componentKey}`,
|
||||
rowStyle?.className,
|
||||
)}
|
||||
id={component.id}
|
||||
>
|
||||
<ResizableContainer
|
||||
id={component.id}
|
||||
adjustableWidth={parentComponent.type === ROW_TYPE}
|
||||
widthStep={columnWidth}
|
||||
widthMultiple={widthMultiple}
|
||||
heightStep={GRID_BASE_UNIT}
|
||||
adjustableHeight={false}
|
||||
heightMultiple={component.meta.height}
|
||||
minWidthMultiple={GRID_MIN_COLUMN_COUNT}
|
||||
minHeightMultiple={GRID_MIN_COLUMN_COUNT}
|
||||
maxWidthMultiple={availableColumnCount + widthMultiple}
|
||||
onResizeStart={onResizeStart}
|
||||
onResize={onResize}
|
||||
onResizeStop={onResizeStop}
|
||||
>
|
||||
<div
|
||||
ref={dragSourceRef}
|
||||
className="dashboard-component"
|
||||
data-test="dashboard-component-chart-holder"
|
||||
>
|
||||
{editMode && (
|
||||
<HoverMenu position="top">
|
||||
<DeleteComponentButton onDelete={handleDeleteComponent} />
|
||||
</HoverMenu>
|
||||
)}
|
||||
<Suspense fallback={<div>{t('Loading...')}</div>}>
|
||||
<Component dashboardData={dashboardData} />
|
||||
</Suspense>
|
||||
</div>
|
||||
</ResizableContainer>
|
||||
</div>
|
||||
{dropIndicatorProps && <div {...dropIndicatorProps} />}
|
||||
</WithPopoverMenu>
|
||||
)}
|
||||
</DragDroppable>
|
||||
);
|
||||
};
|
||||
export default DynamicComponent;
|
|
@ -25,6 +25,7 @@ import {
|
|||
ROW_TYPE,
|
||||
TAB_TYPE,
|
||||
TABS_TYPE,
|
||||
DYNAMIC_TYPE,
|
||||
} from '../../util/componentTypes';
|
||||
|
||||
import ChartHolder from './ChartHolder';
|
||||
|
@ -35,6 +36,7 @@ import Header from './Header';
|
|||
import Row from './Row';
|
||||
import Tab from './Tab';
|
||||
import TabsConnected from './Tabs';
|
||||
import DynamicComponent from './DynamicComponent';
|
||||
|
||||
export { default as ChartHolder } from './ChartHolder';
|
||||
export { default as Markdown } from './Markdown';
|
||||
|
@ -44,6 +46,7 @@ export { default as Header } from './Header';
|
|||
export { default as Row } from './Row';
|
||||
export { default as Tab } from './Tab';
|
||||
export { default as Tabs } from './Tabs';
|
||||
export { default as DynamicComponent } from './DynamicComponent';
|
||||
|
||||
export const componentLookup = {
|
||||
[CHART_TYPE]: ChartHolder,
|
||||
|
@ -54,4 +57,5 @@ export const componentLookup = {
|
|||
[ROW_TYPE]: Row,
|
||||
[TAB_TYPE]: Tab,
|
||||
[TABS_TYPE]: TabsConnected,
|
||||
[DYNAMIC_TYPE]: DynamicComponent,
|
||||
};
|
||||
|
|
|
@ -37,10 +37,10 @@ const defaultProps = {
|
|||
|
||||
export default class DraggableNewComponent extends React.PureComponent {
|
||||
render() {
|
||||
const { label, id, type, className } = this.props;
|
||||
const { label, id, type, className, meta } = this.props;
|
||||
return (
|
||||
<DragDroppable
|
||||
component={{ type, id }}
|
||||
component={{ type, id, meta }}
|
||||
parentComponent={{
|
||||
id: NEW_COMPONENTS_SOURCE_ID,
|
||||
type: NEW_COMPONENT_SOURCE_TYPE,
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import React, { FC } from 'react';
|
||||
import DraggableNewComponent from './DraggableNewComponent';
|
||||
import { DYNAMIC_TYPE } from '../../../util/componentTypes';
|
||||
import { NEW_DYNAMIC_COMPONENT } from '../../../util/constants';
|
||||
import { DashboardComponentsRegistryMetadata } from '../../../../visualizations/dashboardComponents/DashboardComponentsRegistry';
|
||||
|
||||
type DraggableNewDynamicComponent = {
|
||||
componentKey: string;
|
||||
metadata: DashboardComponentsRegistryMetadata;
|
||||
};
|
||||
|
||||
const DraggableNewDynamicComponent: FC<DraggableNewDynamicComponent> = ({
|
||||
componentKey,
|
||||
metadata,
|
||||
}) => (
|
||||
<DraggableNewComponent
|
||||
id={NEW_DYNAMIC_COMPONENT}
|
||||
type={DYNAMIC_TYPE}
|
||||
label={metadata.name}
|
||||
meta={{ metadata, componentKey }}
|
||||
className={`fa fa-${metadata.iconName}`}
|
||||
/>
|
||||
);
|
||||
|
||||
export default DraggableNewDynamicComponent;
|
|
@ -17,11 +17,14 @@
|
|||
* under the License.
|
||||
*/
|
||||
import React, { RefObject } from 'react';
|
||||
import { styled, DataMask } from '@superset-ui/core';
|
||||
import {
|
||||
DataMaskStateWithId,
|
||||
Filter,
|
||||
styled,
|
||||
DataMask,
|
||||
} from '@superset-ui/core';
|
||||
import FilterControl from 'src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControl';
|
||||
import { CascadeFilter } from 'src/dashboard/components/nativeFilters/FilterBar/CascadeFilters/types';
|
||||
import { Filter } from 'src/dashboard/components/nativeFilters/types';
|
||||
import { DataMaskStateWithId } from 'src/dataMask/types';
|
||||
|
||||
export interface CascadeFilterControlProps {
|
||||
dataMaskSelected?: DataMaskStateWithId;
|
||||
|
|
|
@ -23,15 +23,21 @@ import React, {
|
|||
useState,
|
||||
useRef,
|
||||
} from 'react';
|
||||
import { styled, t, DataMask, css, SupersetTheme } from '@superset-ui/core';
|
||||
import {
|
||||
css,
|
||||
DataMask,
|
||||
DataMaskStateWithId,
|
||||
Filter,
|
||||
styled,
|
||||
SupersetTheme,
|
||||
t,
|
||||
} from '@superset-ui/core';
|
||||
import Popover from 'src/components/Popover';
|
||||
import Icons from 'src/components/Icons';
|
||||
import { Pill } from 'src/dashboard/components/FiltersBadge/Styles';
|
||||
import { DataMaskStateWithId } from 'src/dataMask/types';
|
||||
import FilterControl from 'src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControl';
|
||||
import CascadeFilterControl from 'src/dashboard/components/nativeFilters/FilterBar/CascadeFilters/CascadeFilterControl';
|
||||
import { CascadeFilter } from 'src/dashboard/components/nativeFilters/FilterBar/CascadeFilters/types';
|
||||
import { Filter } from 'src/dashboard/components/nativeFilters/types';
|
||||
|
||||
interface CascadePopoverProps {
|
||||
dataMaskSelected: DataMaskStateWithId;
|
||||
|
|
|
@ -17,8 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { DataMask } from '@superset-ui/core';
|
||||
import { Filter } from '../../types';
|
||||
import { DataMask, Filter } from '@superset-ui/core';
|
||||
|
||||
export type CascadeFilter = Filter & { dataMask?: DataMask } & {
|
||||
cascadeChildren: CascadeFilter[];
|
||||
|
|
|
@ -20,8 +20,7 @@ import React, { useState } from 'react';
|
|||
import { useDispatch } from 'react-redux';
|
||||
import { setFilterConfiguration } from 'src/dashboard/actions/nativeFilters';
|
||||
import Button from 'src/components/Button';
|
||||
import { styled } from '@superset-ui/core';
|
||||
import { FilterConfiguration } from 'src/dashboard/components/nativeFilters/types';
|
||||
import { FilterConfiguration, styled } from '@superset-ui/core';
|
||||
import { FiltersConfigModal } from 'src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal';
|
||||
import { getFilterBarTestId } from '..';
|
||||
|
||||
|
|
|
@ -18,22 +18,24 @@
|
|||
*/
|
||||
import React, { FC, useCallback, useMemo, useState } from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
import { DataMask, styled, t } from '@superset-ui/core';
|
||||
import {
|
||||
DataMask,
|
||||
DataMaskStateWithId,
|
||||
Filter,
|
||||
NativeFilterType,
|
||||
styled,
|
||||
t,
|
||||
} from '@superset-ui/core';
|
||||
import {
|
||||
createHtmlPortalNode,
|
||||
InPortal,
|
||||
OutPortal,
|
||||
} from 'react-reverse-portal';
|
||||
import { Collapse } from 'src/common/components';
|
||||
import { DataMaskStateWithId } from 'src/dataMask/types';
|
||||
import {
|
||||
useDashboardHasTabs,
|
||||
useSelectFiltersInScope,
|
||||
} from 'src/dashboard/components/nativeFilters/state';
|
||||
import {
|
||||
Filter,
|
||||
NativeFilterType,
|
||||
} from 'src/dashboard/components/nativeFilters/types';
|
||||
import CascadePopover from '../CascadeFilters/CascadePopover';
|
||||
import { useFilters } from '../state';
|
||||
import { buildCascadeFiltersTree } from './utils';
|
||||
|
|
|
@ -18,9 +18,11 @@
|
|||
*/
|
||||
import { useMemo } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { NativeFiltersState } from 'src/dashboard/reducers/types';
|
||||
import { DataMaskStateWithId } from 'src/dataMask/types';
|
||||
import { ExtraFormData } from '@superset-ui/core';
|
||||
import {
|
||||
DataMaskStateWithId,
|
||||
ExtraFormData,
|
||||
NativeFiltersState,
|
||||
} from '@superset-ui/core';
|
||||
import { mergeExtraFormData } from '../../utils';
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
|
|
|
@ -17,9 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
import React, { RefObject } from 'react';
|
||||
import { DataMask } from '@superset-ui/core';
|
||||
import { DataMaskStateWithId } from 'src/dataMask/types';
|
||||
import { Filter } from '../../types';
|
||||
import { DataMask, DataMaskStateWithId, Filter } from '@superset-ui/core';
|
||||
|
||||
export interface FilterProps {
|
||||
dataMaskSelected?: DataMaskStateWithId;
|
||||
|
|
|
@ -18,11 +18,11 @@
|
|||
*/
|
||||
import { debounce } from 'lodash';
|
||||
import { Dispatch } from 'react';
|
||||
import { Filter, NativeFilterType, Divider } from '@superset-ui/core';
|
||||
import {
|
||||
setFocusedNativeFilter,
|
||||
unsetFocusedNativeFilter,
|
||||
} from 'src/dashboard/actions/nativeFilters';
|
||||
import { Filter, NativeFilterType, Divider } from '../../types';
|
||||
import { CascadeFilter } from '../CascadeFilters/types';
|
||||
import { mapParentFiltersToChildren } from '../utils';
|
||||
|
||||
|
|
|
@ -17,12 +17,11 @@
|
|||
* under the License.
|
||||
*/
|
||||
import React, { FC, useMemo, useState } from 'react';
|
||||
import { HandlerFunction, styled, t } from '@superset-ui/core';
|
||||
import { DataMaskState, HandlerFunction, styled, t } from '@superset-ui/core';
|
||||
import { Typography, Tooltip } from 'src/common/components';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import Button from 'src/components/Button';
|
||||
import { updateFilterSet } from 'src/dashboard/actions/nativeFilters';
|
||||
import { DataMaskState } from 'src/dataMask/types';
|
||||
import { WarningOutlined } from '@ant-design/icons';
|
||||
import { ActionButtons } from './Footer';
|
||||
import { useNativeFiltersDataMask, useFilters, useFilterSets } from '../state';
|
||||
|
|
|
@ -18,10 +18,15 @@
|
|||
*/
|
||||
import { Typography, Dropdown, Menu } from 'src/common/components';
|
||||
import React, { FC } from 'react';
|
||||
import { FilterSet } from 'src/dashboard/reducers/types';
|
||||
import { DataMaskState } from 'src/dataMask/types';
|
||||
import {
|
||||
DataMaskState,
|
||||
FilterSet,
|
||||
HandlerFunction,
|
||||
styled,
|
||||
supersetTheme,
|
||||
t,
|
||||
} from '@superset-ui/core';
|
||||
import { CheckOutlined, EllipsisOutlined } from '@ant-design/icons';
|
||||
import { HandlerFunction, styled, supersetTheme, t } from '@superset-ui/core';
|
||||
import Button from 'src/components/Button';
|
||||
import { Tooltip } from 'src/components/Tooltip';
|
||||
import FiltersHeader from './FiltersHeader';
|
||||
|
|
|
@ -17,16 +17,20 @@
|
|||
* under the License.
|
||||
*/
|
||||
import React, { FC } from 'react';
|
||||
import { styled, t, useTheme } from '@superset-ui/core';
|
||||
import {
|
||||
DataMaskState,
|
||||
FilterSet,
|
||||
NativeFilterType,
|
||||
styled,
|
||||
t,
|
||||
useTheme,
|
||||
} from '@superset-ui/core';
|
||||
import { Collapse, Typography, Tooltip } from 'src/common/components';
|
||||
import { DataMaskState } from 'src/dataMask/types';
|
||||
import Icons from 'src/components/Icons';
|
||||
import { areObjectsEqual } from 'src/reduxUtils';
|
||||
import { FilterSet } from 'src/dashboard/reducers/types';
|
||||
import { getFilterValueForDisplay } from './utils';
|
||||
import { useFilters } from '../state';
|
||||
import { getFilterBarTestId } from '../index';
|
||||
import { NativeFilterType } from '../../types';
|
||||
|
||||
const FilterHeader = styled.div`
|
||||
display: flex;
|
||||
|
|
|
@ -18,18 +18,25 @@
|
|||
*/
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { DataMask, HandlerFunction, styled, t } from '@superset-ui/core';
|
||||
import {
|
||||
DataMask,
|
||||
DataMaskState,
|
||||
DataMaskWithId,
|
||||
Filter,
|
||||
Filters,
|
||||
FilterSet,
|
||||
HandlerFunction,
|
||||
styled,
|
||||
t,
|
||||
} from '@superset-ui/core';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { DataMaskState, DataMaskWithId } from 'src/dataMask/types';
|
||||
import {
|
||||
createFilterSet,
|
||||
deleteFilterSet,
|
||||
updateFilterSet,
|
||||
} from 'src/dashboard/actions/nativeFilters';
|
||||
import { Filters, FilterSet } from 'src/dashboard/reducers/types';
|
||||
import { areObjectsEqual } from 'src/reduxUtils';
|
||||
import { findExistingFilterSet } from './utils';
|
||||
import { Filter } from '../../types';
|
||||
import { useFilters, useNativeFiltersDataMask, useFilterSets } from '../state';
|
||||
import Footer from './Footer';
|
||||
import FilterSetUnit from './FilterSetUnit';
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { FilterSet } from 'src/dashboard/reducers/types';
|
||||
import { FilterSet } from '@superset-ui/core';
|
||||
import { findExistingFilterSet } from '.';
|
||||
|
||||
const createDataMaskSelected = () => ({
|
||||
|
|
|
@ -18,10 +18,8 @@
|
|||
*/
|
||||
|
||||
import shortid from 'shortid';
|
||||
import { t } from '@superset-ui/core';
|
||||
import { DataMaskState, FilterSet, t } from '@superset-ui/core';
|
||||
import { areObjectsEqual } from 'src/reduxUtils';
|
||||
import { DataMaskState } from 'src/dataMask/types';
|
||||
import { FilterSet } from 'src/dashboard/reducers/types';
|
||||
|
||||
export const generateFiltersSetId = () => `FILTERS_SET-${shortid.generate()}`;
|
||||
|
||||
|
|
|
@ -17,15 +17,20 @@
|
|||
* under the License.
|
||||
*/
|
||||
/* eslint-disable no-param-reassign */
|
||||
import { styled, t, useTheme } from '@superset-ui/core';
|
||||
import {
|
||||
DataMaskState,
|
||||
DataMaskStateWithId,
|
||||
Filter,
|
||||
styled,
|
||||
t,
|
||||
useTheme,
|
||||
} from '@superset-ui/core';
|
||||
import React, { FC } from 'react';
|
||||
import Icons from 'src/components/Icons';
|
||||
import Button from 'src/components/Button';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { DataMaskState, DataMaskStateWithId } from 'src/dataMask/types';
|
||||
import FilterConfigurationLink from 'src/dashboard/components/nativeFilters/FilterBar/FilterConfigurationLink';
|
||||
import { useFilters } from 'src/dashboard/components/nativeFilters/FilterBar/state';
|
||||
import { Filter } from 'src/dashboard/components/nativeFilters/types';
|
||||
import { getFilterBarTestId } from '..';
|
||||
import { RootState } from '../../../../types';
|
||||
|
||||
|
|
|
@ -18,7 +18,16 @@
|
|||
*/
|
||||
|
||||
/* eslint-disable no-param-reassign */
|
||||
import { DataMask, HandlerFunction, styled, t } from '@superset-ui/core';
|
||||
import {
|
||||
DataMaskStateWithId,
|
||||
DataMaskWithId,
|
||||
Filter,
|
||||
NativeFilterType,
|
||||
DataMask,
|
||||
HandlerFunction,
|
||||
styled,
|
||||
t,
|
||||
} from '@superset-ui/core';
|
||||
import React, { useEffect, useState, useCallback, useMemo } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import cx from 'classnames';
|
||||
|
@ -28,14 +37,9 @@ import { useHistory } from 'react-router-dom';
|
|||
import { usePrevious } from 'src/hooks/usePrevious';
|
||||
import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
|
||||
import { updateDataMask, clearDataMask } from 'src/dataMask/actions';
|
||||
import { DataMaskStateWithId, DataMaskWithId } from 'src/dataMask/types';
|
||||
import { useImmer } from 'use-immer';
|
||||
import { isEmpty, isEqual } from 'lodash';
|
||||
import { testWithId } from 'src/utils/testUtils';
|
||||
import {
|
||||
Filter,
|
||||
NativeFilterType,
|
||||
} from 'src/dashboard/components/nativeFilters/types';
|
||||
import Loading from 'src/components/Loading';
|
||||
import { getInitialDataMask } from 'src/dataMask/reducer';
|
||||
import { URL_PARAMS } from 'src/constants';
|
||||
|
|
|
@ -19,20 +19,18 @@
|
|||
/* eslint-disable no-param-reassign */
|
||||
import { useSelector } from 'react-redux';
|
||||
import { filter, keyBy } from 'lodash';
|
||||
import {
|
||||
Filters,
|
||||
FilterSets as FilterSetsType,
|
||||
} from 'src/dashboard/reducers/types';
|
||||
import {
|
||||
DataMaskState,
|
||||
DataMaskStateWithId,
|
||||
DataMaskWithId,
|
||||
} from 'src/dataMask/types';
|
||||
Filter,
|
||||
Filters,
|
||||
FilterSets as FilterSetsType,
|
||||
} from '@superset-ui/core';
|
||||
import { useContext, useEffect, useMemo, useState } from 'react';
|
||||
import { ChartsState, RootState } from 'src/dashboard/types';
|
||||
import { MigrationContext } from 'src/dashboard/containers/DashboardPage';
|
||||
import { FILTER_BOX_MIGRATION_STATES } from 'src/explore/constants';
|
||||
import { Filter } from 'src/dashboard/components/nativeFilters/types';
|
||||
import { NATIVE_FILTER_PREFIX } from '../FiltersConfigModal/utils';
|
||||
|
||||
export const useFilterSets = () =>
|
||||
|
|
|
@ -17,10 +17,13 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { DataMaskStateWithId } from 'src/dataMask/types';
|
||||
import { areObjectsEqual } from 'src/reduxUtils';
|
||||
import { FilterState } from '@superset-ui/core';
|
||||
import { Filter, Divider } from '../types';
|
||||
import {
|
||||
DataMaskStateWithId,
|
||||
Filter,
|
||||
FilterState,
|
||||
Divider,
|
||||
} from '@superset-ui/core';
|
||||
|
||||
export enum TabIds {
|
||||
AllFilters = 'allFilters',
|
||||
|
|
|
@ -19,8 +19,7 @@
|
|||
import React from 'react';
|
||||
import { FormItem } from 'src/components/Form';
|
||||
import { Input, TextArea } from 'src/common/components';
|
||||
import { styled, t } from '@superset-ui/core';
|
||||
import { NativeFilterType } from '../types';
|
||||
import { NativeFilterType, styled, t } from '@superset-ui/core';
|
||||
|
||||
interface Props {
|
||||
componentId: string;
|
||||
|
|
|
@ -16,9 +16,8 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { styled } from '@superset-ui/core';
|
||||
import { NativeFilterType, styled } from '@superset-ui/core';
|
||||
import React from 'react';
|
||||
import { NativeFilterType } from '../types';
|
||||
import FilterTitlePane from './FilterTitlePane';
|
||||
import { FilterRemoval } from './types';
|
||||
|
||||
|
|
|
@ -16,10 +16,9 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { styled, t, useTheme } from '@superset-ui/core';
|
||||
import { NativeFilterType, styled, t, useTheme } from '@superset-ui/core';
|
||||
import React from 'react';
|
||||
import { Dropdown, MainNav as Menu } from 'src/common/components';
|
||||
import { NativeFilterType } from '../types';
|
||||
import FilterTitleContainer from './FilterTitleContainer';
|
||||
import { FilterRemoval } from './types';
|
||||
|
||||
|
|
|
@ -18,11 +18,10 @@
|
|||
*/
|
||||
|
||||
import React, { FC, useCallback, useState } from 'react';
|
||||
import { t, styled } from '@superset-ui/core';
|
||||
import { NativeFilterScope, styled, t } from '@superset-ui/core';
|
||||
import { Radio } from 'src/components/Radio';
|
||||
import { Form, Typography } from 'src/common/components';
|
||||
import { useComponentDidUpdate } from 'src/hooks/useComponentDidUpdate/useComponentDidUpdate';
|
||||
import { Scope } from '../../../types';
|
||||
import { ScopingType } from './types';
|
||||
import ScopingTree from './ScopingTree';
|
||||
import { getDefaultScopeValue, isScopingAll } from './utils';
|
||||
|
@ -30,9 +29,9 @@ import { getDefaultScopeValue, isScopingAll } from './utils';
|
|||
type FilterScopeProps = {
|
||||
pathToFormValue?: string[];
|
||||
updateFormValues: (values: any) => void;
|
||||
formFilterScope?: Scope;
|
||||
formFilterScope?: NativeFilterScope;
|
||||
forceUpdate: Function;
|
||||
filterScope?: Scope;
|
||||
filterScope?: NativeFilterScope;
|
||||
formScopingType?: ScopingType;
|
||||
chartId?: number;
|
||||
initiallyExcludedCharts?: number[];
|
||||
|
|
|
@ -18,19 +18,19 @@
|
|||
*/
|
||||
|
||||
import React, { FC, useMemo, useState } from 'react';
|
||||
import { NativeFilterScope } from '@superset-ui/core';
|
||||
import { Tree } from 'src/common/components';
|
||||
import { DASHBOARD_ROOT_ID } from 'src/dashboard/util/constants';
|
||||
import { Tooltip } from 'src/components/Tooltip';
|
||||
import Icons from 'src/components/Icons';
|
||||
import { useFilterScopeTree } from './state';
|
||||
import { findFilterScope, getTreeCheckedItems } from './utils';
|
||||
import { Scope } from '../../../types';
|
||||
|
||||
type ScopingTreeProps = {
|
||||
forceUpdate: Function;
|
||||
updateFormValues: (values: any) => void;
|
||||
formScope?: Scope;
|
||||
initialScope: Scope;
|
||||
formScope?: NativeFilterScope;
|
||||
initialScope: NativeFilterScope;
|
||||
chartId?: number;
|
||||
initiallyExcludedCharts?: number[];
|
||||
};
|
||||
|
|
|
@ -23,9 +23,8 @@ import {
|
|||
TAB_TYPE,
|
||||
} from 'src/dashboard/util/componentTypes';
|
||||
import { DASHBOARD_ROOT_ID } from 'src/dashboard/util/constants';
|
||||
import { t } from '@superset-ui/core';
|
||||
import { NativeFilterScope, t } from '@superset-ui/core';
|
||||
import { BuildTreeLeafTitle, TreeItem } from './types';
|
||||
import { Scope } from '../../../types';
|
||||
|
||||
export const isShowTypeInTree = ({ type, meta }: LayoutItem, charts?: Charts) =>
|
||||
(type === TAB_TYPE || type === CHART_TYPE || type === DASHBOARD_ROOT_TYPE) &&
|
||||
|
@ -114,7 +113,10 @@ const checkTreeItem = (
|
|||
});
|
||||
};
|
||||
|
||||
export const getTreeCheckedItems = (scope: Scope, layout: Layout) => {
|
||||
export const getTreeCheckedItems = (
|
||||
scope: NativeFilterScope,
|
||||
layout: Layout,
|
||||
) => {
|
||||
const checkedItems: string[] = [];
|
||||
checkTreeItem(checkedItems, layout, [...scope.rootPath], [...scope.excluded]);
|
||||
return [...new Set(checkedItems)];
|
||||
|
@ -124,7 +126,7 @@ export const getTreeCheckedItems = (scope: Scope, layout: Layout) => {
|
|||
export const findFilterScope = (
|
||||
checkedKeys: string[],
|
||||
layout: Layout,
|
||||
): Scope => {
|
||||
): NativeFilterScope => {
|
||||
if (!checkedKeys.length) {
|
||||
return {
|
||||
rootPath: [],
|
||||
|
@ -170,14 +172,14 @@ export const findFilterScope = (
|
|||
export const getDefaultScopeValue = (
|
||||
chartId?: number,
|
||||
initiallyExcludedCharts: number[] = [],
|
||||
): Scope => ({
|
||||
): NativeFilterScope => ({
|
||||
rootPath: [DASHBOARD_ROOT_ID],
|
||||
excluded: chartId
|
||||
? [chartId, ...initiallyExcludedCharts]
|
||||
: initiallyExcludedCharts,
|
||||
});
|
||||
|
||||
export const isScopingAll = (scope: Scope, chartId?: number) =>
|
||||
export const isScopingAll = (scope: NativeFilterScope, chartId?: number) =>
|
||||
!scope ||
|
||||
(scope.rootPath[0] === DASHBOARD_ROOT_ID &&
|
||||
!scope.excluded.filter(item => item !== chartId).length);
|
||||
|
|
|
@ -27,9 +27,11 @@ import {
|
|||
Behavior,
|
||||
ChartDataResponseResult,
|
||||
Column,
|
||||
Filter,
|
||||
GenericDataType,
|
||||
getChartMetadataRegistry,
|
||||
JsonResponse,
|
||||
NativeFilterType,
|
||||
styled,
|
||||
SupersetApiError,
|
||||
SupersetClient,
|
||||
|
@ -71,10 +73,6 @@ import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
|
|||
import { waitForAsyncData } from 'src/middleware/asyncEvent';
|
||||
import { cacheWrapper } from 'src/utils/cacheWrapper';
|
||||
import { ClientErrorObject } from 'src/utils/getClientErrorObject';
|
||||
import {
|
||||
Filter,
|
||||
NativeFilterType,
|
||||
} from 'src/dashboard/components/nativeFilters/types';
|
||||
import { SingleValueType } from 'src/filters/components/Range/SingleValueType';
|
||||
import { getFormData } from 'src/dashboard/components/nativeFilters/utils';
|
||||
import {
|
||||
|
|
|
@ -18,12 +18,9 @@
|
|||
*/
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import { Filter, NativeFilterType } from '@superset-ui/core';
|
||||
import { render, screen } from 'spec/helpers/testing-library';
|
||||
import { FormInstance } from 'src/common/components';
|
||||
import {
|
||||
Filter,
|
||||
NativeFilterType,
|
||||
} from 'src/dashboard/components/nativeFilters/types';
|
||||
import getControlItemsMap, { ControlItemsProps } from './getControlItemsMap';
|
||||
import { getControlItems, setNativeFilterFieldValues } from './utils';
|
||||
|
||||
|
|
|
@ -23,7 +23,12 @@ import {
|
|||
import React from 'react';
|
||||
import { Checkbox } from 'src/common/components';
|
||||
import { FormInstance } from 'antd/lib/form';
|
||||
import { getChartControlPanelRegistry, styled, t } from '@superset-ui/core';
|
||||
import {
|
||||
Filter,
|
||||
getChartControlPanelRegistry,
|
||||
styled,
|
||||
t,
|
||||
} from '@superset-ui/core';
|
||||
import { Tooltip } from 'src/components/Tooltip';
|
||||
import { FormItem } from 'src/components/Form';
|
||||
import {
|
||||
|
@ -37,7 +42,6 @@ import {
|
|||
StyledLabel,
|
||||
StyledRowFormItem,
|
||||
} from './FiltersConfigForm';
|
||||
import { Filter } from '../../types';
|
||||
import { ColumnSelect } from './ColumnSelect';
|
||||
|
||||
export interface ControlItemsProps {
|
||||
|
|
|
@ -18,10 +18,9 @@
|
|||
*/
|
||||
import { useEffect, useState } from 'react';
|
||||
import { FormInstance } from 'antd/lib/form';
|
||||
import { t } from '@superset-ui/core';
|
||||
import { Filter, t } from '@superset-ui/core';
|
||||
import { NativeFiltersForm, NativeFiltersFormItem } from '../types';
|
||||
import { setNativeFilterFieldValues, useForceUpdate } from './utils';
|
||||
import { Filter } from '../../types';
|
||||
|
||||
// When some fields in form changed we need re-fetch data for Filter defaultValue
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
|
|
|
@ -24,18 +24,20 @@ import React, {
|
|||
useRef,
|
||||
} from 'react';
|
||||
import { uniq, isEqual, sortBy, debounce } from 'lodash';
|
||||
import { t, styled, SLOW_DEBOUNCE } from '@superset-ui/core';
|
||||
import { Form } from 'src/common/components';
|
||||
import ErrorBoundary from 'src/components/ErrorBoundary';
|
||||
import { StyledModal } from 'src/components/Modal';
|
||||
import { testWithId } from 'src/utils/testUtils';
|
||||
import { useFilterConfigMap, useFilterConfiguration } from '../state';
|
||||
import {
|
||||
Filter,
|
||||
FilterConfiguration,
|
||||
NativeFilterType,
|
||||
Divider,
|
||||
} from '../types';
|
||||
styled,
|
||||
SLOW_DEBOUNCE,
|
||||
t,
|
||||
} from '@superset-ui/core';
|
||||
import { Form } from 'src/common/components';
|
||||
import ErrorBoundary from 'src/components/ErrorBoundary';
|
||||
import { StyledModal } from 'src/components/Modal';
|
||||
import { testWithId } from 'src/utils/testUtils';
|
||||
import { useFilterConfigMap, useFilterConfiguration } from '../state';
|
||||
import FiltureConfigurePane from './FilterConfigurePane';
|
||||
import FiltersConfigForm, {
|
||||
FilterPanels,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { useEffect } from 'react';
|
||||
import { usePrevious } from 'src/hooks/usePrevious';
|
||||
import { NativeFilterType } from '@superset-ui/core';
|
||||
import { FilterRemoval } from './types';
|
||||
import { NativeFilterType } from '../types';
|
||||
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
|
|
|
@ -16,11 +16,15 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { AdhocFilter, DataMask } from '@superset-ui/core';
|
||||
import { NativeFilterType, Scope } from '../types';
|
||||
import {
|
||||
AdhocFilter,
|
||||
DataMask,
|
||||
NativeFilterType,
|
||||
NativeFilterScope,
|
||||
} from '@superset-ui/core';
|
||||
|
||||
export interface NativeFiltersFormItem {
|
||||
scope: Scope;
|
||||
scope: NativeFilterScope;
|
||||
name: string;
|
||||
filterType: string;
|
||||
dataset: {
|
||||
|
|
|
@ -20,7 +20,14 @@ import { FormInstance } from 'antd/lib/form';
|
|||
import shortid from 'shortid';
|
||||
import { getInitialDataMask } from 'src/dataMask/reducer';
|
||||
|
||||
import { t } from '@superset-ui/core';
|
||||
import {
|
||||
Filter,
|
||||
FilterConfiguration,
|
||||
NativeFilterType,
|
||||
Divider,
|
||||
t,
|
||||
NativeFilterTarget,
|
||||
} from '@superset-ui/core';
|
||||
import { DASHBOARD_ROOT_ID } from 'src/dashboard/util/constants';
|
||||
import {
|
||||
FilterRemoval,
|
||||
|
@ -28,13 +35,6 @@ import {
|
|||
FilterHierarchy,
|
||||
FilterHierarchyNode,
|
||||
} from './types';
|
||||
import {
|
||||
Filter,
|
||||
FilterConfiguration,
|
||||
NativeFilterType,
|
||||
Divider,
|
||||
Target,
|
||||
} from '../types';
|
||||
|
||||
export const REMOVAL_DELAY_SECS = 5;
|
||||
|
||||
|
@ -156,7 +156,7 @@ export const createHandleSave =
|
|||
description: formInputs.description,
|
||||
};
|
||||
}
|
||||
const target: Partial<Target> = {};
|
||||
const target: Partial<NativeFilterTarget> = {};
|
||||
if (formInputs.dataset) {
|
||||
target.datasetId = formInputs.dataset.value;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ import {
|
|||
FilterConfiguration,
|
||||
NativeFilterType,
|
||||
Divider,
|
||||
} from './types';
|
||||
} from '@superset-ui/core';
|
||||
import { ActiveTabs, DashboardLayout, RootState } from '../../types';
|
||||
import { TAB_TYPE } from '../../util/componentTypes';
|
||||
import { CascadeFilter } from './FilterBar/CascadeFilters/types';
|
||||
|
|
|
@ -17,21 +17,21 @@
|
|||
* under the License.
|
||||
*/
|
||||
import {
|
||||
ExtraFormData,
|
||||
QueryFormData,
|
||||
getChartMetadataRegistry,
|
||||
AdhocFilter,
|
||||
Behavior,
|
||||
DataMaskStateWithId,
|
||||
EXTRA_FORM_DATA_APPEND_KEYS,
|
||||
EXTRA_FORM_DATA_OVERRIDE_KEYS,
|
||||
AdhocFilter,
|
||||
ExtraFormData,
|
||||
FeatureFlag,
|
||||
Filter,
|
||||
getChartMetadataRegistry,
|
||||
QueryFormData,
|
||||
} from '@superset-ui/core';
|
||||
import { Charts, DashboardLayout } from 'src/dashboard/types';
|
||||
import { RefObject } from 'react';
|
||||
import { DataMaskStateWithId } from 'src/dataMask/types';
|
||||
import extractUrlParams from 'src/dashboard/util/extractUrlParams';
|
||||
import { isFeatureEnabled } from 'src/featureFlags';
|
||||
import { Filter } from './types';
|
||||
import { CHART_TYPE, TAB_TYPE } from '../../util/componentTypes';
|
||||
import { DASHBOARD_GRID_ID, DASHBOARD_ROOT_ID } from '../../util/constants';
|
||||
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { NativeFilterType } from 'src/dashboard/components/nativeFilters/types';
|
||||
import { NativeFiltersState } from 'src/dashboard/reducers/types';
|
||||
import { DataMaskStateWithId } from 'src/dataMask/types';
|
||||
import {
|
||||
DataMaskStateWithId,
|
||||
NativeFiltersState,
|
||||
NativeFilterType,
|
||||
} from '@superset-ui/core';
|
||||
|
||||
export const mockDataMaskInfo: DataMaskStateWithId = {
|
||||
DefaultsID: {
|
||||
|
|
|
@ -24,8 +24,11 @@ import {
|
|||
SET_FOCUSED_NATIVE_FILTER,
|
||||
UNSET_FOCUSED_NATIVE_FILTER,
|
||||
} from 'src/dashboard/actions/nativeFilters';
|
||||
import { FilterSet, NativeFiltersState } from './types';
|
||||
import { FilterConfiguration } from '../components/nativeFilters/types';
|
||||
import {
|
||||
FilterSet,
|
||||
FilterConfiguration,
|
||||
NativeFiltersState,
|
||||
} from '@superset-ui/core';
|
||||
import { HYDRATE_DASHBOARD } from '../actions/hydrate';
|
||||
|
||||
export function getInitialState({
|
||||
|
|
|
@ -18,9 +18,7 @@
|
|||
*/
|
||||
|
||||
import componentTypes from 'src/dashboard/util/componentTypes';
|
||||
import { DataMaskStateWithId } from 'src/dataMask/types';
|
||||
import { JsonObject } from '@superset-ui/core';
|
||||
import { Filter, Scope } from '../components/nativeFilters/types';
|
||||
import { NativeFilterScope, JsonObject } from '@superset-ui/core';
|
||||
|
||||
export enum Scoping {
|
||||
All = 'All',
|
||||
|
@ -31,7 +29,7 @@ export type ChartConfiguration = {
|
|||
[chartId: number]: {
|
||||
id: number;
|
||||
crossFilters: {
|
||||
scope: Scope;
|
||||
scope: NativeFilterScope;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -82,13 +80,6 @@ export type LayoutItem = {
|
|||
};
|
||||
};
|
||||
|
||||
export type FilterSet = {
|
||||
id: number;
|
||||
name: string;
|
||||
nativeFilters: Filters;
|
||||
dataMask: DataMaskStateWithId;
|
||||
};
|
||||
|
||||
export type FilterSetFullData = {
|
||||
changed_by_fk: string | null;
|
||||
changed_on: string | null;
|
||||
|
@ -101,17 +92,3 @@ export type FilterSetFullData = {
|
|||
owner_type: string;
|
||||
params: JsonObject;
|
||||
};
|
||||
|
||||
export type FilterSets = {
|
||||
[filtersSetId: string]: FilterSet;
|
||||
};
|
||||
|
||||
export type Filters = {
|
||||
[filterId: string]: Filter;
|
||||
};
|
||||
|
||||
export type NativeFiltersState = {
|
||||
filters: Filters;
|
||||
filterSets: FilterSets;
|
||||
focusedFilterId?: string;
|
||||
};
|
||||
|
|
|
@ -18,17 +18,17 @@
|
|||
*/
|
||||
import {
|
||||
ChartProps,
|
||||
DataMaskStateWithId,
|
||||
ExtraFormData,
|
||||
GenericDataType,
|
||||
JsonObject,
|
||||
NativeFiltersState,
|
||||
} from '@superset-ui/core';
|
||||
import { DatasourceMeta } from '@superset-ui/chart-controls';
|
||||
import { chart } from 'src/chart/chartReducer';
|
||||
import componentTypes from 'src/dashboard/util/componentTypes';
|
||||
|
||||
import { User } from 'src/types/bootstrapTypes';
|
||||
import { DataMaskStateWithId } from '../dataMask/types';
|
||||
import { NativeFiltersState } from './reducers/types';
|
||||
import { ChartState } from '../explore/types';
|
||||
|
||||
export { Dashboard } from 'src/types/Dashboard';
|
||||
|
|
|
@ -16,12 +16,15 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { DataMaskStateWithId } from 'src/dataMask/types';
|
||||
import { JsonObject } from '@superset-ui/core';
|
||||
import {
|
||||
DataMaskStateWithId,
|
||||
Filters,
|
||||
JsonObject,
|
||||
NativeFilterScope,
|
||||
} from '@superset-ui/core';
|
||||
import { CHART_TYPE } from './componentTypes';
|
||||
import { Scope } from '../components/nativeFilters/types';
|
||||
import { ActiveFilters, Layout, LayoutItem } from '../types';
|
||||
import { ChartConfiguration, Filters } from '../reducers/types';
|
||||
import { ChartConfiguration } from '../reducers/types';
|
||||
import { DASHBOARD_ROOT_ID } from './constants';
|
||||
|
||||
// Looking for affected chart scopes and values
|
||||
|
@ -35,7 +38,7 @@ export const findAffectedCharts = ({
|
|||
}: {
|
||||
child: string;
|
||||
layout: { [key: string]: LayoutItem };
|
||||
scope: Scope;
|
||||
scope: NativeFilterScope;
|
||||
activeFilters: ActiveFilters;
|
||||
filterId: string;
|
||||
extraFormData: any;
|
||||
|
|
|
@ -16,13 +16,17 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { DataRecordFilters, JsonObject } from '@superset-ui/core';
|
||||
import {
|
||||
DataMaskStateWithId,
|
||||
DataRecordFilters,
|
||||
JsonObject,
|
||||
NativeFiltersState,
|
||||
} from '@superset-ui/core';
|
||||
import { ChartQueryPayload, Charts, LayoutItem } from 'src/dashboard/types';
|
||||
import { getExtraFormData } from 'src/dashboard/components/nativeFilters/utils';
|
||||
import { DataMaskStateWithId } from 'src/dataMask/types';
|
||||
import { areObjectsEqual } from 'src/reduxUtils';
|
||||
import getEffectiveExtraFilters from './getEffectiveExtraFilters';
|
||||
import { ChartConfiguration, NativeFiltersState } from '../../reducers/types';
|
||||
import { ChartConfiguration } from '../../reducers/types';
|
||||
import { getAllActiveFilters } from '../activeAllDashboardFilters';
|
||||
|
||||
// We cache formData objects so that our connected container components don't always trigger
|
||||
|
|
|
@ -16,8 +16,17 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { COLUMN_TYPE, CHART_TYPE, MARKDOWN_TYPE } from './componentTypes';
|
||||
import {
|
||||
COLUMN_TYPE,
|
||||
CHART_TYPE,
|
||||
MARKDOWN_TYPE,
|
||||
DYNAMIC_TYPE,
|
||||
} from './componentTypes';
|
||||
|
||||
export default function componentIsResizable(entity: { type: string }) {
|
||||
return [COLUMN_TYPE, CHART_TYPE, MARKDOWN_TYPE].indexOf(entity.type) > -1;
|
||||
return (
|
||||
[COLUMN_TYPE, CHART_TYPE, MARKDOWN_TYPE, DYNAMIC_TYPE].indexOf(
|
||||
entity.type,
|
||||
) > -1
|
||||
);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@ export const NEW_COMPONENT_SOURCE_TYPE = 'NEW_COMPONENT_SOURCE';
|
|||
export const ROW_TYPE = 'ROW';
|
||||
export const TABS_TYPE = 'TABS';
|
||||
export const TAB_TYPE = 'TAB';
|
||||
// Dynamic type proposes lazy loading of custom dashboard components that can be added in separate repository
|
||||
export const DYNAMIC_TYPE = 'DYNAMIC';
|
||||
|
||||
export default {
|
||||
CHART_TYPE,
|
||||
|
@ -42,4 +44,5 @@ export default {
|
|||
ROW_TYPE,
|
||||
TABS_TYPE,
|
||||
TAB_TYPE,
|
||||
DYNAMIC_TYPE,
|
||||
};
|
||||
|
|
|
@ -31,6 +31,7 @@ export const NEW_MARKDOWN_ID = 'NEW_MARKDOWN_ID';
|
|||
export const NEW_ROW_ID = 'NEW_ROW_ID';
|
||||
export const NEW_TAB_ID = 'NEW_TAB_ID';
|
||||
export const NEW_TABS_ID = 'NEW_TABS_ID';
|
||||
export const NEW_DYNAMIC_COMPONENT = 'NEW_DYNAMIC_COMPONENT';
|
||||
|
||||
// grid constants
|
||||
export const DASHBOARD_ROOT_DEPTH = 0;
|
||||
|
|
|
@ -19,17 +19,13 @@
|
|||
import shortid from 'shortid';
|
||||
import { find, isEmpty } from 'lodash';
|
||||
|
||||
import {
|
||||
Filter,
|
||||
NativeFilterType,
|
||||
} from 'src/dashboard/components/nativeFilters/types';
|
||||
import {
|
||||
FILTER_CONFIG_ATTRIBUTES,
|
||||
TIME_FILTER_LABELS,
|
||||
TIME_FILTER_MAP,
|
||||
} from 'src/explore/constants';
|
||||
import { DASHBOARD_FILTER_SCOPE_GLOBAL } from 'src/dashboard/reducers/dashboardFilters';
|
||||
import { TimeGranularity } from '@superset-ui/core';
|
||||
import { Filter, NativeFilterType, TimeGranularity } from '@superset-ui/core';
|
||||
import { getChartIdsInFilterScope } from './activeDashboardFilters';
|
||||
import getFilterConfigsFromFormdata from './getFilterConfigsFromFormdata';
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ import {
|
|||
COLUMN_TYPE,
|
||||
MARKDOWN_TYPE,
|
||||
CHART_TYPE,
|
||||
DYNAMIC_TYPE,
|
||||
} from './componentTypes';
|
||||
|
||||
function getTotalChildWidth({ id, components }) {
|
||||
|
@ -84,6 +85,7 @@ export default function getDetailedComponentWidth({
|
|||
}
|
||||
});
|
||||
} else if (
|
||||
component.type === DYNAMIC_TYPE ||
|
||||
component.type === MARKDOWN_TYPE ||
|
||||
component.type === CHART_TYPE
|
||||
) {
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { Filter } from '@superset-ui/core';
|
||||
import getFormDataWithExtraFilters, {
|
||||
GetFormDataWithExtraFiltersArguments,
|
||||
} from 'src/dashboard/util/charts/getFormDataWithExtraFilters';
|
||||
import { DASHBOARD_ROOT_ID } from 'src/dashboard/util/constants';
|
||||
import { Filter } from 'src/dashboard/components/nativeFilters/types';
|
||||
import { LayoutItem } from 'src/dashboard/types';
|
||||
import { dashboardLayout } from 'spec/fixtures/mockDashboardLayout';
|
||||
import { sliceId as chartId } from 'spec/fixtures/mockChartQueries';
|
||||
|
|
|
@ -16,9 +16,13 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { CHART_TYPE, MARKDOWN_TYPE } from './componentTypes';
|
||||
import { CHART_TYPE, MARKDOWN_TYPE, DYNAMIC_TYPE } from './componentTypes';
|
||||
|
||||
const USER_CONTENT_COMPONENT_TYPE: string[] = [CHART_TYPE, MARKDOWN_TYPE];
|
||||
const USER_CONTENT_COMPONENT_TYPE: string[] = [
|
||||
CHART_TYPE,
|
||||
MARKDOWN_TYPE,
|
||||
DYNAMIC_TYPE,
|
||||
];
|
||||
export default function isDashboardEmpty(layout: any): boolean {
|
||||
// has at least one chart or markdown component
|
||||
return !Object.values(layout).some(
|
||||
|
|
|
@ -43,6 +43,7 @@ import {
|
|||
ROW_TYPE,
|
||||
TABS_TYPE,
|
||||
TAB_TYPE,
|
||||
DYNAMIC_TYPE,
|
||||
} from './componentTypes';
|
||||
|
||||
import { DASHBOARD_ROOT_DEPTH as rootDepth } from './constants';
|
||||
|
@ -62,6 +63,7 @@ const parentMaxDepthLookup = {
|
|||
|
||||
[DASHBOARD_GRID_TYPE]: {
|
||||
[CHART_TYPE]: depthOne,
|
||||
[DYNAMIC_TYPE]: depthOne,
|
||||
[MARKDOWN_TYPE]: depthOne,
|
||||
[COLUMN_TYPE]: depthOne,
|
||||
[DIVIDER_TYPE]: depthOne,
|
||||
|
@ -72,6 +74,7 @@ const parentMaxDepthLookup = {
|
|||
|
||||
[ROW_TYPE]: {
|
||||
[CHART_TYPE]: depthFour,
|
||||
[DYNAMIC_TYPE]: depthFour,
|
||||
[MARKDOWN_TYPE]: depthFour,
|
||||
[COLUMN_TYPE]: depthFour,
|
||||
},
|
||||
|
@ -82,6 +85,7 @@ const parentMaxDepthLookup = {
|
|||
|
||||
[TAB_TYPE]: {
|
||||
[CHART_TYPE]: depthFive,
|
||||
[DYNAMIC_TYPE]: depthFive,
|
||||
[MARKDOWN_TYPE]: depthFive,
|
||||
[COLUMN_TYPE]: depthThree,
|
||||
[DIVIDER_TYPE]: depthFive,
|
||||
|
@ -101,6 +105,7 @@ const parentMaxDepthLookup = {
|
|||
|
||||
// these have no valid children
|
||||
[CHART_TYPE]: {},
|
||||
[DYNAMIC_TYPE]: {},
|
||||
[DIVIDER_TYPE]: {},
|
||||
[HEADER_TYPE]: {},
|
||||
[MARKDOWN_TYPE]: {},
|
||||
|
|
|
@ -28,12 +28,14 @@ import {
|
|||
ROW_TYPE,
|
||||
TABS_TYPE,
|
||||
TAB_TYPE,
|
||||
DYNAMIC_TYPE,
|
||||
} from './componentTypes';
|
||||
|
||||
import {
|
||||
MEDIUM_HEADER,
|
||||
BACKGROUND_TRANSPARENT,
|
||||
GRID_DEFAULT_CHART_WIDTH,
|
||||
GRID_COLUMN_COUNT,
|
||||
} from './constants';
|
||||
|
||||
const typeToDefaultMetaData = {
|
||||
|
@ -56,6 +58,10 @@ const typeToDefaultMetaData = {
|
|||
defaultText: t('Tab title'),
|
||||
placeholder: t('Tab title'),
|
||||
},
|
||||
[DYNAMIC_TYPE]: {
|
||||
width: GRID_COLUMN_COUNT,
|
||||
background: BACKGROUND_TRANSPARENT,
|
||||
},
|
||||
};
|
||||
|
||||
function uuid(type) {
|
||||
|
|
|
@ -16,10 +16,8 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { DataMask } from '@superset-ui/core';
|
||||
import { FilterConfiguration } from '../dashboard/components/nativeFilters/types';
|
||||
import { DataMask, FilterConfiguration, Filters } from '@superset-ui/core';
|
||||
import { FeatureFlag, isFeatureEnabled } from '../featureFlags';
|
||||
import { Filters } from '../dashboard/reducers/types';
|
||||
import { getInitialDataMask } from './reducer';
|
||||
|
||||
export const CLEAR_DATA_MASK_STATE = 'CLEAR_DATA_MASK_STATE';
|
||||
|
|
|
@ -20,23 +20,25 @@
|
|||
/* eslint-disable no-param-reassign */
|
||||
// <- When we work with Immer, we need reassign, so disabling lint
|
||||
import produce from 'immer';
|
||||
import { DataMask, FeatureFlag } from '@superset-ui/core';
|
||||
import {
|
||||
DataMask,
|
||||
DataMaskStateWithId,
|
||||
DataMaskWithId,
|
||||
FeatureFlag,
|
||||
Filter,
|
||||
FilterConfiguration,
|
||||
Filters,
|
||||
} from '@superset-ui/core';
|
||||
import { NATIVE_FILTER_PREFIX } from 'src/dashboard/components/nativeFilters/FiltersConfigModal/utils';
|
||||
import { HYDRATE_DASHBOARD } from 'src/dashboard/actions/hydrate';
|
||||
import { isFeatureEnabled } from 'src/featureFlags';
|
||||
import { DataMaskStateWithId, DataMaskWithId } from './types';
|
||||
import {
|
||||
AnyDataMaskAction,
|
||||
CLEAR_DATA_MASK_STATE,
|
||||
SET_DATA_MASK_FOR_FILTER_CONFIG_COMPLETE,
|
||||
UPDATE_DATA_MASK,
|
||||
} from './actions';
|
||||
import {
|
||||
Filter,
|
||||
FilterConfiguration,
|
||||
} from '../dashboard/components/nativeFilters/types';
|
||||
import { areObjectsEqual } from '../reduxUtils';
|
||||
import { Filters } from '../dashboard/reducers/types';
|
||||
|
||||
export function getInitialDataMask(
|
||||
id?: string | number,
|
||||
|
|
|
@ -25,6 +25,7 @@ import { merge } from 'lodash';
|
|||
import setupClient from './setup/setupClient';
|
||||
import setupColors from './setup/setupColors';
|
||||
import setupFormatters from './setup/setupFormatters';
|
||||
import setupDashboardComponents from './setup/setupDasboardComponents';
|
||||
|
||||
if (process.env.WEBPACK_MODE === 'development') {
|
||||
setHotLoaderConfig({ logLevel: 'debug', trackTailUpdates: false });
|
||||
|
@ -60,6 +61,8 @@ setupColors(
|
|||
// Setup number formatters
|
||||
setupFormatters();
|
||||
|
||||
setupDashboardComponents();
|
||||
|
||||
export const theme = merge(
|
||||
supersetTheme,
|
||||
bootstrapData?.common?.theme_overrides ?? {},
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
This file can be overridden from outside by custom config, it will add/delete new components to existing config in
|
||||
superset-frontend/src/visualizations/presets/dashboardComponents.ts file
|
||||
*/
|
||||
|
||||
// import dashboardComponentsRegistry from '../visualizations/presets/dashboardComponents';
|
||||
// import example from '../visualizations/dashboardComponents/ExampleComponent';
|
||||
|
||||
export default function setupDashboardComponents() {
|
||||
// Add custom dashboard components here. Example:
|
||||
// dashboardComponentsRegistry.set('example', example);
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import React, { ComponentType } from 'react';
|
||||
import { JsonObject } from '@superset-ui/core';
|
||||
|
||||
export interface RegistryMetadata {
|
||||
description: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface ComponentItem<Metadata = RegistryMetadata> {
|
||||
metadata: Metadata;
|
||||
loadComponent: () => Promise<{ default: ComponentType<any> }>;
|
||||
}
|
||||
|
||||
export interface ComponentRegistry<Metadata = RegistryMetadata> {
|
||||
metadata: Metadata;
|
||||
Component: ComponentType<any>;
|
||||
}
|
||||
|
||||
export type FunctionalRegistryState<RegistryT> = {
|
||||
registry: { [key: string]: RegistryT & { key: string } };
|
||||
registryKeys: string[];
|
||||
};
|
||||
|
||||
export const registryGetAll =
|
||||
<RegistryT>({ registryKeys, registry }: FunctionalRegistryState<RegistryT>) =>
|
||||
() =>
|
||||
registryKeys.map(key => registry[key]);
|
||||
|
||||
export const registryDelete =
|
||||
<RegistryT>({ registryKeys, registry }: FunctionalRegistryState<RegistryT>) =>
|
||||
(keyToDelete: string) => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
registryKeys = registryKeys.filter(key => key !== keyToDelete);
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
delete registry[keyToDelete];
|
||||
};
|
||||
|
||||
export const registryGet =
|
||||
<RegistryT>({ registry }: FunctionalRegistryState<RegistryT>) =>
|
||||
(key: string) =>
|
||||
registry[key];
|
||||
|
||||
export const registrySet =
|
||||
({ registryKeys, registry }: FunctionalRegistryState<JsonObject>) =>
|
||||
(key: string, item: JsonObject) => {
|
||||
registryKeys.push(key);
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
registry[key] = {
|
||||
key,
|
||||
...item,
|
||||
};
|
||||
};
|
||||
|
||||
export const registrySetComponent =
|
||||
({ registryKeys, registry }: FunctionalRegistryState<ComponentRegistry>) =>
|
||||
(key: string, item: ComponentItem) => {
|
||||
registryKeys.push(key);
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
registry[key] = {
|
||||
key,
|
||||
metadata: item.metadata,
|
||||
Component: React.lazy(item.loadComponent),
|
||||
};
|
||||
};
|
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import {
|
||||
ComponentItem,
|
||||
ComponentRegistry,
|
||||
FunctionalRegistryState,
|
||||
registryDelete,
|
||||
registryGet,
|
||||
registryGetAll,
|
||||
RegistryMetadata,
|
||||
registrySetComponent,
|
||||
} from '../../utils/functionalRegistry';
|
||||
|
||||
export interface DashboardComponentsRegistryMetadata extends RegistryMetadata {
|
||||
iconName: string;
|
||||
}
|
||||
|
||||
/*
|
||||
This is registry that contains list of dynamic dashboard components that can be added in addition to main components
|
||||
*/
|
||||
|
||||
const DashboardComponentsRegistry = (
|
||||
initComponents: { key: string; item: ComponentItem }[] = [],
|
||||
) => {
|
||||
const state: FunctionalRegistryState<
|
||||
ComponentRegistry<DashboardComponentsRegistryMetadata>
|
||||
> = {
|
||||
registry: {},
|
||||
registryKeys: [],
|
||||
};
|
||||
|
||||
const set = registrySetComponent(state);
|
||||
|
||||
initComponents.forEach(({ key, item }) => {
|
||||
set(key, item);
|
||||
});
|
||||
|
||||
return {
|
||||
set,
|
||||
get: registryGet(state),
|
||||
delete: registryDelete(state),
|
||||
getAll: registryGetAll(state),
|
||||
};
|
||||
};
|
||||
|
||||
export default DashboardComponentsRegistry;
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { DashboardComponentMetadata, t } from '@superset-ui/core';
|
||||
|
||||
// TODO: POC only component can be removed after PR approved
|
||||
const ExampleComponent = ({
|
||||
metadata,
|
||||
}: {
|
||||
metadata: DashboardComponentMetadata;
|
||||
}) => (
|
||||
<div>
|
||||
{t('We have the following keys: %s', Object.keys(metadata).join(', '))}
|
||||
</div>
|
||||
);
|
||||
|
||||
export default ExampleComponent;
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
// TODO: POC only component can be removed after PR approved
|
||||
export default {
|
||||
metadata: {
|
||||
name: 'Example',
|
||||
description: 'Example description',
|
||||
iconName: 'filter',
|
||||
},
|
||||
loadComponent: () => import('./ExampleComponent'),
|
||||
};
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
Preset dashboard components (in addition to basic components like row, column, chart, etc...)
|
||||
*/
|
||||
|
||||
import DashboardComponentsRegistry from '../dashboardComponents/DashboardComponentsRegistry';
|
||||
|
||||
const dashboardComponents = DashboardComponentsRegistry([
|
||||
// Here can be added default dashboard components
|
||||
]);
|
||||
|
||||
export default dashboardComponents;
|
Loading…
Reference in New Issue