Modals: design update (#33368)

* Modals: Style update draft

* Modal.ButtonRow to control spacing better in a centralised way

* Remove header border if no tabs

* Added border and made buttons right aligned and changed order of buttons

* Updating the overlay

* Tweaks to paddings

* Updated share modals
This commit is contained in:
Torkel Ödegaard
2021-04-26 18:26:56 +02:00
committed by GitHub
parent de65cef850
commit 4643bfa539
23 changed files with 176 additions and 166 deletions

View File

@@ -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
<br />
File path: {provisionedId}
</p>
<HorizontalGroup justify="center">
<Modal.ButtonRow>
<Button variant="secondary" onClick={hideModal}>
OK
</Button>
</HorizontalGroup>
</Modal.ButtonRow>
</Modal>
);

View File

@@ -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<Props> = ({ repeat, title, onUpdate, onCancel })
<RepeatRowSelect repeat={newRepeat} onChange={onChangeRepeat} />
</Field>
<HorizontalGroup>
<Modal.ButtonRow>
<Button type="submit">Update</Button>
<Button variant="secondary" onClick={onCancel}>
Cancel
</Button>
</HorizontalGroup>
</Modal.ButtonRow>
</>
)}
</Form>

View File

@@ -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<SaveDashboardModalProps> = ({ on
Use <strong>Save As</strong> to create custom version.
</small>
</div>
<HorizontalGroup justify="center">
<Modal.ButtonRow>
<SaveDashboardAsButton dashboard={dashboard} onSaveSuccess={onDismiss} />
<Button
variant="destructive"
@@ -103,7 +103,7 @@ const ConfirmPluginDashboardSaveModal: React.FC<SaveDashboardModalProps> = ({ on
<Button variant="secondary" onClick={onDismiss}>
Cancel
</Button>
</HorizontalGroup>
</Modal.ButtonRow>
</div>
</Modal>
);

View File

@@ -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<UnsavedChangesModalProps> = ({
width: 500px;
`}
>
<VerticalGroup align={'center'} spacing={'md'}>
<h4>Do you want to save your changes?</h4>
<HorizontalGroup justify="center">
<SaveDashboardButton dashboard={dashboard} onSaveSuccess={onSaveSuccess} />
<Button
variant="destructive"
onClick={() => {
onDiscard();
onDismiss();
}}
>
Discard
</Button>
<Button variant="secondary" onClick={onDismiss}>
Cancel
</Button>
</HorizontalGroup>
</VerticalGroup>
<h5>Do you want to save your changes?</h5>
<Modal.ButtonRow>
<Button variant="secondary" onClick={onDismiss}>
Cancel
</Button>
<Button
variant="destructive"
onClick={() => {
onDiscard();
onDismiss();
}}
>
Discard
</Button>
<SaveDashboardButton dashboard={dashboard} onSaveSuccess={onSaveSuccess} />
</Modal.ButtonRow>
</Modal>
);
};

View File

@@ -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<SaveDashboardFormProps & { isNew?: bo
<Field label="Copy tags">
<Switch name="copyTags" ref={register} />
</Field>
<HorizontalGroup>
<Button type="submit" aria-label="Save dashboard button">
Save
</Button>
<Modal.ButtonRow>
<Button variant="secondary" onClick={onCancel}>
Cancel
</Button>
</HorizontalGroup>
<Button type="submit" aria-label="Save dashboard button">
Save
</Button>
</Modal.ButtonRow>
</>
)}
</Form>

View File

@@ -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<SaveDashboardFormProps> = ({ dashboard,
>
{({ register, errors }) => (
<>
<div className="gf-form-group">
<div>
{hasTimeChanged && (
<Checkbox
label="Save current time range as dashboard default"
@@ -58,14 +58,14 @@ export const SaveDashboardForm: React.FC<SaveDashboardFormProps> = ({ dashboard,
<TextArea name="message" ref={register} placeholder="Add a note to describe your changes." autoFocus />
</div>
<HorizontalGroup>
<Button type="submit" aria-label={selectors.pages.SaveDashboardModal.save}>
Save
</Button>
<Modal.ButtonRow>
<Button variant="secondary" onClick={onCancel}>
Cancel
</Button>
</HorizontalGroup>
<Button type="submit" aria-label={selectors.pages.SaveDashboardModal.save}>
Save
</Button>
</Modal.ButtonRow>
</>
)}
</Form>

View File

@@ -1,7 +1,7 @@
import React, { useCallback, useState } from 'react';
import { css } from '@emotion/css';
import { saveAs } from 'file-saver';
import { Button, HorizontalGroup, stylesFactory, TextArea, useTheme, VerticalGroup } from '@grafana/ui';
import { Button, Modal, stylesFactory, TextArea, useTheme } from '@grafana/ui';
import { CopyToClipboard } from 'app/core/components/CopyToClipboard/CopyToClipboard';
import { SaveDashboardFormProps } from '../types';
import { AppEvents, GrafanaTheme } from '@grafana/data';
@@ -29,8 +29,8 @@ export const SaveProvisionedDashboardForm: React.FC<SaveDashboardFormProps> = ({
const styles = getStyles(theme);
return (
<>
<VerticalGroup spacing="lg">
<small>
<div>
<div>
This dashboard cannot be saved from the Grafana UI because it has been provisioned from another source. Copy
the JSON or save it to a file below, then you can update your dashboard in the provisioning source.
<br />
@@ -46,8 +46,7 @@ export const SaveProvisionedDashboardForm: React.FC<SaveDashboardFormProps> = ({
</a>{' '}
for more information about provisioning.
</i>
</small>
<div>
<br /> <br />
<strong>File path: </strong> {dashboard.meta.provisionedExternalId}
</div>
<TextArea
@@ -58,16 +57,16 @@ export const SaveProvisionedDashboardForm: React.FC<SaveDashboardFormProps> = ({
}}
className={styles.json}
/>
<HorizontalGroup>
<Modal.ButtonRow>
<Button variant="secondary" onClick={onCancel}>
Cancel
</Button>
<CopyToClipboard text={() => dashboardJSON} elType={Button} onSuccess={onCopyToClipboardSuccess}>
Copy JSON to clipboard
</CopyToClipboard>
<Button onClick={saveToFile}>Save JSON to file</Button>
<Button variant="secondary" onClick={onCancel}>
Cancel
</Button>
</HorizontalGroup>
</VerticalGroup>
</Modal.ButtonRow>
</div>
</>
);
};

View File

@@ -1,5 +1,5 @@
import React, { FormEvent, PureComponent } from 'react';
import { RadioButtonGroup, Switch, Field, TextArea, ClipboardButton } from '@grafana/ui';
import { RadioButtonGroup, Switch, Field, TextArea, ClipboardButton, Modal } from '@grafana/ui';
import { SelectableValue, AppEvents } from '@grafana/data';
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
import { appEvents } from 'app/core/core';
@@ -96,9 +96,11 @@ export class ShareEmbed extends PureComponent<Props, State> {
>
<TextArea rows={5} value={iframeHtml} onChange={this.onIframeHtmlChange}></TextArea>
</Field>
<ClipboardButton variant="primary" getText={this.getIframeHtml} onClipboardCopy={this.onIframeHtmlCopy}>
Copy to clipboard
</ClipboardButton>
<Modal.ButtonRow>
<ClipboardButton variant="primary" getText={this.getIframeHtml} onClipboardCopy={this.onIframeHtmlCopy}>
Copy to clipboard
</ClipboardButton>
</Modal.ButtonRow>
</>
);
}

View File

@@ -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<Props, State> {
<Field label="Export for sharing externally">
<Switch value={shareExternally} onChange={this.onShareExternallyChange} />
</Field>
<div className="gf-form-button-row">
<Button variant="primary" onClick={this.onSaveAsFile}>
Save to file
<Modal.ButtonRow>
<Button variant="secondary" onClick={onDismiss}>
Cancel
</Button>
<Button variant="secondary" onClick={this.onViewJson}>
View JSON
</Button>
<Button variant="secondary" onClick={onDismiss}>
Cancel
<Button variant="primary" onClick={this.onSaveAsFile}>
Save to file
</Button>
</div>
</Modal.ButtonRow>
</>
);
}

View File

@@ -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<Props, State> {
<Input type="number" width={21} value={timeoutSeconds} onChange={this.onTimeoutChange} />
</Field>
<div className="gf-form-button-row">
<Button variant="primary" disabled={isLoading} onClick={this.createSnapshot()}>
Local Snapshot
<Modal.ButtonRow>
<Button variant="secondary" onClick={onDismiss}>
Cancel
</Button>
{externalEnabled && (
<Button variant="secondary" disabled={isLoading} onClick={this.createSnapshot(true)}>
{sharingButtonText}
</Button>
)}
<Button variant="secondary" onClick={onDismiss}>
Cancel
<Button variant="primary" disabled={isLoading} onClick={this.createSnapshot()}>
Local Snapshot
</Button>
</div>
</Modal.ButtonRow>
</>
);
}

View File

@@ -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
<FolderPicker onChange={({ id }) => setFolderId(id)} initialFolderId={initialFolderId} />
</Field>
<div className={styles.buttons}>
<Modal.ButtonRow>
<Button
onClick={() => {
panel.title = panelTitle;
@@ -37,7 +35,7 @@ export const AddLibraryPanelContents = ({ panel, initialFolderId, onDismiss }: A
<Button variant="secondary" onClick={onDismiss}>
Cancel
</Button>
</div>
</Modal.ButtonRow>
</>
);
};
@@ -53,10 +51,3 @@ export const AddLibraryPanelModal: React.FC<Props> = ({ isOpen = false, panel, i
</Modal>
);
};
const getStyles = () => ({
buttons: css`
display: flex;
gap: 10px;
`,
});

View File

@@ -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<Props> = ({ libraryPanel, onDismiss, on
{connected ? <HasConnectedDashboards dashboardTitles={dashboardTitles} /> : null}
{!connected ? <Confirm /> : null}
<HorizontalGroup>
<Button variant="destructive" onClick={onConfirm} disabled={connected}>
Delete
</Button>
<Modal.ButtonRow>
<Button variant="secondary" onClick={onDismiss}>
Cancel
</Button>
</HorizontalGroup>
<Button variant="destructive" onClick={onConfirm} disabled={connected}>
Delete
</Button>
</Modal.ButtonRow>
</div>
) : null}
</Modal>

View File

@@ -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<Props> = ({
</tbody>
</table>
)}
<HorizontalGroup>
<Modal.ButtonRow>
<Button variant="secondary" onClick={onDismiss}>
Cancel
</Button>
<Button variant="destructive" onClick={discardAndClose}>
Discard
</Button>
<Button
onClick={() => {
saveLibraryPanel(panel, folderId).then(() => {
@@ -109,13 +115,7 @@ export const SaveLibraryPanelModal: React.FC<Props> = ({
>
Update all
</Button>
<Button variant="destructive" onClick={discardAndClose}>
Discard
</Button>
<Button variant="secondary" onClick={onDismiss}>
Cancel
</Button>
</HorizontalGroup>
</Modal.ButtonRow>
</div>
</Modal>
);

View File

@@ -132,11 +132,11 @@ export const StartModal: FC<StartModalProps> = ({ playlist, onDismiss }) => {
onChange={(e) => setAutofit(e.currentTarget.checked)}
/>
</VerticalGroup>
<div className="gf-form-button-row">
<Modal.ButtonRow>
<Button variant="primary" onClick={onStart}>
Start {playlist.name}
</Button>
</div>
</Modal.ButtonRow>
</Modal>
);
};