Skip to content
Snippets Groups Projects
Unverified Commit def15e33 authored by Emmad Usmani's avatar Emmad Usmani Committed by GitHub
Browse files

show different empty state on dashboards without write access (#32597)

* fix dashboard empty state logic

* address comments
parent 2eb1d185
No related branches found
No related tags found
No related merge requests found
......@@ -30,6 +30,7 @@ describe("scenarios > dashboard > tabs", () => {
visitDashboardAndCreateTab({ dashboardId: 1, save: false });
dashboardCards().within(() => {
cy.findByText("Orders").should("not.exist");
cy.findByText(`There's nothing here, yet.`).should("be.visible");
});
// Add card to second tab
......
......@@ -27,7 +27,7 @@ import {
} from "./Dashboard.styled";
import {
DashboardEmptyState,
TabEmptyState,
DashboardEmptyStateWithoutAddPrompt,
} from "./DashboardEmptyState/DashboardEmptyState";
import { updateParametersWidgetStickiness } from "./stickyParameters";
......@@ -234,6 +234,55 @@ class Dashboard extends Component {
this.props.toggleSidebar(SIDEBAR_NAME.addQuestion);
};
renderContent = () => {
const { dashboard, selectedTabId, isNightMode, isFullscreen } = this.props;
const canWrite = dashboard?.can_write ?? false;
const dashboardHasCards = dashboard?.ordered_cards.length > 0 ?? false;
const tabHasCards =
dashboard?.ordered_cards.filter(
c =>
selectedTabId !== undefined && c.dashboard_tab_id === selectedTabId,
).length > 0 ?? false;
const shouldRenderAsNightMode = isNightMode && isFullscreen;
if (!dashboardHasCards && !canWrite) {
return (
<DashboardEmptyStateWithoutAddPrompt
isNightMode={shouldRenderAsNightMode}
/>
);
}
if (!dashboardHasCards) {
return (
<DashboardEmptyState
dashboard={dashboard}
isNightMode={shouldRenderAsNightMode}
addQuestion={this.onAddQuestion}
closeNavbar={this.props.closeNavbar}
/>
);
}
if (dashboardHasCards && !tabHasCards) {
return (
<DashboardEmptyStateWithoutAddPrompt
isNightMode={shouldRenderAsNightMode}
/>
);
}
return (
<DashboardGrid
{...this.props}
dashboard={this.props.dashboard}
isNightMode={shouldRenderAsNightMode}
onEditingChange={this.setEditing}
/>
);
};
render() {
const {
addParameter,
......@@ -254,18 +303,12 @@ class Dashboard extends Component {
isHeaderVisible,
embedOptions,
isAutoApplyFilters,
selectedTabId,
} = this.props;
const { error, isParametersWidgetSticky } = this.state;
const shouldRenderAsNightMode = isNightMode && isFullscreen;
const dashboardHasCards = dashboard?.ordered_cards.length > 0 ?? false;
const tabHasCards =
dashboard?.ordered_cards.filter(
c =>
selectedTabId !== undefined && c.dashboard_tab_id === selectedTabId,
).length > 0 ?? false;
const visibleParameters = getVisibleParameters(parameters);
const parametersWidget = (
......@@ -354,23 +397,7 @@ class Dashboard extends Component {
addMarginTop={cardsContainerShouldHaveMarginTop}
id="Dashboard-Cards-Container"
>
{dashboardHasCards && tabHasCards ? (
<DashboardGrid
{...this.props}
dashboard={this.props.dashboard}
isNightMode={shouldRenderAsNightMode}
onEditingChange={this.setEditing}
/>
) : dashboardHasCards ? (
<TabEmptyState isNightMode={shouldRenderAsNightMode} />
) : (
<DashboardEmptyState
dashboard={dashboard}
isNightMode={shouldRenderAsNightMode}
addQuestion={this.onAddQuestion}
closeNavbar={this.props.closeNavbar}
/>
)}
{this.renderContent()}
</CardsContainer>
</ParametersAndCardsContainer>
......
......@@ -54,11 +54,13 @@ export function DashboardEmptyState({
);
}
interface TabEmptyStateProps {
interface DashboardEmptyStateWithoutAddPromptProps {
isNightMode: boolean;
}
export function TabEmptyState({ isNightMode }: TabEmptyStateProps) {
export function DashboardEmptyStateWithoutAddPrompt({
isNightMode,
}: DashboardEmptyStateWithoutAddPromptProps) {
return (
<Container isNightMode={isNightMode}>
<EmptyState title={t`There's nothing here, yet.`} />
......
import { render, screen } from "@testing-library/react";
import { createMockDashboard } from "metabase-types/api/mocks";
import { DashboardEmptyState, TabEmptyState } from "./DashboardEmptyState";
import {
DashboardEmptyState,
DashboardEmptyStateWithoutAddPrompt,
} from "./DashboardEmptyState";
describe("DashboardEmptyState", () => {
it("renders", () => {
......@@ -22,9 +25,9 @@ describe("DashboardEmptyState", () => {
});
});
describe("TabEmptyState", () => {
describe("DashboardEmptyStateWithoutAddPrompt", () => {
it("renders", () => {
render(<TabEmptyState isNightMode={false} />);
render(<DashboardEmptyStateWithoutAddPrompt isNightMode={false} />);
expect(screen.getByText("There's nothing here, yet.")).toBeInTheDocument();
});
......
import { Route } from "react-router";
import userEvent from "@testing-library/user-event";
import {
screen,
renderWithProviders,
......@@ -7,6 +8,7 @@ import {
} from "__support__/ui";
import DashboardApp from "metabase/dashboard/containers/DashboardApp";
import { BEFORE_UNLOAD_UNSAVED_MESSAGE } from "metabase/hooks/use-before-unload";
import type { Dashboard } from "metabase-types/api";
import {
createMockCard,
createMockCollection,
......@@ -14,7 +16,6 @@ import {
createMockDashboard,
createMockDatabase,
createMockTable,
createMockUser,
} from "metabase-types/api/mocks";
import { createMockDashboardState } from "metabase-types/store/mocks";
import {
......@@ -31,7 +32,6 @@ import {
import { createMockEntitiesState } from "__support__/store";
import { callMockEvent } from "__support__/events";
const TEST_DASHBOARD = createMockDashboard();
const TEST_COLLECTION = createMockCollection();
const TEST_DATABASE_WITH_ACTIONS = createMockDatabase({
......@@ -47,22 +47,24 @@ const TEST_CARD = createMockCard();
const TEST_TABLE = createMockTable();
async function setup({ user = createMockUser() }) {
async function setup({ dashboard }: { dashboard?: Partial<Dashboard> } = {}) {
const mockDashboard = createMockDashboard(dashboard);
setupDatabasesEndpoints([TEST_DATABASE_WITH_ACTIONS]);
setupDashboardEndpoints(createMockDashboard(TEST_DASHBOARD));
setupDashboardEndpoints(mockDashboard);
setupCollectionsEndpoints({ collections: [] });
setupCollectionItemsEndpoint(TEST_COLLECTION);
setupSearchEndpoints([TEST_COLLECTION_ITEM]);
setupCardsEndpoints([TEST_CARD]);
setupTableEndpoints([TEST_TABLE]);
setupTableEndpoints(TEST_TABLE);
setupBookmarksEndpoints([]);
setupActionsEndpoints([]);
window.HTMLElement.prototype.scrollIntoView = function () {};
window.HTMLElement.prototype.scrollIntoView = () => null;
const mockEventListener = jest.spyOn(window, "addEventListener");
const DashboardAppContainer = props => {
const DashboardAppContainer = (props: any) => {
return (
<main>
<link rel="icon" />
......@@ -74,8 +76,7 @@ async function setup({ user = createMockUser() }) {
renderWithProviders(
<Route path="/dashboard/:slug" component={DashboardAppContainer} />,
{
initialRoute: `/dashboard/${TEST_DASHBOARD.id}`,
currentUser: user,
initialRoute: `/dashboard/${mockDashboard.id}`,
withRouter: true,
storeInitialState: {
dashboard: createMockDashboardState(),
......@@ -104,7 +105,7 @@ describe("DashboardApp", function () {
});
it("should have a beforeunload event when the user tries to leave a dirty dashboard", async function () {
const { mockEventListener } = await setup({});
const { mockEventListener } = await setup();
userEvent.click(screen.getByLabelText("Edit dashboard"));
userEvent.click(screen.getByTestId("dashboard-name-heading"));
......@@ -119,7 +120,7 @@ describe("DashboardApp", function () {
});
it("should not have a beforeunload event when the dashboard is unedited", async function () {
const { mockEventListener } = await setup({});
const { mockEventListener } = await setup();
userEvent.click(screen.getByLabelText("Edit dashboard"));
......@@ -128,4 +129,20 @@ describe("DashboardApp", function () {
expect(mockEvent.returnValue).toBe(undefined);
});
});
describe("empty dashboard", () => {
it("should prompt the user to add a question if they have write access", async () => {
await setup();
expect(screen.getByText(/add a saved question/i)).toBeInTheDocument();
});
it("should should show an empty state without the 'add a question' prompt if the user lacks write access", async () => {
await setup({ dashboard: { can_write: false } });
expect(
screen.getByText(/there's nothing here, yet./i),
).toBeInTheDocument();
});
});
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment