fix: SqlLab error when collapsing the left panel preview (#36858)

Co-authored-by: Diego Pucci <diegopucci.me@gmail.com>
This commit is contained in:
Enzo Martellucci
2025-12-31 14:11:59 +01:00
committed by GitHub
parent e112d863bf
commit 7cd76e4647
2 changed files with 205 additions and 18 deletions

View File

@@ -1098,12 +1098,14 @@ export function reFetchQueryResults(query) {
export function expandTable(table) {
return function (dispatch) {
const sync = isFeatureEnabled(FeatureFlag.SqllabBackendPersistence)
? SupersetClient.post({
endpoint: encodeURI(`/tableschemaview/${table.id}/expanded`),
postPayload: { expanded: true },
})
: Promise.resolve();
const sync =
isFeatureEnabled(FeatureFlag.SqllabBackendPersistence) &&
table.initialized
? SupersetClient.post({
endpoint: encodeURI(`/tableschemaview/${table.id}/expanded`),
postPayload: { expanded: true },
})
: Promise.resolve();
return sync
.then(() => dispatch({ type: EXPAND_TABLE, table }))
@@ -1122,12 +1124,14 @@ export function expandTable(table) {
export function collapseTable(table) {
return function (dispatch) {
const sync = isFeatureEnabled(FeatureFlag.SqllabBackendPersistence)
? SupersetClient.post({
endpoint: encodeURI(`/tableschemaview/${table.id}/expanded`),
postPayload: { expanded: false },
})
: Promise.resolve();
const sync =
isFeatureEnabled(FeatureFlag.SqllabBackendPersistence) &&
table.initialized
? SupersetClient.post({
endpoint: encodeURI(`/tableschemaview/${table.id}/expanded`),
postPayload: { expanded: false },
})
: Promise.resolve();
return sync
.then(() => dispatch({ type: COLLAPSE_TABLE, table }))

View File

@@ -934,6 +934,10 @@ describe('async actions', () => {
fetchMock.delete(updateTableSchemaEndpoint, {});
fetchMock.post(updateTableSchemaEndpoint, JSON.stringify({ id: 1 }));
const updateTableSchemaExpandedEndpoint =
'glob:**/tableschemaview/*/expanded';
fetchMock.post(updateTableSchemaExpandedEndpoint, {});
const getTableMetadataEndpoint =
'glob:**/api/v1/database/*/table_metadata/*';
fetchMock.get(getTableMetadataEndpoint, {});
@@ -1411,10 +1415,10 @@ describe('async actions', () => {
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('expandTable', () => {
test('updates the table schema state in the backend', () => {
test('updates the table schema state in the backend when initialized', () => {
expect.assertions(2);
const table = { id: 1 };
const table = { id: 1, initialized: true };
const store = mockStore({});
const expectedActions = [
{
@@ -1424,17 +1428,108 @@ describe('async actions', () => {
];
return store.dispatch(actions.expandTable(table)).then(() => {
expect(store.getActions()).toEqual(expectedActions);
expect(fetchMock.calls(updateTableSchemaEndpoint)).toHaveLength(1);
const expandedCalls = fetchMock
.calls()
.filter(
call =>
call[0] &&
call[0].includes('/tableschemaview/') &&
call[0].includes('/expanded'),
);
expect(expandedCalls).toHaveLength(1);
});
});
test('does not call backend when table is not initialized', () => {
expect.assertions(2);
const table = { id: 'yVJPtuSackF', initialized: false };
const store = mockStore({});
const expectedActions = [
{
type: actions.EXPAND_TABLE,
table,
},
];
return store.dispatch(actions.expandTable(table)).then(() => {
expect(store.getActions()).toEqual(expectedActions);
// Check all POST calls to find the expanded endpoint
const expandedCalls = fetchMock
.calls()
.filter(
call =>
call[0] &&
call[0].includes('/tableschemaview/') &&
call[0].includes('/expanded'),
);
expect(expandedCalls).toHaveLength(0);
});
});
test('does not call backend when initialized is undefined', () => {
expect.assertions(2);
const table = { id: 'yVJPtuSackF' };
const store = mockStore({});
const expectedActions = [
{
type: actions.EXPAND_TABLE,
table,
},
];
return store.dispatch(actions.expandTable(table)).then(() => {
expect(store.getActions()).toEqual(expectedActions);
// Check all POST calls to find the expanded endpoint
const expandedCalls = fetchMock
.calls()
.filter(
call =>
call[0] &&
call[0].includes('/tableschemaview/') &&
call[0].includes('/expanded'),
);
expect(expandedCalls).toHaveLength(0);
});
});
test('does not call backend when feature flag is off', () => {
expect.assertions(2);
isFeatureEnabled.mockImplementation(
feature => !(feature === 'SQLLAB_BACKEND_PERSISTENCE'),
);
const table = { id: 1, initialized: true };
const store = mockStore({});
const expectedActions = [
{
type: actions.EXPAND_TABLE,
table,
},
];
return store.dispatch(actions.expandTable(table)).then(() => {
expect(store.getActions()).toEqual(expectedActions);
// Check all POST calls to find the expanded endpoint
const expandedCalls = fetchMock
.calls()
.filter(
call =>
call[0] &&
call[0].includes('/tableschemaview/') &&
call[0].includes('/expanded'),
);
expect(expandedCalls).toHaveLength(0);
isFeatureEnabled.mockRestore();
});
});
});
// eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks
describe('collapseTable', () => {
test('updates the table schema state in the backend', () => {
test('updates the table schema state in the backend when initialized', () => {
expect.assertions(2);
const table = { id: 1 };
const table = { id: 1, initialized: true };
const store = mockStore({});
const expectedActions = [
{
@@ -1444,7 +1539,95 @@ describe('async actions', () => {
];
return store.dispatch(actions.collapseTable(table)).then(() => {
expect(store.getActions()).toEqual(expectedActions);
expect(fetchMock.calls(updateTableSchemaEndpoint)).toHaveLength(1);
const expandedCalls = fetchMock
.calls()
.filter(
call =>
call[0] &&
call[0].includes('/tableschemaview/') &&
call[0].includes('/expanded'),
);
expect(expandedCalls).toHaveLength(1);
});
});
test('does not call backend when table is not initialized', () => {
expect.assertions(2);
const table = { id: 'yVJPtuSackF', initialized: false };
const store = mockStore({});
const expectedActions = [
{
type: actions.COLLAPSE_TABLE,
table,
},
];
return store.dispatch(actions.collapseTable(table)).then(() => {
expect(store.getActions()).toEqual(expectedActions);
const expandedCalls = fetchMock
.calls()
.filter(
call =>
call[0] &&
call[0].includes('/tableschemaview/') &&
call[0].includes('/expanded'),
);
expect(expandedCalls).toHaveLength(0);
});
});
test('does not call backend when initialized is undefined', () => {
expect.assertions(2);
const table = { id: 'yVJPtuSackF' };
const store = mockStore({});
const expectedActions = [
{
type: actions.COLLAPSE_TABLE,
table,
},
];
return store.dispatch(actions.collapseTable(table)).then(() => {
expect(store.getActions()).toEqual(expectedActions);
const expandedCalls = fetchMock
.calls()
.filter(
call =>
call[0] &&
call[0].includes('/tableschemaview/') &&
call[0].includes('/expanded'),
);
expect(expandedCalls).toHaveLength(0);
});
});
test('does not call backend when feature flag is off', () => {
expect.assertions(2);
isFeatureEnabled.mockImplementation(
feature => !(feature === 'SQLLAB_BACKEND_PERSISTENCE'),
);
const table = { id: 1, initialized: true };
const store = mockStore({});
const expectedActions = [
{
type: actions.COLLAPSE_TABLE,
table,
},
];
return store.dispatch(actions.collapseTable(table)).then(() => {
expect(store.getActions()).toEqual(expectedActions);
const expandedCalls = fetchMock
.calls()
.filter(
call =>
call[0] &&
call[0].includes('/tableschemaview/') &&
call[0].includes('/expanded'),
);
expect(expandedCalls).toHaveLength(0);
isFeatureEnabled.mockRestore();
});
});
});