blob: 49e0d31433a9c48211f3d946764e7587f792e882 [file] [log] [blame]
/**
* 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 { ReactNode } from 'react';
import { styled, t } from '@superset-ui/core';
import { Modal, Loading, Flex } from '@superset-ui/core/components';
import { ModalTitleWithIcon } from 'src/components/ModalTitleWithIcon';
interface StandardModalProps {
width?: number;
title: string;
icon?: ReactNode;
show: boolean;
onHide: () => void;
onSave: () => void;
saveDisabled?: boolean;
saveLoading?: boolean;
saveText?: string;
cancelText?: string;
errorTooltip?: ReactNode;
children: ReactNode;
isEditMode?: boolean;
centered?: boolean;
destroyOnClose?: boolean;
maskClosable?: boolean;
wrapProps?: object;
contentLoading?: boolean;
}
// Standard modal widths
export const MODAL_STANDARD_WIDTH = 500;
export const MODAL_MEDIUM_WIDTH = 600;
export const MODAL_LARGE_WIDTH = 900;
const StyledModal = styled(Modal)`
.ant-modal-body {
max-height: 60vh;
height: auto;
overflow-y: auto;
padding: 0;
}
.ant-modal-header {
padding: ${({ theme }) => theme.sizeUnit * 3}px
${({ theme }) => theme.sizeUnit * 4}px
${({ theme }) => theme.sizeUnit * 3}px;
margin-bottom: 0;
border-bottom: 1px solid ${({ theme }) => theme.colorBorder};
}
.ant-modal-footer {
height: ${({ theme }) => theme.sizeUnit * 16.25}px;
}
.control-label {
margin-top: ${({ theme }) => theme.sizeUnit}px;
}
/* Remove top margin from collapse component */
.ant-collapse {
border: none;
> .ant-collapse-item:first-child {
border-top: none;
}
/* Remove margin from collapse headers */
.ant-collapse-header {
padding-bottom: 0 !important;
/* Remove margin from the CollapseLabelInModal component */
> div {
margin-bottom: 0;
}
}
}
/* Ensure collapse sections have proper padding */
.ant-collapse-content-box {
padding: ${({ theme }) => theme.sizeUnit * 4}px;
}
`;
export function StandardModal({
width = MODAL_STANDARD_WIDTH,
title,
icon,
show,
onHide,
onSave,
saveDisabled = false,
saveLoading = false,
saveText,
cancelText,
errorTooltip,
children,
isEditMode = false,
centered = true,
destroyOnClose = true,
maskClosable = false,
wrapProps,
contentLoading = false,
}: StandardModalProps) {
const primaryButtonName = saveText || (isEditMode ? t('Save') : t('Add'));
return (
<StyledModal
disablePrimaryButton={saveDisabled || saveLoading || contentLoading}
primaryButtonLoading={saveLoading}
primaryTooltipMessage={errorTooltip}
onHandledPrimaryAction={onSave}
onHide={onHide}
primaryButtonName={primaryButtonName}
show={show}
width={`${width}px`}
wrapProps={wrapProps}
title={
icon ? (
<ModalTitleWithIcon
isEditMode={isEditMode}
title={title}
data-test="standard-modal-title"
/>
) : (
title
)
}
>
{contentLoading ? (
<Flex justify="center" align="center" style={{ minHeight: 200 }}>
<Loading />
</Flex>
) : (
children
)}
</StyledModal>
);
}