This is an automated email from the ASF dual-hosted git repository.

elizabeth pushed a commit to branch elizabeth/fix-resize-bug
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 5845c7c112c8ade8c39573cdf49ab3e04df7a655
Author: Beto Dealmeida <[email protected]>
AuthorDate: Tue Jul 29 15:43:47 2025 -0400

    feat: allow creating dataset without exploring (#34380)
---
 .../datasets/AddDataset/Footer/Footer.test.tsx     | 146 ++++++++++++++++++++-
 .../features/datasets/AddDataset/Footer/index.tsx  |  52 ++++++--
 2 files changed, 182 insertions(+), 16 deletions(-)

diff --git 
a/superset-frontend/src/features/datasets/AddDataset/Footer/Footer.test.tsx 
b/superset-frontend/src/features/datasets/AddDataset/Footer/Footer.test.tsx
index 65507a170b..fa81ce20e0 100644
--- a/superset-frontend/src/features/datasets/AddDataset/Footer/Footer.test.tsx
+++ b/superset-frontend/src/features/datasets/AddDataset/Footer/Footer.test.tsx
@@ -16,7 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import { render, screen } from 'spec/helpers/testing-library';
+import {
+  render,
+  screen,
+  waitFor,
+  userEvent,
+} from 'spec/helpers/testing-library';
 import Footer from 'src/features/datasets/AddDataset/Footer';
 
 const mockHistoryPush = jest.fn();
@@ -27,6 +32,14 @@ jest.mock('react-router-dom', () => ({
   }),
 }));
 
+// Mock the API call
+const mockCreateResource = jest.fn();
+jest.mock('src/views/CRUD/hooks', () => ({
+  useSingleViewResource: () => ({
+    createResource: mockCreateResource,
+  }),
+}));
+
 const mockedProps = {
   url: 'realwebsite.com',
 };
