fix(sqllab): Show warning message when deprecated db is selected (#29607)

This commit is contained in:
JUST.in DO IT 2024-07-17 10:37:58 -07:00 committed by GitHub
parent 9da5be3d79
commit db3fa8df77
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 116 additions and 83 deletions

View File

@ -160,13 +160,23 @@ describe('SqlEditor', () => {
}); });
it('does not render SqlEditor if no db selected', async () => { it('does not render SqlEditor if no db selected', async () => {
const queryEditor = initialState.sqlLab.queryEditors[1]; const queryEditor = initialState.sqlLab.queryEditors[2];
const { findByText } = setup({ ...mockedProps, queryEditor }, store); const { findByText } = setup({ ...mockedProps, queryEditor }, store);
expect( expect(
await findByText('Select a database to write a query'), await findByText('Select a database to write a query'),
).toBeInTheDocument(); ).toBeInTheDocument();
}); });
it('renders db unavailable message', async () => {
const queryEditor = initialState.sqlLab.queryEditors[1];
const { findByText } = setup({ ...mockedProps, queryEditor }, store);
expect(
await findByText(
'The database that was used to generate this query could not be found',
),
).toBeInTheDocument();
});
it('render a SqlEditorLeftBar', async () => { it('render a SqlEditorLeftBar', async () => {
const { getByTestId } = setup(mockedProps, store); const { getByTestId } = setup(mockedProps, store);
await waitFor(() => await waitFor(() =>

View File

@ -99,6 +99,7 @@ import {
setItem, setItem,
} from 'src/utils/localStorageHelpers'; } from 'src/utils/localStorageHelpers';
import { EmptyStateBig } from 'src/components/EmptyState'; import { EmptyStateBig } from 'src/components/EmptyState';
import Alert from 'src/components/Alert';
import getBootstrapData from 'src/utils/getBootstrapData'; import getBootstrapData from 'src/utils/getBootstrapData';
import useLogAction from 'src/logger/useLogAction'; import useLogAction from 'src/logger/useLogAction';
import { import {
@ -258,31 +259,38 @@ const SqlEditor: FC<Props> = ({
const theme = useTheme(); const theme = useTheme();
const dispatch = useDispatch(); const dispatch = useDispatch();
const { database, latestQuery, hideLeftBar, currentQueryEditorId } = const {
useSelector< database,
SqlLabRootState, latestQuery,
{ hideLeftBar,
database?: DatabaseObject; currentQueryEditorId,
latestQuery?: QueryResponse; hasSqlStatement,
hideLeftBar?: boolean; } = useSelector<
currentQueryEditorId: QueryEditor['id']; SqlLabRootState,
} {
>(({ sqlLab: { unsavedQueryEditor, databases, queries, tabHistory } }) => { database?: DatabaseObject;
let { dbId, latestQueryId, hideLeftBar } = queryEditor; latestQuery?: QueryResponse;
if (unsavedQueryEditor?.id === queryEditor.id) { hideLeftBar?: boolean;
dbId = unsavedQueryEditor.dbId || dbId; currentQueryEditorId: QueryEditor['id'];
latestQueryId = unsavedQueryEditor.latestQueryId || latestQueryId; hasSqlStatement: boolean;
hideLeftBar = isBoolean(unsavedQueryEditor.hideLeftBar) }
? unsavedQueryEditor.hideLeftBar >(({ sqlLab: { unsavedQueryEditor, databases, queries, tabHistory } }) => {
: hideLeftBar; let { dbId, latestQueryId, hideLeftBar } = queryEditor;
} if (unsavedQueryEditor?.id === queryEditor.id) {
return { dbId = unsavedQueryEditor.dbId || dbId;
database: databases[dbId || ''], latestQueryId = unsavedQueryEditor.latestQueryId || latestQueryId;
latestQuery: queries[latestQueryId || ''], hideLeftBar = isBoolean(unsavedQueryEditor.hideLeftBar)
hideLeftBar, ? unsavedQueryEditor.hideLeftBar
currentQueryEditorId: tabHistory.slice(-1)[0], : hideLeftBar;
}; }
}, shallowEqual); return {
hasSqlStatement: Boolean(queryEditor.sql?.trim().length > 0),
database: databases[dbId || ''],
latestQuery: queries[latestQueryId || ''],
hideLeftBar,
currentQueryEditorId: tabHistory.slice(-1)[0],
};
}, shallowEqual);
const logAction = useLogAction({ queryEditorId: queryEditor.id }); const logAction = useLogAction({ queryEditorId: queryEditor.id });
const isActive = currentQueryEditorId === queryEditor.id; const isActive = currentQueryEditorId === queryEditor.id;
@ -728,7 +736,7 @@ const SqlEditor: FC<Props> = ({
dispatch(addSavedQueryToTabState(queryEditor, savedQuery)); dispatch(addSavedQueryToTabState(queryEditor, savedQuery));
}; };
const renderEditorBottomBar = () => { const renderEditorBottomBar = (hideActions: boolean) => {
const { allow_ctas: allowCTAS, allow_cvas: allowCVAS } = database || {}; const { allow_ctas: allowCTAS, allow_cvas: allowCVAS } = database || {};
const showMenu = allowCTAS || allowCVAS; const showMenu = allowCTAS || allowCVAS;
@ -767,63 +775,78 @@ const SqlEditor: FC<Props> = ({
return ( return (
<StyledToolbar className="sql-toolbar" id="js-sql-toolbar"> <StyledToolbar className="sql-toolbar" id="js-sql-toolbar">
<div className="leftItems"> {hideActions ? (
<span> <Alert
<RunQueryActionButton type="warning"
allowAsync={database?.allow_run_async === true} message={t(
queryEditorId={queryEditor.id} 'The database that was used to generate this query could not be found',
queryState={latestQuery?.state} )}
runQuery={runQuery} description={t(
stopQuery={stopQuery} 'Choose one of the available databases on the left panel.',
overlayCreateAsMenu={showMenu ? runMenuBtn : null} )}
/> closable={false}
</span> />
{isFeatureEnabled(FeatureFlag.EstimateQueryCost) && ) : (
database?.allows_cost_estimate && ( <>
<div className="leftItems">
<span> <span>
<EstimateQueryCostButton <RunQueryActionButton
getEstimate={getQueryCostEstimate} allowAsync={database?.allow_run_async === true}
queryEditorId={queryEditor.id} queryEditorId={queryEditor.id}
tooltip={t('Estimate the cost before running a query')} queryState={latestQuery?.state}
runQuery={runQuery}
stopQuery={stopQuery}
overlayCreateAsMenu={showMenu ? runMenuBtn : null}
/> />
</span> </span>
)} {isFeatureEnabled(FeatureFlag.EstimateQueryCost) &&
<span> database?.allows_cost_estimate && (
<QueryLimitSelect <span>
queryEditorId={queryEditor.id} <EstimateQueryCostButton
maxRow={maxRow} getEstimate={getQueryCostEstimate}
defaultQueryLimit={defaultQueryLimit} queryEditorId={queryEditor.id}
/> tooltip={t('Estimate the cost before running a query')}
</span> />
{latestQuery && ( </span>
<Timer )}
startTime={latestQuery.startDttm} <span>
endTime={latestQuery.endDttm} <QueryLimitSelect
status={STATE_TYPE_MAP[latestQuery.state]} queryEditorId={queryEditor.id}
isRunning={latestQuery.state === 'running'} maxRow={maxRow}
/> defaultQueryLimit={defaultQueryLimit}
)} />
</div> </span>
<div className="rightItems"> {latestQuery && (
<span> <Timer
<SaveQuery startTime={latestQuery.startDttm}
queryEditorId={queryEditor.id} endTime={latestQuery.endDttm}
columns={latestQuery?.results?.columns || []} status={STATE_TYPE_MAP[latestQuery.state]}
onSave={onSaveQuery} isRunning={latestQuery.state === 'running'}
onUpdate={(query, remoteId) => />
dispatch(updateSavedQuery(query, remoteId)) )}
} </div>
saveQueryWarning={saveQueryWarning} <div className="rightItems">
database={database} <span>
/> <SaveQuery
</span> queryEditorId={queryEditor.id}
<span> columns={latestQuery?.results?.columns || []}
<ShareSqlLabQuery queryEditorId={queryEditor.id} /> onSave={onSaveQuery}
</span> onUpdate={(query, remoteId) =>
<AntdDropdown overlay={renderDropdown()} trigger={['click']}> dispatch(updateSavedQuery(query, remoteId))
<Icons.MoreHoriz iconColor={theme.colors.grayscale.base} /> }
</AntdDropdown> saveQueryWarning={saveQueryWarning}
</div> database={database}
/>
</span>
<span>
<ShareSqlLabQuery queryEditorId={queryEditor.id} />
</span>
<AntdDropdown overlay={renderDropdown()} trigger={['click']}>
<Icons.MoreHoriz iconColor={theme.colors.grayscale.base} />
</AntdDropdown>
</div>
</>
)}
</StyledToolbar> </StyledToolbar>
); );
}; };
@ -866,7 +889,7 @@ const SqlEditor: FC<Props> = ({
height={`${aceEditorHeight}px`} height={`${aceEditorHeight}px`}
hotkeys={hotkeys} hotkeys={hotkeys}
/> />
{renderEditorBottomBar()} {renderEditorBottomBar(showEmptyState)}
</div> </div>
<SouthPane <SouthPane
queryEditorId={queryEditor.id} queryEditorId={queryEditor.id}
@ -923,7 +946,7 @@ const SqlEditor: FC<Props> = ({
> >
<Skeleton active /> <Skeleton active />
</div> </div>
) : showEmptyState ? ( ) : showEmptyState && !hasSqlStatement ? (
<EmptyStateBig <EmptyStateBig
image="vector.svg" image="vector.svg"
title={t('Select a database to write a query')} title={t('Select a database to write a query')}

View File

@ -210,7 +210,7 @@ export const extraQueryEditor1 = {
export const extraQueryEditor2 = { export const extraQueryEditor2 = {
...defaultQueryEditor, ...defaultQueryEditor,
id: 'owkdi998', id: 'owkdi998',
sql: 'SELECT *\nFROM\nWHERE\nGROUP BY', sql: '',
name: 'Untitled Query 3', name: 'Untitled Query 3',
}; };