fix: Broken splitter in sql lab and some minor visual fixes (#35416)

This commit is contained in:
Kamil Gabryjelski
2025-10-01 13:11:50 +02:00
committed by GitHub
parent bf88d9bb1c
commit 88e5581d04
8 changed files with 271 additions and 12 deletions

View File

@@ -56,7 +56,7 @@
"@visx/xychart": "^3.5.1",
"ag-grid-community": "34.2.0",
"ag-grid-react": "34.2.0",
"antd": "^5.24.6",
"antd": "^5.24.9",
"chrono-node": "^2.7.8",
"classnames": "^2.2.5",
"content-disposition": "^0.5.4",
@@ -60754,7 +60754,7 @@
"typescript": "^5.0.0"
},
"peerDependencies": {
"antd": "^5.24.6",
"antd": "^5.24.9",
"react": "^17.0.2"
}
},
@@ -63543,7 +63543,7 @@
"@types/react-loadable": "*",
"@types/react-window": "^1.8.8",
"@types/tinycolor2": "*",
"antd": "^5.24.6",
"antd": "^5.24.9",
"nanoid": "^5.0.9",
"react": "^17.0.2",
"react-dom": "^17.0.2",

View File

@@ -129,7 +129,7 @@
"@visx/xychart": "^3.5.1",
"ag-grid-community": "34.2.0",
"ag-grid-react": "34.2.0",
"antd": "^5.24.6",
"antd": "^5.24.9",
"chrono-node": "^2.7.8",
"classnames": "^2.2.5",
"content-disposition": "^0.5.4",

View File