@@ -34,7 +47,7 @@ const mockedProps = {
 const mockPropsWithDataset = {
   url: 'realwebsite.com',
   datasetObject: {
-    database: {
+    db: {
       id: '1',
       database_name: 'examples',
     },
@@ -47,6 +60,10 @@ const mockPropsWithDataset = {
 };
 
 describe('Footer', () => {
+  beforeEach(() => {
+    jest.clearAllMocks();
+  });
+
   test('renders a Footer with a cancel button and a disabled create button', 
() => {
     render(<Footer {...mockedProps} />, { useRedux: true });
 
@@ -55,21 +72,28 @@ describe('Footer', () => {
     });
 
     const createButton = screen.getByRole('button', {
-      name: /Create/i,
+      name: /Create dataset and create chart/i,
     });
 
     expect(saveButton).toBeVisible();
     expect(createButton).toBeDisabled();
   });
 
-  test('renders a Create Dataset button when a table is selected', () => {
+  test('renders a Create Dataset dropdown button when a table is selected', () 
=> {
     render(<Footer {...mockPropsWithDataset} />, { useRedux: true });
 
     const createButton = screen.getByRole('button', {
-      name: /Create/i,
+      name: /Create dataset and create chart/i,
     });
 
     expect(createButton).toBeEnabled();
+
+    // Check that it's a dropdown button with the correct text
+    expect(createButton).toHaveTextContent('Create dataset and create chart');
+
+    // Check for the dropdown arrow
+    const dropdownArrow = screen.getByRole('img', { hidden: true });
+    expect(dropdownArrow).toBeInTheDocument();
   });
 
   test('create button becomes disabled when table already has a dataset', () 
=> {
@@ -78,9 +102,119 @@ describe('Footer', () => {
     });
 
     const createButton = screen.getByRole('button', {
-      name: /Create/i,
+      name: /Create dataset and create chart/i,
     });
 
     expect(createButton).toBeDisabled();
   });
+
+  test('shows dropdown menu when dropdown arrow is clicked', async () => {
+    render(<Footer {...mockPropsWithDataset} />, { useRedux: true });
+
+    // Find and click the dropdown trigger (the arrow part)
+    const dropdownTrigger = screen.getByRole('button', { name: 'down' });
+    userEvent.click(dropdownTrigger);
+
+    // Check that the dropdown menu option is visible
+    await waitFor(() => {
+      expect(screen.getByText('Create dataset only')).toBeVisible();
+    });
+  });
+
+  test('navigates to chart creation when main button is clicked', async () => {
+    mockCreateResource.mockResolvedValue(123); // Mock successful dataset 
creation
+
+    render(<Footer {...mockPropsWithDataset} />, { useRedux: true });
+
+    const createButton = screen.getByRole('button', {
+      name: /Create dataset and create chart/i,
+    });
+
+    userEvent.click(createButton);
+
+    await waitFor(() => {
+      expect(mockCreateResource).toHaveBeenCalledWith({
+        database: '1',
+        catalog: undefined,
+        schema: 'public',
+        table_name: 'real_info',
+      });
+      expect(mockHistoryPush).toHaveBeenCalledWith(
+        '/chart/add/?dataset=real_info',
+      );
+    });
+  });
+
+  test('navigates to dataset list when "Create dataset only" menu option is 
clicked', async () => {
+    mockCreateResource.mockResolvedValue(123);
+
+    render(<Footer {...mockPropsWithDataset} />, { useRedux: true });
+
+    // Open dropdown menu
+    const dropdownTrigger = screen.getByRole('button', { name: 'down' });
+    userEvent.click(dropdownTrigger);
+
+    // Click the "Create dataset only" option
+    await waitFor(() => {
+      const datasetOnlyOption = screen.getByText('Create dataset only');
+      userEvent.click(datasetOnlyOption);
+    });
+
+    await waitFor(() => {
+      expect(mockCreateResource).toHaveBeenCalledWith({
+        database: '1',
+        catalog: undefined,
+        schema: 'public',
+        table_name: 'real_info',
+      });
+      expect(mockHistoryPush).toHaveBeenCalledWith('/tablemodelview/list/');
+    });
+  });
+
+  test('handles dataset creation failure gracefully', async () => {
+    mockCreateResource.mockResolvedValue(null); // Mock failed dataset creation
+
+    render(<Footer {...mockPropsWithDataset} />, { useRedux: true });
+
+    const createButton = screen.getByRole('button', {
+      name: /Create dataset and create chart/i,
+    });
+
+    userEvent.click(createButton);
+
+    await waitFor(() => {
+      expect(mockCreateResource).toHaveBeenCalled();
+      // Should not navigate if creation failed
+      expect(mockHistoryPush).not.toHaveBeenCalled();
+    });
+  });
+
+  test('passes correct data to createResource with catalog', async () => {
+    const mockPropsWithCatalog = {
+      ...mockPropsWithDataset,
+      datasetObject: {
+        ...mockPropsWithDataset.datasetObject,
+        catalog: 'test_catalog',
+      },
+    };
+
+    mockCreateResource.mockResolvedValue(456);
+
+    render(<Footer {...mockPropsWithCatalog} />, { useRedux: true });
+
+    const createButton = screen.getByRole('button', {
+      name: /Create dataset and create chart/i,
+    });
+
+    userEvent.click(createButton);
+
+    await waitFor(() => {
+      expect(mockCreateResource).toHaveBeenCalledWith({
+        database: '1',
+        catalog: 'test_catalog',
+        schema: 'public',
+        table_name: 'real_info',
+      });
+    });
+  });
 });
diff --git 
a/superset-frontend/src/features/datasets/AddDataset/Footer/index.tsx 
b/superset-frontend/src/features/datasets/AddDataset/Footer/index.tsx
index 880e948f57..1a43ff2c52 100644
--- a/superset-frontend/src/features/datasets/AddDataset/Footer/index.tsx
+++ b/superset-frontend/src/features/datasets/AddDataset/Footer/index.tsx
@@ -17,8 +17,14 @@
  * under the License.
  */
 import { useHistory } from 'react-router-dom';
-import { Button } from '@superset-ui/core/components';
-import { t } from '@superset-ui/core';
+import {
+  Button,
+  DropdownButton,
+  Menu,
+  Flex,
+} from '@superset-ui/core/components';
+import { t, useTheme } from '@superset-ui/core';
+import { Icons } from '@superset-ui/core/components/Icons';
 import { useSingleViewResource } from 'src/views/CRUD/hooks';
 import { logEvent } from 'src/logger/actions';
 import withToasts from 'src/components/MessageToasts/withToasts';
@@ -55,6 +61,7 @@ function Footer({
   datasets,
 }: FooterProps) {
   const history = useHistory();
+  const theme = useTheme();
   const { createResource } = useSingleViewResource<Partial<DatasetObject>>(
     'dataset',
     t('dataset'),
@@ -85,7 +92,7 @@ function Footer({
 
   const tooltipText = t('Select a database table.');
 
-  const onSave = () => {
+  const onSave = (createChart: boolean = true) => {
     if (datasetObject) {
       const data = {
         database: datasetObject.db?.id,
@@ -100,32 +107,57 @@ function Footer({
         if (typeof response === 'number') {
           logEvent(LOG_ACTIONS_DATASET_CREATION_SUCCESS, datasetObject);
           // When a dataset is created the response we get is its ID number
-          history.push(`/chart/add/?dataset=${datasetObject.table_name}`);
+          if (createChart) {
+            history.push(`/chart/add/?dataset=${datasetObject.table_name}`);
+          } else {
+            history.push('/tablemodelview/list/');
+          }
         }
       });
     }
   };
 
+  const onSaveOnly = () => {
+    onSave(false);
+  };
+
   const CREATE_DATASET_TEXT = t('Create dataset and create chart');
+  const CREATE_DATASET_ONLY_TEXT = t('Create dataset only');
   const disabledCheck =
     !datasetObject?.table_name ||
     !hasColumns ||
     datasets?.includes(datasetObject?.table_name);
 
+  const dropdownMenu = (
+    <Menu>
+      <Menu.Item key="create-only" onClick={onSaveOnly}>
+        {CREATE_DATASET_ONLY_TEXT}
+      </Menu.Item>
+    </Menu>
+  );
+
   return (
-    <>
+    <Flex align="center" justify="flex-end" gap="8px">
       <Button buttonStyle="secondary" onClick={cancelButtonOnClick}>
         {t('Cancel')}
       </Button>
-      <Button
-        buttonStyle="primary"
+      <DropdownButton
+        type="primary"
         disabled={disabledCheck}
         tooltip={!datasetObject?.table_name ? tooltipText : undefined}
-        onClick={onSave}
+        onClick={() => onSave(true)}
+        popupRender={() => dropdownMenu}
+        icon={
+          <Icons.DownOutlined
+            iconSize="xs"
+            iconColor={theme.colors.grayscale.light5}
+          />
+        }
+        trigger={['click']}
       >
         {CREATE_DATASET_TEXT}
-      </Button>
-    </>
+      </DropdownButton>
+    </Flex>
   );
 }
 

Reply via email to