diff --git a/packages/grafana-data/src/themes/createComponents.ts b/packages/grafana-data/src/themes/createComponents.ts index 907b3c50fcc..172b3c7f778 100644 --- a/packages/grafana-data/src/themes/createComponents.ts +++ b/packages/grafana-data/src/themes/createComponents.ts @@ -74,7 +74,7 @@ export function createComponents(colors: ThemeColors, shadows: ThemeShadows): Th padding: 1, }, overlay: { - background: colors.mode === 'dark' ? 'rgba(0, 0, 0, 0.27)' : 'rgba(208, 209, 211, 0.24)', + background: colors.mode === 'dark' ? 'rgba(0, 0, 0, 0.45)' : 'rgba(208, 209, 211, 0.24)', }, }; } diff --git a/packages/grafana-ui/src/components/ConfirmModal/ConfirmModal.tsx b/packages/grafana-ui/src/components/ConfirmModal/ConfirmModal.tsx index aff2346b52f..0f4301ad727 100644 --- a/packages/grafana-ui/src/components/ConfirmModal/ConfirmModal.tsx +++ b/packages/grafana-ui/src/components/ConfirmModal/ConfirmModal.tsx @@ -57,37 +57,35 @@ export const ConfirmModal = ({ return ( -
-
- {body} - {description ?
{description}
: null} - {confirmationText ? ( -
- - - -
- ) : null} -
- - {onAlternative ? ( - - ) : null} - - - +
+ {body} + {description ?
{description}
: null} + {confirmationText ? ( +
+ + + +
+ ) : null}
+ + + + {onAlternative ? ( + + ) : null} + ); }; @@ -96,20 +94,14 @@ const getStyles = (theme: GrafanaThemeV2) => ({ modal: css` width: 500px; `, - modalContent: css` - text-align: center; - `, modalText: css({ - fontSize: theme.typography.h4.fontSize, + fontSize: theme.typography.h5.fontSize, color: theme.colors.text.primary, - marginBottom: `calc(${theme.spacing(2)}*2)`, - paddingTop: theme.spacing(2), }), modalDescription: css({ - fontSize: theme.typography.h6.fontSize, - paddingTop: theme.spacing(2), + fontSize: theme.typography.body.fontSize, }), modalConfirmationInput: css({ - paddingTop: theme.spacing(2), + paddingTop: theme.spacing(1), }), }); diff --git a/packages/grafana-ui/src/components/Forms/FieldSet.tsx b/packages/grafana-ui/src/components/Forms/FieldSet.tsx index 78e6180713c..bb029c46cdf 100644 --- a/packages/grafana-ui/src/components/Forms/FieldSet.tsx +++ b/packages/grafana-ui/src/components/Forms/FieldSet.tsx @@ -26,6 +26,10 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => { return { wrapper: css` margin-bottom: ${theme.spacing.formSpacingBase * 4}px; + + &:last-child { + margin-bottom: 0; + } `, }; }); diff --git a/packages/grafana-ui/src/components/IconButton/IconButton.tsx b/packages/grafana-ui/src/components/IconButton/IconButton.tsx index 6b479f2aaff..aa0d10f906f 100644 --- a/packages/grafana-ui/src/components/IconButton/IconButton.tsx +++ b/packages/grafana-ui/src/components/IconButton/IconButton.tsx @@ -54,7 +54,7 @@ IconButton.displayName = 'IconButton'; const getStyles = stylesFactory((theme: GrafanaThemeV2, size: IconSize) => { const hoverColor = theme.colors.action.hover; const pixelSize = getSvgSize(size); - const hoverSize = pixelSize / 2; + const hoverSize = Math.max(pixelSize / 3, 8); return { button: css` diff --git a/packages/grafana-ui/src/components/Modal/Modal.story.tsx b/packages/grafana-ui/src/components/Modal/Modal.story.tsx index a0fa5809617..57a7e019f15 100644 --- a/packages/grafana-ui/src/components/Modal/Modal.story.tsx +++ b/packages/grafana-ui/src/components/Modal/Modal.story.tsx @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import { oneLineTrim } from 'common-tags'; import { Story, Meta } from '@storybook/react'; import { getAvailableIcons } from '../../types'; -import { Modal, ModalTabsHeader, TabContent } from '@grafana/ui'; +import { Button, Modal, ModalTabsHeader, TabContent } from '@grafana/ui'; import { css, cx } from '@emotion/css'; import { withCenteredStory } from '../../utils/storybook/withCenteredStory'; @@ -54,6 +54,10 @@ export const Basic: Story = ({ body, title, ...args }) => { return ( {body} + + + + ); }; diff --git a/packages/grafana-ui/src/components/Modal/Modal.tsx b/packages/grafana-ui/src/components/Modal/Modal.tsx index edf4f8ecc82..c13fcf69535 100644 --- a/packages/grafana-ui/src/components/Modal/Modal.tsx +++ b/packages/grafana-ui/src/components/Modal/Modal.tsx @@ -1,4 +1,4 @@ -import React, { FC, PropsWithChildren, useCallback, useEffect } from 'react'; +import React, { PropsWithChildren, useCallback, useEffect } from 'react'; import { Portal } from '../Portal/Portal'; import { cx } from '@emotion/css'; import { useTheme2 } from '../../themes'; @@ -6,9 +6,12 @@ import { IconName } from '../../types'; import { getModalStyles } from './getModalStyles'; import { ModalHeader } from './ModalHeader'; import { IconButton } from '../IconButton/IconButton'; +import { HorizontalGroup } from '../Layout/Layout'; export interface Props { + /** @deprecated no longer used */ icon?: IconName; + /** @deprecated no longer used */ iconTooltip?: string; /** Title for the modal or custom header element */ title: string | JSX.Element; @@ -23,7 +26,7 @@ export interface Props { onClickBackdrop?: () => void; } -export function Modal(props: PropsWithChildren): ReturnType> { +export function Modal(props: PropsWithChildren) { const { title, children, @@ -62,14 +65,16 @@ export function Modal(props: PropsWithChildren): ReturnType> { return null; } + const headerClass = cx(styles.modalHeader, typeof title !== 'string' && styles.modalHeaderWithTabs); + return (
-
+
{typeof title === 'string' && } {typeof title !== 'string' && title}
- +
{children}
@@ -79,6 +84,21 @@ export function Modal(props: PropsWithChildren): ReturnType> { ); } +function ModalButtonRow({ children }: { children: React.ReactNode }) { + const theme = useTheme2(); + const styles = getModalStyles(theme); + + return ( +
+ + {children} + +
+ ); +} + +Modal.ButtonRow = ModalButtonRow; + interface DefaultModalHeaderProps { title: string; icon?: IconName; diff --git a/packages/grafana-ui/src/components/Modal/ModalHeader.tsx b/packages/grafana-ui/src/components/Modal/ModalHeader.tsx index 2bce1bc3fd5..4873b394c73 100644 --- a/packages/grafana-ui/src/components/Modal/ModalHeader.tsx +++ b/packages/grafana-ui/src/components/Modal/ModalHeader.tsx @@ -2,29 +2,22 @@ import React from 'react'; import { getModalStyles } from './getModalStyles'; import { IconName } from '../../types'; import { useStyles2 } from '../../themes'; -import { Icon } from '../Icon/Icon'; -import { Tooltip } from '..'; interface Props { title: string; + /** @deprecated */ icon?: IconName; + /** @deprecated */ iconTooltip?: string; } +/** @internal */ export const ModalHeader: React.FC = ({ icon, iconTooltip, title, children }) => { const styles = useStyles2(getModalStyles); return ( <> -

- {icon && !iconTooltip && } - {icon && iconTooltip && ( - - - - )} - {title} -

+

{title}

{children} ); diff --git a/packages/grafana-ui/src/components/Modal/getModalStyles.ts b/packages/grafana-ui/src/components/Modal/getModalStyles.ts index eb7b674eced..a33f11787ae 100644 --- a/packages/grafana-ui/src/components/Modal/getModalStyles.ts +++ b/packages/grafana-ui/src/components/Modal/getModalStyles.ts @@ -3,7 +3,7 @@ import { GrafanaThemeV2 } from '@grafana/data'; import { stylesFactory } from '../../themes'; export const getModalStyles = stylesFactory((theme: GrafanaThemeV2) => { - const borderRadius = theme.shape.borderRadius(2); + const borderRadius = theme.shape.borderRadius(1); return { modal: css` @@ -12,6 +12,7 @@ export const getModalStyles = stylesFactory((theme: GrafanaThemeV2) => { background: ${theme.colors.background.primary}; box-shadow: ${theme.shadows.z3}; border-radius: ${borderRadius}; + border: 1px solid ${theme.colors.border.weak}; background-clip: padding-box; outline: none; width: 750px; @@ -34,17 +35,21 @@ export const getModalStyles = stylesFactory((theme: GrafanaThemeV2) => { `, modalHeader: css` label: modalHeader; - background: ${theme.colors.background.secondary}; - border-radius: ${borderRadius} ${borderRadius} 0 0; display: flex; - height: 42px; + align-items: center; + min-height: 42px; + margin: ${theme.spacing(1, 2, 0, 2)}; + `, + modalHeaderWithTabs: css` + border-bottom: 1px solid ${theme.colors.border.weak}; `, modalHeaderTitle: css` font-size: ${theme.typography.size.lg}; - margin: 0 ${theme.spacing(2)}; + margin: ${theme.spacing(0, 4, 0, 1)}; display: flex; align-items: center; - line-height: 42px; + position: relative; + top: 2px; `, modalHeaderIcon: css` margin-right: ${theme.spacing(2)}; @@ -57,15 +62,18 @@ export const getModalStyles = stylesFactory((theme: GrafanaThemeV2) => { height: 100%; display: flex; align-items: center; + color: ${theme.colors.text.secondary}; flex-grow: 1; justify-content: flex-end; - padding-right: ${theme.spacing(1)}; `, modalContent: css` - padding: ${theme.spacing(2)}; + padding: ${theme.spacing(3)}; overflow: auto; width: 100%; - max-height: calc(90vh - ${theme.spacing(2)}); + max-height: calc(90vh - ${theme.spacing(4)}); + `, + modalButtonRow: css` + padding-top: ${theme.spacing(3)}; `, }; }); diff --git a/packages/grafana-ui/src/components/Tabs/TabContent.tsx b/packages/grafana-ui/src/components/Tabs/TabContent.tsx index cef016f0b1c..9463f09a9d1 100644 --- a/packages/grafana-ui/src/components/Tabs/TabContent.tsx +++ b/packages/grafana-ui/src/components/Tabs/TabContent.tsx @@ -10,7 +10,6 @@ interface Props extends HTMLAttributes { const getTabContentStyle = stylesFactory((theme: GrafanaThemeV2) => { return { tabContent: css` - padding: ${theme.spacing(1)}; background: ${theme.colors.background.primary}; `, }; diff --git a/public/app/features/dashboard/components/DeleteDashboard/DeleteDashboardModal.tsx b/public/app/features/dashboard/components/DeleteDashboard/DeleteDashboardModal.tsx index bb279be76aa..d23cd8cc72b 100644 --- a/public/app/features/dashboard/components/DeleteDashboard/DeleteDashboardModal.tsx +++ b/public/app/features/dashboard/components/DeleteDashboard/DeleteDashboardModal.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { css } from '@emotion/css'; import { sumBy } from 'lodash'; -import { Modal, ConfirmModal, HorizontalGroup, Button } from '@grafana/ui'; +import { Modal, ConfirmModal, Button } from '@grafana/ui'; import { DashboardModel, PanelModel } from '../../state'; import { useDashboardDelete } from './useDashboardDelete'; import useAsyncFn from 'react-use/lib/useAsyncFn'; @@ -88,10 +88,10 @@ const ProvisionedDeleteModal = ({ hideModal, provisionedId }: { hideModal(): voi
File path: {provisionedId}

- + - + ); diff --git a/public/app/features/dashboard/components/RowOptions/RowOptionsForm.tsx b/public/app/features/dashboard/components/RowOptions/RowOptionsForm.tsx index 7fc77cf5aec..343db6beb78 100644 --- a/public/app/features/dashboard/components/RowOptions/RowOptionsForm.tsx +++ b/public/app/features/dashboard/components/RowOptions/RowOptionsForm.tsx @@ -1,5 +1,5 @@ import React, { FC, useCallback, useState } from 'react'; -import { Button, Field, Form, HorizontalGroup, Input } from '@grafana/ui'; +import { Button, Field, Form, Modal, Input } from '@grafana/ui'; import { RepeatRowSelect } from '../RepeatRowSelect/RepeatRowSelect'; @@ -33,12 +33,12 @@ export const RowOptionsForm: FC = ({ repeat, title, onUpdate, onCancel }) - + - + )} diff --git a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardErrorProxy.tsx b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardErrorProxy.tsx index 3822f56c853..d6b731edd94 100644 --- a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardErrorProxy.tsx +++ b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardErrorProxy.tsx @@ -1,5 +1,5 @@ import React, { useEffect } from 'react'; -import { Button, ConfirmModal, HorizontalGroup, Modal, stylesFactory, useTheme } from '@grafana/ui'; +import { Button, ConfirmModal, Modal, stylesFactory, useTheme } from '@grafana/ui'; import { GrafanaTheme } from '@grafana/data'; import { css } from '@emotion/css'; import { DashboardModel } from 'app/features/dashboard/state'; @@ -89,7 +89,7 @@ const ConfirmPluginDashboardSaveModal: React.FC = ({ on Use Save As to create custom version.
- + - +
); diff --git a/public/app/features/dashboard/components/SaveDashboard/UnsavedChangesModal.tsx b/public/app/features/dashboard/components/SaveDashboard/UnsavedChangesModal.tsx index b4221e0ea23..8f6142a62af 100644 --- a/public/app/features/dashboard/components/SaveDashboard/UnsavedChangesModal.tsx +++ b/public/app/features/dashboard/components/SaveDashboard/UnsavedChangesModal.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Button, HorizontalGroup, Modal, VerticalGroup } from '@grafana/ui'; +import { Button, Modal } from '@grafana/ui'; import { SaveDashboardButton } from './SaveDashboardButton'; import { DashboardModel } from '../../state'; import { css } from '@emotion/css'; @@ -27,24 +27,22 @@ export const UnsavedChangesModal: React.FC = ({ width: 500px; `} > - -

Do you want to save your changes?

- - - - - -
+
Do you want to save your changes?
+ + + + + ); }; diff --git a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.tsx b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.tsx index 4d0f092e34c..79ee49c8cb0 100644 --- a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.tsx +++ b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Button, HorizontalGroup, Input, Switch, Form, Field, InputControl } from '@grafana/ui'; +import { Button, Input, Switch, Form, Field, InputControl, Modal } from '@grafana/ui'; import { DashboardModel, PanelModel } from 'app/features/dashboard/state'; import { FolderPicker } from 'app/core/components/Select/FolderPicker'; import { SaveDashboardFormProps } from '../types'; @@ -114,14 +114,14 @@ export const SaveDashboardAsForm: React.FC - - + - + + )} diff --git a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.tsx b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.tsx index b2cba26fc60..932cca130d6 100644 --- a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.tsx +++ b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.tsx @@ -1,6 +1,6 @@ import React, { useMemo } from 'react'; -import { Button, Checkbox, Form, HorizontalGroup, TextArea } from '@grafana/ui'; +import { Button, Checkbox, Form, Modal, TextArea } from '@grafana/ui'; import { selectors } from '@grafana/e2e-selectors'; import { SaveDashboardFormProps } from '../types'; @@ -36,7 +36,7 @@ export const SaveDashboardForm: React.FC = ({ dashboard, > {({ register, errors }) => ( <> -
+
{hasTimeChanged && ( = ({ dashboard, - - Copy to clipboard - + + + Copy to clipboard + + ); } diff --git a/public/app/features/dashboard/components/ShareModal/ShareExport.tsx b/public/app/features/dashboard/components/ShareModal/ShareExport.tsx index 6ff70790ea2..581f5103c73 100644 --- a/public/app/features/dashboard/components/ShareModal/ShareExport.tsx +++ b/public/app/features/dashboard/components/ShareModal/ShareExport.tsx @@ -1,6 +1,6 @@ import React, { PureComponent } from 'react'; import { saveAs } from 'file-saver'; -import { Button, Field, Switch } from '@grafana/ui'; +import { Button, Field, Modal, Switch } from '@grafana/ui'; import { DashboardModel, PanelModel } from 'app/features/dashboard/state'; import { DashboardExporter } from 'app/features/dashboard/components/DashExportModal'; import { appEvents } from 'app/core/core'; @@ -95,17 +95,17 @@ export class ShareExport extends PureComponent { -
- - -
+ ); } diff --git a/public/app/features/dashboard/components/ShareModal/ShareSnapshot.tsx b/public/app/features/dashboard/components/ShareModal/ShareSnapshot.tsx index 20b68937afd..c6fd0f5e369 100644 --- a/public/app/features/dashboard/components/ShareModal/ShareSnapshot.tsx +++ b/public/app/features/dashboard/components/ShareModal/ShareSnapshot.tsx @@ -1,5 +1,5 @@ import React, { PureComponent } from 'react'; -import { Button, ClipboardButton, Icon, Spinner, Select, Input, LinkButton, Field } from '@grafana/ui'; +import { Button, ClipboardButton, Icon, Spinner, Select, Input, LinkButton, Field, Modal } from '@grafana/ui'; import { AppEvents, SelectableValue } from '@grafana/data'; import { getBackendSrv } from '@grafana/runtime'; import { DashboardModel, PanelModel } from 'app/features/dashboard/state'; @@ -233,19 +233,19 @@ export class ShareSnapshot extends PureComponent { -
- {externalEnabled && ( )} - -
+ ); } diff --git a/public/app/features/library-panels/components/AddLibraryPanelModal/AddLibraryPanelModal.tsx b/public/app/features/library-panels/components/AddLibraryPanelModal/AddLibraryPanelModal.tsx index 1e64a76410a..b41ace7247c 100644 --- a/public/app/features/library-panels/components/AddLibraryPanelModal/AddLibraryPanelModal.tsx +++ b/public/app/features/library-panels/components/AddLibraryPanelModal/AddLibraryPanelModal.tsx @@ -1,8 +1,7 @@ import React, { useState } from 'react'; -import { Button, Field, Input, Modal, useStyles } from '@grafana/ui'; +import { Button, Field, Input, Modal } from '@grafana/ui'; import { FolderPicker } from 'app/core/components/Select/FolderPicker'; import { PanelModel } from '../../../dashboard/state'; -import { css } from '@emotion/css'; import { usePanelSave } from '../../utils/usePanelSave'; interface AddLibraryPanelContentsProps { onDismiss: () => void; @@ -11,7 +10,6 @@ interface AddLibraryPanelContentsProps { } export const AddLibraryPanelContents = ({ panel, initialFolderId, onDismiss }: AddLibraryPanelContentsProps) => { - const styles = useStyles(getStyles); const [folderId, setFolderId] = useState(initialFolderId); const [panelTitle, setPanelTitle] = useState(panel.title); const { saveLibraryPanel } = usePanelSave(); @@ -25,7 +23,7 @@ export const AddLibraryPanelContents = ({ panel, initialFolderId, onDismiss }: A setFolderId(id)} initialFolderId={initialFolderId} /> -
+ -
+ ); }; @@ -53,10 +51,3 @@ export const AddLibraryPanelModal: React.FC = ({ isOpen = false, panel, i ); }; - -const getStyles = () => ({ - buttons: css` - display: flex; - gap: 10px; - `, -}); diff --git a/public/app/features/library-panels/components/DeleteLibraryPanelModal/DeleteLibraryPanelModal.tsx b/public/app/features/library-panels/components/DeleteLibraryPanelModal/DeleteLibraryPanelModal.tsx index 1e46b5679a1..1264faf2f4c 100644 --- a/public/app/features/library-panels/components/DeleteLibraryPanelModal/DeleteLibraryPanelModal.tsx +++ b/public/app/features/library-panels/components/DeleteLibraryPanelModal/DeleteLibraryPanelModal.tsx @@ -1,5 +1,5 @@ import React, { FC, useEffect, useMemo, useReducer } from 'react'; -import { Button, HorizontalGroup, Modal, useStyles } from '@grafana/ui'; +import { Button, Modal, useStyles } from '@grafana/ui'; import { LoadingState } from '@grafana/data'; import { LibraryPanelDTO } from '../../types'; @@ -35,14 +35,14 @@ export const DeleteLibraryPanelModal: FC = ({ libraryPanel, onDismiss, on {connected ? : null} {!connected ? : null} - - + - + +
) : null} diff --git a/public/app/features/library-panels/components/SaveLibraryPanelModal/SaveLibraryPanelModal.tsx b/public/app/features/library-panels/components/SaveLibraryPanelModal/SaveLibraryPanelModal.tsx index 53c25f610b6..43a5ed21013 100644 --- a/public/app/features/library-panels/components/SaveLibraryPanelModal/SaveLibraryPanelModal.tsx +++ b/public/app/features/library-panels/components/SaveLibraryPanelModal/SaveLibraryPanelModal.tsx @@ -1,5 +1,5 @@ import React, { useCallback, useState } from 'react'; -import { Button, HorizontalGroup, Icon, Input, Modal, useStyles } from '@grafana/ui'; +import { Button, Icon, Input, Modal, useStyles } from '@grafana/ui'; import { useAsync, useDebounce } from 'react-use'; import { getBackendSrv } from 'app/core/services/backend_srv'; import { usePanelSave } from '../../utils/usePanelSave'; @@ -98,7 +98,13 @@ export const SaveLibraryPanelModal: React.FC = ({ )} - + + + - - - +
); diff --git a/public/app/features/playlist/PlaylistPage.tsx b/public/app/features/playlist/PlaylistPage.tsx index a51baa7a6d7..142f08fc260 100644 --- a/public/app/features/playlist/PlaylistPage.tsx +++ b/public/app/features/playlist/PlaylistPage.tsx @@ -132,11 +132,11 @@ export const StartModal: FC = ({ playlist, onDismiss }) => { onChange={(e) => setAutofit(e.currentTarget.checked)} /> -
+ -
+ ); };