@@ -22,7 +22,7 @@
"typescript": "^5.0.0"
},
"peerDependencies": {
"antd": "^5.24.6",
"antd": "^5.24.9",
"react": "^17.0.2"
},
"scripts": {

View File

@@ -91,7 +91,7 @@
"timezone-mock": "1.3.6"
},
"peerDependencies": {
"antd": "^5.24.6",
"antd": "^5.24.9",
"@emotion/cache": "^11.4.0",
"@emotion/react": "^11.4.1",
"@emotion/styled": "^11.14.1",

View File

@@ -265,7 +265,9 @@ const ChangeDatasourceModal: FunctionComponent<ChangeDatasourceModalProps> = ({
{confirmChange && (
<ConfirmModalStyled>
<div className="btn-container">
<Button onClick={handlerCancelConfirm}>{t('Cancel')}</Button>
<Button buttonStyle="secondary" onClick={handlerCancelConfirm}>
{t('Cancel')}
</Button>
<Button
className="proceed-btn"
buttonStyle="primary"

View File

@@ -100,6 +100,7 @@ export const ErrorAlert: React.FC<ErrorAlertProps> = ({
</span>
</div>
)}
{children}
</div>
);
const renderAlert = (closable: boolean) => (
@@ -129,7 +130,6 @@ export const ErrorAlert: React.FC<ErrorAlertProps> = ({
footer={null}
>
{renderAlert(false)}
{children}
</Modal>
</>
);

View File

@@ -0,0 +1,248 @@
/**
* 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 userEvent from '@testing-library/user-event';
import { ExploreAlert } from './ExploreAlert';
test('renders with title and body text', () => {
render(
<ExploreAlert title="Test Title" bodyText="Test body text" type="info" />,
);
expect(screen.getByText('Test Title')).toBeInTheDocument();
expect(screen.getByText('Test body text')).toBeInTheDocument();
});
test('renders info type alert', () => {
const { container } = render(
<ExploreAlert title="Info Alert" bodyText="Info message" type="info" />,
);
expect(container.querySelector('.ant-alert-info')).toBeInTheDocument();
});
test('renders warning type alert', () => {
const { container } = render(
<ExploreAlert
title="Warning Alert"
bodyText="Warning message"
type="warning"
/>,
);
expect(container.querySelector('.ant-alert-warning')).toBeInTheDocument();
});
test('renders error type alert', () => {
const { container } = render(
<ExploreAlert title="Error Alert" bodyText="Error message" type="error" />,
);
expect(container.querySelector('.ant-alert-error')).toBeInTheDocument();
});
test('renders primary button when text and action provided', () => {
const primaryAction = jest.fn();
render(
<ExploreAlert
title="Alert with button"
bodyText="Body text"
type="info"
primaryButtonText="Primary Action"
primaryButtonAction={primaryAction}
/>,
);
expect(screen.getByText('Primary Action')).toBeInTheDocument();
});
test('calls primary button action when clicked', async () => {
const primaryAction = jest.fn();
render(
<ExploreAlert
title="Alert with button"
bodyText="Body text"
type="info"
primaryButtonText="Click Me"
primaryButtonAction={primaryAction}
/>,
);
await userEvent.click(screen.getByText('Click Me'));
expect(primaryAction).toHaveBeenCalledTimes(1);
});
test('renders both primary and secondary buttons when provided', () => {
const primaryAction = jest.fn();
const secondaryAction = jest.fn();
render(
<ExploreAlert
title="Alert with buttons"
bodyText="Body text"
type="info"
primaryButtonText="Primary"
primaryButtonAction={primaryAction}
secondaryButtonText="Secondary"
secondaryButtonAction={secondaryAction}
/>,
);
expect(screen.getByText('Primary')).toBeInTheDocument();
expect(screen.getByText('Secondary')).toBeInTheDocument();
});
test('calls secondary button action when clicked', async () => {
const primaryAction = jest.fn();
const secondaryAction = jest.fn();
render(
<ExploreAlert
title="Alert with buttons"
bodyText="Body text"
type="info"
primaryButtonText="Primary"
primaryButtonAction={primaryAction}
secondaryButtonText="Secondary"
secondaryButtonAction={secondaryAction}
/>,
);
await userEvent.click(screen.getByText('Secondary'));
expect(secondaryAction).toHaveBeenCalledTimes(1);
expect(primaryAction).not.toHaveBeenCalled();
});
test('does not render buttons when only text is provided without action', () => {
render(
<ExploreAlert
title="Alert without action"
bodyText="Body text"
type="info"
primaryButtonText="Primary"
/>,
);
expect(screen.queryByText('Primary')).not.toBeInTheDocument();
});
test('does not render buttons when only action is provided without text', () => {
const primaryAction = jest.fn();
render(
<ExploreAlert
title="Alert without text"
bodyText="Body text"
type="info"
primaryButtonAction={primaryAction}
/>,
);
expect(screen.queryByRole('button')).not.toBeInTheDocument();
});
test('does not render secondary button when secondary action is missing', () => {
const primaryAction = jest.fn();
render(
<ExploreAlert
title="Alert"
bodyText="Body text"
type="info"
primaryButtonText="Primary"
primaryButtonAction={primaryAction}
secondaryButtonText="Secondary"
/>,
);
expect(screen.getByText('Primary')).toBeInTheDocument();
expect(screen.queryByText('Secondary')).not.toBeInTheDocument();
});
test('does not render secondary button when secondary text is missing', () => {
const primaryAction = jest.fn();
const secondaryAction = jest.fn();
render(
<ExploreAlert
title="Alert"
bodyText="Body text"
type="info"
primaryButtonText="Primary"
primaryButtonAction={primaryAction}
secondaryButtonAction={secondaryAction}
/>,
);
expect(screen.getByText('Primary')).toBeInTheDocument();
expect(
screen.queryByRole('button', { name: /secondary/i }),
).not.toBeInTheDocument();
});
test('applies custom className', () => {
const { container } = render(
<ExploreAlert
title="Alert"
bodyText="Body text"
type="info"
className="custom-class"
/>,
);
expect(container.querySelector('.custom-class')).toBeInTheDocument();
});
test('renders with ReactNode as bodyText', () => {
render(
<ExploreAlert
title="Alert"
bodyText={
<div>
<span>Line 1</span>
<span>Line 2</span>
</div>
}
type="info"
/>,
);
expect(screen.getByText('Line 1')).toBeInTheDocument();
expect(screen.getByText('Line 2')).toBeInTheDocument();
});
test('is not closable by default', () => {
const { container } = render(
<ExploreAlert title="Alert" bodyText="Body text" type="info" />,
);
expect(
container.querySelector('.ant-alert-close-icon'),
).not.toBeInTheDocument();
});
test('shows icon by default', () => {
const { container } = render(
<ExploreAlert title="Alert" bodyText="Body text" type="info" />,
);
expect(container.querySelector('.anticon')).toBeInTheDocument();
});

View File

@@ -20,6 +20,7 @@
import { forwardRef, RefObject, MouseEvent } from 'react';
import { Button } from '@superset-ui/core/components';
import { ErrorAlert } from 'src/components';
import { styled } from '@superset-ui/core';
interface ControlPanelAlertProps {
title: string;
@@ -32,6 +33,12 @@ interface ControlPanelAlertProps {
className?: string;
}
const ButtonContainer = styled.div`
display: flex;
justify-content: flex-end;
margin-top: ${({ theme }) => theme.sizeUnit * 4}px;
`;
export const ExploreAlert = forwardRef(
(
{
@@ -55,14 +62,16 @@ export const ExploreAlert = forwardRef(
showIcon
>
{primaryButtonText && primaryButtonAction && (
<div>
<ButtonContainer>
{secondaryButtonAction && secondaryButtonText && (
<Button onClick={secondaryButtonAction}>
<Button buttonStyle="secondary" onClick={secondaryButtonAction}>
{secondaryButtonText}
</Button>
)}
<Button onClick={primaryButtonAction}>{primaryButtonText}</Button>
</div>
<Button buttonStyle="secondary" onClick={primaryButtonAction}>
{primaryButtonText}
</Button>
</ButtonContainer>
)}
</ErrorAlert>
),