mirror of
https://github.com/apache/superset.git
synced 2026-04-23 18:14:56 +00:00
refactor(sqllab): nonblocking switch query editor (#29108)
This commit is contained in:
@@ -58,6 +58,7 @@ const unsavedSqlLabState = {
|
||||
},
|
||||
editorTabLastUpdatedAt,
|
||||
};
|
||||
|
||||
beforeAll(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
@@ -66,6 +67,16 @@ afterAll(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
const updateActiveEditorTabState = `glob:*/tabstateview/*/activate`;
|
||||
|
||||
beforeEach(() => {
|
||||
fetchMock.post(updateActiveEditorTabState, {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fetchMock.reset();
|
||||
});
|
||||
|
||||
test('sync the unsaved editor tab state when there are new changes since the last update', async () => {
|
||||
const updateEditorTabState = `glob:*/tabstateview/${defaultQueryEditor.id}`;
|
||||
fetchMock.put(updateEditorTabState, 200);
|
||||
@@ -108,6 +119,33 @@ test('sync the unsaved NEW editor state when there are new in local storage', as
|
||||
fetchMock.restore();
|
||||
});
|
||||
|
||||
test('sync the active editor id when there are updates in tab history', async () => {
|
||||
expect(fetchMock.calls(updateActiveEditorTabState)).toHaveLength(0);
|
||||
render(<EditorAutoSync />, {
|
||||
useRedux: true,
|
||||
initialState: {
|
||||
...initialState,
|
||||
sqlLab: {
|
||||
...initialState.sqlLab,
|
||||
lastUpdatedActiveTab: 'old-tab-id',
|
||||
queryEditors: [
|
||||
...initialState.sqlLab.queryEditors,
|
||||
{
|
||||
id: 'rnd-new-id12',
|
||||
name: 'new tab name',
|
||||
inLocalStorage: false,
|
||||
},
|
||||
],
|
||||
tabHistory: ['old-tab-id', 'rnd-new-id12'],
|
||||
},
|
||||
},
|
||||
});
|
||||
await waitFor(() => jest.advanceTimersByTime(INTERVAL));
|
||||
expect(fetchMock.calls(updateActiveEditorTabState)).toHaveLength(1);
|
||||
await waitFor(() => jest.advanceTimersByTime(INTERVAL));
|
||||
expect(fetchMock.calls(updateActiveEditorTabState)).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('skip syncing the unsaved editor tab state when the updates are already synced', async () => {
|
||||
const updateEditorTabState = `glob:*/tabstateview/${defaultQueryEditor.id}`;
|
||||
fetchMock.put(updateEditorTabState, 200);
|
||||
|
||||
@@ -26,11 +26,15 @@ import {
|
||||
QueryEditor,
|
||||
UnsavedQueryEditor,
|
||||
} from 'src/SqlLab/types';
|
||||
import { useUpdateSqlEditorTabMutation } from 'src/hooks/apiResources/sqlEditorTabs';
|
||||
import {
|
||||
useUpdateCurrentSqlEditorTabMutation,
|
||||
useUpdateSqlEditorTabMutation,
|
||||
} from 'src/hooks/apiResources/sqlEditorTabs';
|
||||
import { useDebounceValue } from 'src/hooks/useDebounceValue';
|
||||
import {
|
||||
syncQueryEditor,
|
||||
setEditorTabLastUpdate,
|
||||
setLastUpdatedActiveTab,
|
||||
} from 'src/SqlLab/actions/sqlLab';
|
||||
import useEffectEvent from 'src/hooks/useEffectEvent';
|
||||
|
||||
@@ -71,7 +75,15 @@ const EditorAutoSync: FC = () => {
|
||||
);
|
||||
const dispatch = useDispatch();
|
||||
const lastSavedTimestampRef = useRef<number>(editorTabLastUpdatedAt);
|
||||
|
||||
const currentQueryEditorId = useSelector<SqlLabRootState, string>(
|
||||
({ sqlLab }) => sqlLab.tabHistory.slice(-1)[0] || '',
|
||||
);
|
||||
const lastUpdatedActiveTab = useSelector<SqlLabRootState, string>(
|
||||
({ sqlLab }) => sqlLab.lastUpdatedActiveTab,
|
||||
);
|
||||
const [updateSqlEditor, { error }] = useUpdateSqlEditorTabMutation();
|
||||
const [updateCurrentSqlEditor] = useUpdateCurrentSqlEditorTabMutation();
|
||||
|
||||
const debouncedUnsavedQueryEditor = useDebounceValue(
|
||||
unsavedQueryEditor,
|
||||
@@ -94,21 +106,36 @@ const EditorAutoSync: FC = () => {
|
||||
).find(({ inLocalStorage }) => Boolean(inLocalStorage)),
|
||||
);
|
||||
|
||||
const syncCurrentQueryEditor = useEffectEvent(() => {
|
||||
if (
|
||||
currentQueryEditorId &&
|
||||
currentQueryEditorId !== lastUpdatedActiveTab &&
|
||||
!queryEditors.find(({ id }) => id === currentQueryEditorId)
|
||||
?.inLocalStorage
|
||||
) {
|
||||
updateCurrentSqlEditor(currentQueryEditorId).then(() => {
|
||||
dispatch(setLastUpdatedActiveTab(currentQueryEditorId));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
let timer: NodeJS.Timeout;
|
||||
let saveTimer: NodeJS.Timeout;
|
||||
function saveUnsavedQueryEditor() {
|
||||
const firstUnsavedQueryEditor = getUnsavedNewQueryEditor();
|
||||
|
||||
if (firstUnsavedQueryEditor) {
|
||||
dispatch(syncQueryEditor(firstUnsavedQueryEditor));
|
||||
}
|
||||
timer = setTimeout(saveUnsavedQueryEditor, INTERVAL);
|
||||
saveTimer = setTimeout(saveUnsavedQueryEditor, INTERVAL);
|
||||
}
|
||||
timer = setTimeout(saveUnsavedQueryEditor, INTERVAL);
|
||||
const syncTimer = setInterval(syncCurrentQueryEditor, INTERVAL);
|
||||
saveTimer = setTimeout(saveUnsavedQueryEditor, INTERVAL);
|
||||
return () => {
|
||||
clearTimeout(timer);
|
||||
clearTimeout(saveTimer);
|
||||
clearInterval(syncTimer);
|
||||
};
|
||||
}, [getUnsavedNewQueryEditor, dispatch]);
|
||||
}, [getUnsavedNewQueryEditor, syncCurrentQueryEditor, dispatch]);
|
||||
|
||||
useEffect(() => {
|
||||
const unsaved = getUnsavedItems(debouncedUnsavedQueryEditor);
|
||||
|
||||
@@ -411,7 +411,8 @@ describe('SqlEditor', () => {
|
||||
await waitFor(() =>
|
||||
expect(fetchMock.calls('glob:*/tabstateview/*').length).toBe(1),
|
||||
);
|
||||
expect(fetchMock.calls(switchTabApi).length).toBe(1);
|
||||
// it will be called from EditorAutoSync
|
||||
expect(fetchMock.calls(switchTabApi).length).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -79,7 +79,7 @@ import {
|
||||
setActiveSouthPaneTab,
|
||||
updateSavedQuery,
|
||||
formatQuery,
|
||||
switchQueryEditor,
|
||||
fetchQueryEditor,
|
||||
} from 'src/SqlLab/actions/sqlLab';
|
||||
import {
|
||||
STATE_TYPE_MAP,
|
||||
@@ -506,7 +506,7 @@ const SqlEditor: FC<Props> = ({
|
||||
|
||||
const loadQueryEditor = useEffectEvent(() => {
|
||||
if (shouldLoadQueryEditor) {
|
||||
dispatch(switchQueryEditor(queryEditor, displayLimit));
|
||||
dispatch(fetchQueryEditor(queryEditor, displayLimit));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -181,10 +181,7 @@ class TabbedSqlEditors extends PureComponent<TabbedSqlEditorsProps> {
|
||||
if (!queryEditor) {
|
||||
return;
|
||||
}
|
||||
this.props.actions.switchQueryEditor(
|
||||
queryEditor,
|
||||
this.props.displayLimit,
|
||||
);
|
||||
this.props.actions.setActiveQueryEditor(queryEditor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user