Skip to content

Commit

Permalink
Fix metadata loading issues after tabs (#42655)
Browse files Browse the repository at this point in the history
  • Loading branch information
ranquild committed May 14, 2024
1 parent 50a03a1 commit 1519acb
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { loadMetadataForDashboard } from "metabase/dashboard/actions/metadata";
import {
getDashboardById,
getDashCardById,
getInitialSelectedTabId,
getParameterValues,
getQuestions,
getSelectedTabId,
Expand Down Expand Up @@ -126,10 +127,11 @@ export const fetchDashboard = createAsyncThunk(
fetchDashboardCancellation = null;

if (dashboardType === "normal" || dashboardType === "transient") {
const selectedTabId = getSelectedTabId(getState());
const selectedTabId =
getSelectedTabId(getState()) ?? getInitialSelectedTabId(result);

const cards =
selectedTabId === undefined
selectedTabId == null
? result.dashcards
: result.dashcards.filter(
(c: DashboardCard) => c.dashboard_tab_id === selectedTabId,
Expand Down
161 changes: 140 additions & 21 deletions frontend/src/metabase/dashboard/actions/data-fetching.unit.spec.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,163 @@
import { configureStore } from "@reduxjs/toolkit";
import fetchMock from "fetch-mock";

import { setupDashboardEndpoints } from "__support__/server-mocks";
import { getStore } from "__support__/entities-store";
import {
setupDashboardsEndpoints,
setupDatabaseEndpoints,
} from "__support__/server-mocks";
import { createMockEntitiesState } from "__support__/store";
import { Api } from "metabase/api";
import {
createMockCard,
createMockDashboard,
createMockDatabase,
createMockDashboardCard,
createMockDashboardTab,
createMockSettings,
createMockStructuredDatasetQuery,
} from "metabase-types/api/mocks";
import {
createSampleDatabase,
ORDERS_ID,
PRODUCTS_ID,
} from "metabase-types/api/mocks/presets";
import { createMockDashboardState } from "metabase-types/store/mocks";

import { dashboardReducers } from "../reducers";

import { fetchDashboard } from "./data-fetching-typed";

function setup({ dashboards = [] }) {
const database = createSampleDatabase();
const state = {
dashboard: createMockDashboardState(),
entities: createMockEntitiesState({
databases: [database],
}),
settings: createMockSettings(),
};

const store = getStore(
{
[Api.reducerPath]: Api.reducer,
dashboard: dashboardReducers,
entities: (state = {}) => state,
settings: (state = {}) => state,
},
state,
[Api.middleware],
);

setupDatabaseEndpoints(database);
setupDashboardsEndpoints(dashboards);

return store;
}

describe("fetchDashboard", () => {
let store;
it("should fetch metadata for all cards when there are no tabs", async () => {
const dashboard = createMockDashboard({
dashcards: [
createMockDashboardCard({
card: createMockCard({
dataset_query: createMockStructuredDatasetQuery({
query: {
"source-table": PRODUCTS_ID,
},
}),
}),
}),
createMockDashboardCard({
card: createMockCard({
dataset_query: createMockStructuredDatasetQuery({
query: {
"source-table": ORDERS_ID,
},
}),
}),
}),
],
});
const store = setup({
dashboards: [dashboard],
});

beforeEach(() => {
const state = {
dashboard: createMockDashboardState(),
entities: createMockEntitiesState({
databases: [createMockDatabase()],
await store.dispatch(
fetchDashboard({
dashId: dashboard.id,
queryParams: {},
options: {},
}),
settings: createMockSettings(),
};

store = configureStore({
reducer: {
dashboard: dashboardReducers,
entities: (state = {}) => state,
settings: (state = {}) => state,
},
preloadedState: state,
);

expect(
fetchMock.calls(`path:/api/table/${PRODUCTS_ID}/query_metadata`),
).toHaveLength(1);
expect(
fetchMock.calls(`path:/api/table/${ORDERS_ID}/query_metadata`),
).toHaveLength(1);
});

it("should fetch metadata for cards on the first tab when there are tabs", async () => {
const dashboard = createMockDashboard({
dashcards: [
createMockDashboardCard({
card: createMockCard({
dataset_query: createMockStructuredDatasetQuery({
query: {
"source-table": PRODUCTS_ID,
},
}),
}),
dashboard_tab_id: 1,
}),
createMockDashboardCard({
card: createMockCard({
dataset_query: createMockStructuredDatasetQuery({
query: {
"source-table": ORDERS_ID,
},
}),
}),
dashboard_tab_id: 2,
}),
],
tabs: [
createMockDashboardTab({
id: 1,
}),
createMockDashboardTab({
id: 2,
}),
],
});
const store = setup({
dashboards: [dashboard],
});

setupDashboardEndpoints(createMockDashboard({ id: 1 }));
setupDashboardEndpoints(createMockDashboard({ id: 2 }));
await store.dispatch(
fetchDashboard({
dashId: dashboard.id,
queryParams: {},
options: {},
}),
);

expect(
fetchMock.calls(`path:/api/table/${PRODUCTS_ID}/query_metadata`),
).toHaveLength(1);
expect(
fetchMock.calls(`path:/api/table/${ORDERS_ID}/query_metadata`),
).toHaveLength(0);
});

it("should cancel previous dashboard fetch when a new one is initiated (metabase#35959)", async () => {
const store = setup({
dashboards: [
createMockDashboard({ id: 1 }),
createMockDashboard({ id: 2 }),
],
});

const firstFetch = store.dispatch(
fetchDashboard({
dashId: 1,
Expand Down
8 changes: 7 additions & 1 deletion frontend/src/metabase/dashboard/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ import type {
DashboardCard,
DashboardParameterMapping,
ParameterId,
Dashboard,
} from "metabase-types/api";
import type {
ClickBehaviorSidebarState,
EditParameterSidebarState,
State,
StoreDashboard,
} from "metabase-types/store";

import { isQuestionCard, isQuestionDashCard } from "./utils";
Expand Down Expand Up @@ -423,13 +425,17 @@ export const getSelectedTabId = createSelector(
[getDashboard, state => state.dashboard.selectedTabId],
(dashboard, selectedTabId) => {
if (dashboard && selectedTabId === null) {
return dashboard.tabs?.[0]?.id || null;
return getInitialSelectedTabId(dashboard);
}

return selectedTabId;
},
);

export function getInitialSelectedTabId(dashboard: Dashboard | StoreDashboard) {
return dashboard.tabs?.[0]?.id || null;
}

export const getParameterMappingsBeforeEditing = createSelector(
[getDashboardBeforeEditing],
editingDashboard => {
Expand Down

0 comments on commit 1519acb

Please sign in to comment.