Skip to content
Snippets Groups Projects
Unverified Commit 1519acb6 authored by Alexander Polyankin's avatar Alexander Polyankin Committed by GitHub
Browse files

Fix metadata loading issues after tabs (#42655)

parent 50a03a19
No related branches found
No related tags found
No related merge requests found
......@@ -4,6 +4,7 @@ import { loadMetadataForDashboard } from "metabase/dashboard/actions/metadata";
import {
getDashboardById,
getDashCardById,
getInitialSelectedTabId,
getParameterValues,
getQuestions,
getSelectedTabId,
......@@ -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,
......
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,
......
......@@ -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";
......@@ -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 => {
......
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