diff --git a/superset-frontend/src/components/AsyncAceEditor/Tooltip.test.tsx b/superset-frontend/src/components/AsyncAceEditor/Tooltip.test.tsx
new file mode 100644
index 000000000..8365bd6b5
--- /dev/null
+++ b/superset-frontend/src/components/AsyncAceEditor/Tooltip.test.tsx
@@ -0,0 +1,47 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { render, screen } from 'spec/helpers/testing-library';
+import Tooltip, { getTooltipHTML } from './Tooltip';
+
+test('should render a tooltip', () => {
+ const expected = {
+ title: 'tooltip title',
+ icon:
icon
,
+ body: body
,
+ meta: 'meta',
+ footer: footer
,
+ };
+ render();
+ expect(screen.getByText(expected.title)).toBeInTheDocument();
+ expect(screen.getByText(expected.meta)).toBeInTheDocument();
+ expect(screen.getByText('icon')).toBeInTheDocument();
+ expect(screen.getByText('body')).toBeInTheDocument();
+});
+
+test('returns the tooltip HTML', () => {
+ const html = getTooltipHTML({
+ title: 'tooltip title',
+ icon: icon
,
+ body: body
,
+ meta: 'meta',
+ footer: footer
,
+ });
+ expect(html).toContain('tooltip title');
+});
diff --git a/superset-frontend/src/components/AsyncAceEditor/Tooltip.tsx b/superset-frontend/src/components/AsyncAceEditor/Tooltip.tsx
new file mode 100644
index 000000000..bc504587a
--- /dev/null
+++ b/superset-frontend/src/components/AsyncAceEditor/Tooltip.tsx
@@ -0,0 +1,57 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { renderToStaticMarkup } from 'react-dom/server';
+import { Tag } from 'src/components';
+
+type Props = {
+ title: string;
+ icon?: React.ReactNode;
+ body?: React.ReactNode;
+ meta?: string;
+ footer?: React.ReactNode;
+};
+
+export const Tooltip: React.FC = ({
+ title,
+ icon,
+ body,
+ meta,
+ footer,
+}) => (
+
+
+
+ {icon}
+ {title}
+
+ {meta && (
+
+ {meta}
+
+ )}
+
+ {body &&
{body ?? title}
}
+ {footer &&
{footer}
}
+
+);
+
+export const getTooltipHTML = (props: Props) =>
+ `${renderToStaticMarkup()}`;
+
+export default Tooltip;
diff --git a/superset-frontend/src/components/AsyncAceEditor/index.tsx b/superset-frontend/src/components/AsyncAceEditor/index.tsx
index 32e5a687f..f599438c7 100644
--- a/superset-frontend/src/components/AsyncAceEditor/index.tsx
+++ b/superset-frontend/src/components/AsyncAceEditor/index.tsx
@@ -32,6 +32,10 @@ import AsyncEsmComponent, {
} from 'src/components/AsyncEsmComponent';
import useEffectEvent from 'src/hooks/useEffectEvent';
import cssWorkerUrl from 'ace-builds/src-noconflict/worker-css';
+import { useTheme, css } from '@superset-ui/core';
+import { Global } from '@emotion/react';
+
+export { getTooltipHTML } from './Tooltip';
config.setModuleUrl('ace/mode/css_worker', cssWorkerUrl);
@@ -135,6 +139,7 @@ export default function AsyncAceEditor(
},
ref,
) {
+ const supersetTheme = useTheme();
const langTools = acequire('ace/ext/language_tools');
const setCompleters = useEffectEvent(
(keywords: AceCompleterKeyword[]) => {
@@ -167,15 +172,66 @@ export default function AsyncAceEditor(
}, [keywords, setCompleters]);
return (
-
+ <>
+ .ant-tag {
+ margin-right: 0px;
+ }
+ }
+ }
+ `}
+ />
+
+ >
);
},
);
diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx
index ed274d089..fd50f038a 100644
--- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx
+++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx
@@ -41,8 +41,10 @@ import Button from 'src/components/Button';
import { Select } from 'src/components';
import { Form, FormItem } from 'src/components/Form';
+import sqlKeywords from 'src/SqlLab/utils/sqlKeywords';
import { SQLEditor } from 'src/components/AsyncAceEditor';
import { EmptyStateSmall } from 'src/components/EmptyState';
+import { getColumnKeywords } from 'src/explore/controlUtils/getColumnKeywords';
import { StyledColumnOption } from 'src/explore/components/optionRenderers';
import {
POPOVER_INITIAL_HEIGHT,
@@ -287,6 +289,10 @@ const ColumnSelectPopover = ({
const savedExpressionsLabel = t('Saved expressions');
const simpleColumnsLabel = t('Column');
+ const keywords = useMemo(
+ () => sqlKeywords.concat(getColumnKeywords(columns)),
+ [columns],
+ );
return (