From 918fe8e086d2a6286bc4c026a513ffb2085e3356 Mon Sep 17 00:00:00 2001 From: Kamil Gabryjelski Date: Mon, 14 Feb 2022 12:49:29 +0100 Subject: [PATCH 1/4] feat(dashboard): Implement empty states for dashboard --- .../src/assets/images/dashboard.svg | 15 ++ .../src/components/EmptyState/index.tsx | 3 +- .../DashboardBuilder/DashboardBuilder.tsx | 25 ++- .../dashboard/components/DashboardGrid.jsx | 176 ++++++++++-------- 4 files changed, 140 insertions(+), 79 deletions(-) create mode 100644 superset-frontend/src/assets/images/dashboard.svg diff --git a/superset-frontend/src/assets/images/dashboard.svg b/superset-frontend/src/assets/images/dashboard.svg new file mode 100644 index 0000000000000..8950f3a268331 --- /dev/null +++ b/superset-frontend/src/assets/images/dashboard.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/superset-frontend/src/components/EmptyState/index.tsx b/superset-frontend/src/components/EmptyState/index.tsx index 99a6ce7bc7160..a4d41f2e3bd78 100644 --- a/superset-frontend/src/components/EmptyState/index.tsx +++ b/superset-frontend/src/components/EmptyState/index.tsx @@ -35,7 +35,7 @@ export interface EmptyStateSmallProps { } export interface EmptyStateProps extends EmptyStateSmallProps { - buttonText?: string; + buttonText?: string | ReactNode; buttonAction?: React.MouseEventHandler; } @@ -103,6 +103,7 @@ const SmallDescription = styled(Description)` const ActionButton = styled(Button)` ${({ theme }) => css` margin-top: ${theme.gridUnit * 4}px; + z-index: 1; `} `; diff --git a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx index bd6e663db68fd..23134a01fd387 100644 --- a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx +++ b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx @@ -19,7 +19,9 @@ /* eslint-env browser */ import cx from 'classnames'; import React, { FC, useCallback, useMemo } from 'react'; -import { JsonObject, styled, css } from '@superset-ui/core'; +import { JsonObject, styled, css, t } from '@superset-ui/core'; +import { Global } from '@emotion/react'; +import { useDispatch, useSelector } from 'react-redux'; import ErrorBoundary from 'src/components/ErrorBoundary'; import BuilderComponentPane from 'src/dashboard/components/BuilderComponentPane'; import DashboardHeader from 'src/dashboard/containers/DashboardHeader'; @@ -30,7 +32,6 @@ import DashboardComponent from 'src/dashboard/containers/DashboardComponent'; import WithPopoverMenu from 'src/dashboard/components/menu/WithPopoverMenu'; import getDirectPathToTabIndex from 'src/dashboard/util/getDirectPathToTabIndex'; import { URL_PARAMS } from 'src/constants'; -import { useDispatch, useSelector } from 'react-redux'; import { getUrlParam } from 'src/utils/urlUtils'; import { DashboardLayout, RootState } from 'src/dashboard/types'; import { setDirectPathToChild } from 'src/dashboard/actions/dashboardState'; @@ -48,7 +49,7 @@ import { } from 'src/dashboard/util/constants'; import FilterBar from 'src/dashboard/components/nativeFilters/FilterBar'; import Loading from 'src/components/Loading'; -import { Global } from '@emotion/react'; +import { EmptyStateBig } from 'src/components/EmptyState'; import { useUiConfig } from 'src/components/UiConfigContext'; import { shouldFocusTabs, getRootLevelTabsComponent } from './utils'; import DashboardContainer from './DashboardContainer'; @@ -187,6 +188,7 @@ const StyledDashboardContent = styled.div<{ .dashboard-builder-sidepane { width: ${BUILDER_SIDEPANEL_WIDTH}px; + z-index: 1; } .dashboard-component-chart-holder { @@ -208,6 +210,9 @@ const DashboardBuilder: FC = () => { const editMode = useSelector( state => state.dashboardState.editMode, ); + const canEdit = useSelector( + ({ dashboardInfo }) => dashboardInfo.dash_edit_perm, + ); const directPathToChild = useSelector( state => state.dashboardState.directPathToChild, ); @@ -374,6 +379,20 @@ const DashboardBuilder: FC = () => { `div > .filterStatusPopover.ant-popover{z-index: 101}`} `} /> + {!editMode && + !topLevelTabs && + dashboardLayout[DASHBOARD_GRID_ID]?.children?.length === 0 && ( + + )}
); +const DashboardEmptyStateContainer = styled.div` + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; +`; + class DashboardGrid extends React.PureComponent { constructor(props) { super(props); @@ -140,82 +148,100 @@ class DashboardGrid extends React.PureComponent { const { isResizing, rowGuideTop } = this.state; return width < 100 ? null : ( -
-
- {/* make the area above components droppable */} - {editMode && ( - - {renderDraggableContentBottom} - - )} - - {gridComponent?.children?.map((id, index) => ( - - ))} - - {/* make the area below components droppable */} - {editMode && gridComponent?.children?.length > 0 && ( - - {renderDraggableContentTop} - - )} - - {isResizing && - Array(GRID_COLUMN_COUNT) - .fill(null) - .map((_, i) => ( -
- ))} - - {isResizing && rowGuideTop && ( -
+ {editMode && gridComponent?.children?.length === 0 && ( + + + + {t('Create a new chart')} + + } + buttonAction={() => { + window.location.assign('/chart/add'); }} + image="chart.svg" /> - )} + + )} +
+
+ {/* make the area above components droppable */} + {editMode && ( + + {renderDraggableContentBottom} + + )} + {gridComponent?.children?.map((id, index) => ( + + ))} + {/* make the area below components droppable */} + {editMode && gridComponent?.children?.length > 0 && ( + + {renderDraggableContentTop} + + )} + {isResizing && + Array(GRID_COLUMN_COUNT) + .fill(null) + .map((_, i) => ( +
+ ))} + {isResizing && rowGuideTop && ( +
+ )} +
-
+ ); } } From 0ce1a045874c04817d148700317b0722e0daa871 Mon Sep 17 00:00:00 2001 From: Kamil Gabryjelski Date: Mon, 14 Feb 2022 13:05:36 +0100 Subject: [PATCH 2/4] Add empty state to native filters --- .../nativeFilters/FilterBar/index.tsx | 34 ++++++++++++++++--- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx index 6b07c2c7234ab..b8d5a4b6dc43c 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx @@ -44,6 +44,7 @@ import Loading from 'src/components/Loading'; import { getInitialDataMask } from 'src/dataMask/reducer'; import { URL_PARAMS } from 'src/constants'; import { getUrlParam } from 'src/utils/urlUtils'; +import { EmptyStateSmall } from 'src/components/EmptyState'; import { checkIsApplyDisabled, TabIds } from './utils'; import FilterSets from './FilterSets'; import { @@ -57,6 +58,7 @@ import { createFilterKey, updateFilterKey } from './keyValue'; import EditSection from './FilterSets/EditSection'; import Header from './Header'; import FilterControls from './FilterControls/FilterControls'; +import { RootState } from '../../../types'; export const FILTER_BAR_TEST_ID = 'filter-bar'; export const getFilterBarTestId = testWithId(FILTER_BAR_TEST_ID); @@ -135,6 +137,10 @@ const StyledTabs = styled(Tabs)` } `; +const FilterBarEmptyStateContainer = styled.div` + margin-top: ${({ theme }) => theme.gridUnit * 8}px; +`; + export interface FiltersBarProps { filtersOpen: boolean; toggleFiltersBar: any; @@ -168,6 +174,9 @@ const FilterBar: React.FC = ({ const dashboardId = useSelector( ({ dashboardInfo }) => dashboardInfo?.id, ); + const canEdit = useSelector( + ({ dashboardInfo }) => dashboardInfo.dash_edit_perm, + ); const handleFilterSelectionChange = useCallback( ( @@ -382,11 +391,26 @@ const FilterBar: React.FC = ({ ) : (
- + {filterValues.length === 0 ? ( + + + + ) : ( + + )}
)} From d4bf481502cbc625b83fe1411410ff8412ab5eb6 Mon Sep 17 00:00:00 2001 From: Kamil Gabryjelski Date: Mon, 14 Feb 2022 13:08:35 +0100 Subject: [PATCH 3/4] Add missing license --- .../src/assets/images/dashboard.svg | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/superset-frontend/src/assets/images/dashboard.svg b/superset-frontend/src/assets/images/dashboard.svg index 8950f3a268331..161f93a98b419 100644 --- a/superset-frontend/src/assets/images/dashboard.svg +++ b/superset-frontend/src/assets/images/dashboard.svg @@ -1,3 +1,21 @@ + From 89f113d487add72d0b49f02cff463f5fb5755b29 Mon Sep 17 00:00:00 2001 From: Kamil Gabryjelski Date: Mon, 14 Feb 2022 14:30:30 +0100 Subject: [PATCH 4/4] Remove redundant string types from EmptyState --- superset-frontend/src/components/EmptyState/index.tsx | 10 +++++----- .../components/DashboardBuilder/DashboardBuilder.tsx | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/superset-frontend/src/components/EmptyState/index.tsx b/superset-frontend/src/components/EmptyState/index.tsx index a4d41f2e3bd78..e27c72894c15e 100644 --- a/superset-frontend/src/components/EmptyState/index.tsx +++ b/superset-frontend/src/components/EmptyState/index.tsx @@ -29,18 +29,18 @@ export enum EmptyStateSize { } export interface EmptyStateSmallProps { - title: string | ReactNode; - description?: string | ReactNode; - image: string | ReactNode; + title: ReactNode; + description?: ReactNode; + image: ReactNode; } export interface EmptyStateProps extends EmptyStateSmallProps { - buttonText?: string | ReactNode; + buttonText?: ReactNode; buttonAction?: React.MouseEventHandler; } export interface ImageContainerProps { - image: string | ReactNode; + image: ReactNode; size: EmptyStateSize; } diff --git a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx index 23134a01fd387..577351a389dbc 100644 --- a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx +++ b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx @@ -134,7 +134,7 @@ const StyledHeader = styled.div` grid-column: 2; grid-row: 1; position: sticky; - top: 0px; + top: 0; z-index: 100; `; @@ -164,7 +164,7 @@ const StyledDashboardContent = styled.div<{ .grid-container { /* without this, the grid will not get smaller upon toggling the builder panel on */ - width: 0px; + width: 0; flex: 1; position: relative; margin-top: ${({ theme }) => theme.gridUnit * 6}px;