Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Dynamic dashboard component #17208

Merged
merged 43 commits into from
Feb 9, 2022
Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
6eb04b1
fix:fix get permission function
simcha90 Apr 13, 2021
5e9a1d8
Merge branch 'master' of github.com:apache/superset
simcha90 Apr 18, 2021
2c5800a
Merge branch 'master' of github.com:apache/superset
simcha90 Apr 20, 2021
ea9aa8b
Merge branch 'master' of github.com:apache/superset
simcha90 Apr 25, 2021
402918a
Merge branch 'master' of github.com:apache/superset
simcha90 Apr 27, 2021
1a3cc39
Merge branch 'master' of github.com:apache/superset
simcha90 Apr 28, 2021
f6d4590
Merge branch 'master' of github.com:apache/superset
simcha90 May 10, 2021
97f2c15
Merge branch 'master' of github.com:apache/superset
simcha90 May 24, 2021
1f31df7
Merge branch 'master' of github.com:apache/superset
simcha90 May 24, 2021
dce7b7a
Merge branch 'master' of github.com:apache/superset
simcha90 May 26, 2021
0334f35
Merge branch 'master' of github.com:apache/superset
simcha90 May 30, 2021
f6dd314
Merge branch 'master' of github.com:apache/superset
simcha90 Jun 17, 2021
64267e1
Merge branch 'master' of github.com:apache/superset
simcha90 Jun 20, 2021
385eddc
Merge branch 'master' of github.com:apache/superset
simcha90 Jun 24, 2021
51a00a3
Merge branch 'master' of github.com:apache/superset
simcha90 Jul 1, 2021
4e94cb5
Merge branch 'master' of github.com:apache/superset
simcha90 Jul 4, 2021
e7fa0a6
Merge branch 'master' of github.com:apache/superset
simcha90 Jul 7, 2021
c3d24d7
Merge branch 'master' of github.com:apache/superset
simcha90 Aug 31, 2021
a3893a4
Merge branch 'master' of github.com:apache/superset
simcha90 Sep 29, 2021
30c516b
Merge branch 'master' of github.com:apache/superset
simcha90 Oct 5, 2021
03165d1
Merge branch 'master' of github.com:apache/superset
simcha90 Oct 7, 2021
9d86002
Merge branch 'master' of github.com:apache/superset
simcha90 Oct 17, 2021
57f4a13
feat: dynamic loading of dashboard components
simcha90 Oct 24, 2021
8556f1c
fix: revert image
simcha90 Oct 24, 2021
56a4e2a
fix: fix py
simcha90 Oct 24, 2021
208e275
fix: fix py
simcha90 Oct 24, 2021
e02ada3
Merge branch 'master' of github.com:apache/superset into dynamic_dash…
simcha90 Oct 27, 2021
369afd4
fix: pass state to dynamic component
simcha90 Oct 27, 2021
278303d
Merge branch 'master' of github.com:apache/superset into dynamic_dash…
simcha90 Nov 4, 2021
ccb5853
lint: add typing
simcha90 Dec 20, 2021
7ee2be4
Merge branch 'master' of github.com:apache/superset into dynamic_dash…
simcha90 Dec 20, 2021
4dd7bec
Merge branch 'master' of github.com:apache/superset into dynamic_dash…
simcha90 Dec 30, 2021
94e2d5b
lint: fix lint
simcha90 Dec 30, 2021
eba9e97
lint: fix lint
simcha90 Jan 2, 2022
503eea8
Merge branch 'master' of github.com:apache/superset into dynamic_dash…
simcha90 Jan 2, 2022
e374836
refactor: re-run pipeline
simcha90 Jan 2, 2022
aca538a
fix: fix CR notes
simcha90 Jan 17, 2022
d54bd9d
fix: fix CR notes
simcha90 Jan 17, 2022
26c0d65
Merge branch 'master' of github.com:apache/superset into dynamic_dash…
simcha90 Jan 25, 2022
3108ae0
move types and interfaces to core
villebro Feb 7, 2022
8d5993e
reorder exports
villebro Feb 9, 2022
b65e977
Merge branch 'master' into dynamic_dashboard_component
villebro Feb 9, 2022
e5b7040
rename Scope and Target
villebro Feb 9, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
/**
* 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 { 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';
import { NativeFiltersState } from '../../reducers/types';
import { DataMaskStateWithId } from '../../../dataMask/types';

type DashboardComponentMetadata = {
nativeFilters: NativeFiltersState;
dataMask: DataMaskStateWithId;
};

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;
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
ROW_TYPE,
TAB_TYPE,
TABS_TYPE,
DYNAMIC_TYPE,
} from '../../util/componentTypes';

import ChartHolder from './ChartHolder';
Expand All @@ -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';
Expand All @@ -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,
Expand All @@ -54,4 +57,5 @@ export const componentLookup = {
[ROW_TYPE]: Row,
[TAB_TYPE]: Tab,
[TABS_TYPE]: TabsConnected,
[DYNAMIC_TYPE]: DynamicComponent,
};
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
13 changes: 11 additions & 2 deletions superset-frontend/src/dashboard/util/componentIsResizable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
);
}
3 changes: 3 additions & 0 deletions superset-frontend/src/dashboard/util/componentTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -42,4 +44,5 @@ export default {
ROW_TYPE,
TABS_TYPE,
TAB_TYPE,
DYNAMIC_TYPE,
};
1 change: 1 addition & 0 deletions superset-frontend/src/dashboard/util/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
COLUMN_TYPE,
MARKDOWN_TYPE,
CHART_TYPE,
DYNAMIC_TYPE,
} from './componentTypes';

function getTotalChildWidth({ id, components }) {
Expand Down Expand Up @@ -84,6 +85,7 @@ export default function getDetailedComponentWidth({
}
});
} else if (
component.type === DYNAMIC_TYPE ||
component.type === MARKDOWN_TYPE ||
component.type === CHART_TYPE
) {
Expand Down
8 changes: 6 additions & 2 deletions superset-frontend/src/dashboard/util/isDashboardEmpty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Loading