GrafanaUI: Add success state to ClipboardButton (#52069)

* User Experience: apply the same pattern feedback for all copy to clipboard buttons

* add copy icon to all ClipboardButton use cases

* Change primary color for copy to clipboard in create token

* Add success button variant

* Remove copy confirmation from TableCellInspectModal because it's in the base component now

* Design tweaks to copy confirmation

 - Only change the icon to tick to avoid the button changing size
 - Change button to success green
 - Only show copy confirmation state for 2 seconds

* revert TabelCellInspectModal text button back

* revert accidental change to ShareLink

Co-authored-by: joshhunt <josh@trtr.co>
This commit is contained in:
Ezequiel Victorero
2022-07-20 06:33:46 -03:00
committed by GitHub
parent ba76be174f
commit 0633840777
16 changed files with 78 additions and 125 deletions

View File

@@ -5,13 +5,11 @@ import React, { useCallback, useState } from 'react';
import { GrafanaTheme } from '@grafana/data';
import { Stack } from '@grafana/experimental';
import { Button, ClipboardButton, HorizontalGroup, stylesFactory, TextArea, useTheme } from '@grafana/ui';
import { useAppNotification } from 'app/core/copy/appNotification';
import { SaveDashboardFormProps } from '../types';
export const SaveProvisionedDashboardForm: React.FC<SaveDashboardFormProps> = ({ dashboard, onCancel }) => {
const theme = useTheme();
const notifyApp = useAppNotification();
const [dashboardJSON, setDashboardJson] = useState(() => {
const clone = dashboard.getSaveModelClone();
delete clone.id;
@@ -25,10 +23,6 @@ export const SaveProvisionedDashboardForm: React.FC<SaveDashboardFormProps> = ({
saveAs(blob, dashboard.title + '-' + new Date().getTime() + '.json');
}, [dashboard.title, dashboardJSON]);
const onCopyToClipboardSuccess = useCallback(() => {
notifyApp.success('Dashboard JSON copied to clipboard');
}, [notifyApp]);
const styles = getStyles(theme);
return (
<>
@@ -64,7 +58,7 @@ export const SaveProvisionedDashboardForm: React.FC<SaveDashboardFormProps> = ({
<Button variant="secondary" onClick={onCancel} fill="outline">
Cancel
</Button>
<ClipboardButton getText={() => dashboardJSON} onClipboardCopy={onCopyToClipboardSuccess}>
<ClipboardButton icon="copy" getText={() => dashboardJSON}>
Copy JSON to clipboard
</ClipboardButton>
<Button type="submit" onClick={saveToFile}>

View File

@@ -1,9 +1,8 @@
import React, { FormEvent, PureComponent } from 'react';
import { AppEvents, SelectableValue } from '@grafana/data';
import { SelectableValue } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime/src';
import { ClipboardButton, Field, Modal, RadioButtonGroup, Switch, TextArea } from '@grafana/ui';
import { appEvents } from 'app/core/core';
import { ShareModalTabProps } from './types';
import { buildIframeHtml } from './utils';
@@ -62,10 +61,6 @@ export class ShareEmbed extends PureComponent<Props, State> {
this.setState({ selectedTheme: value }, this.buildIframeHtml);
};
onIframeHtmlCopy = () => {
appEvents.emit(AppEvents.alertSuccess, ['Content copied to clipboard']);
};
getIframeHtml = () => {
return this.state.iframeHtml;
};
@@ -104,7 +99,7 @@ export class ShareEmbed extends PureComponent<Props, State> {
/>
</Field>
<Modal.ButtonRow>
<ClipboardButton variant="primary" getText={this.getIframeHtml} onClipboardCopy={this.onIframeHtmlCopy}>
<ClipboardButton icon="copy" variant="primary" getText={this.getIframeHtml}>
Copy to clipboard
</ClipboardButton>
</Modal.ButtonRow>

View File

@@ -1,11 +1,10 @@
import React, { PureComponent } from 'react';
import { AppEvents, SelectableValue } from '@grafana/data';
import { SelectableValue } from '@grafana/data';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
import { reportInteraction } from '@grafana/runtime/src';
import { Alert, ClipboardButton, Field, FieldSet, Icon, Input, RadioButtonGroup, Switch } from '@grafana/ui';
import config from 'app/core/config';
import { appEvents } from 'app/core/core';
import { ShareModalTabProps } from './types';
import { buildImageUrl, buildShareUrl } from './utils';
@@ -76,10 +75,6 @@ export class ShareLink extends PureComponent<Props, State> {
this.setState({ selectedTheme: value });
};
onShareUrlCopy = () => {
appEvents.emit(AppEvents.alertSuccess, ['Content copied to clipboard']);
};
getShareUrl = () => {
return this.state.shareUrl;
};
@@ -120,8 +115,8 @@ export class ShareLink extends PureComponent<Props, State> {
value={shareUrl}
readOnly
addonAfter={
<ClipboardButton variant="primary" getText={this.getShareUrl} onClipboardCopy={this.onShareUrlCopy}>
<Icon name="copy" /> Copy
<ClipboardButton icon="copy" variant="primary" getText={this.getShareUrl}>
Copy
</ClipboardButton>
}
/>

View File

@@ -1,6 +1,5 @@
import React, { useCallback, useEffect, useState } from 'react';
import { AppEvents } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime/src';
import {
Alert,
@@ -16,7 +15,6 @@ import {
} from '@grafana/ui';
import { notifyApp } from 'app/core/actions';
import { createErrorNotification } from 'app/core/copy/appNotification';
import { appEvents } from 'app/core/core';
import { dispatch } from 'app/store/store';
import {
@@ -79,10 +77,6 @@ export const SharePublicDashboard = (props: Props) => {
savePublicDashboardConfig(props.dashboard.uid, publicDashboard, setPublicDashboardConfig).catch();
};
const onShareUrlCopy = () => {
appEvents.emit(AppEvents.alertSuccess, ['Content copied to clipboard']);
};
const onAcknowledge = useCallback(
(field: string, checked: boolean) => {
setAcknowledgements({ ...acknowledgements, [field]: checked });
@@ -219,7 +213,6 @@ export const SharePublicDashboard = (props: Props) => {
getText={() => {
return generatePublicDashboardUrl(publicDashboard);
}}
onClipboardCopy={onShareUrlCopy}
>
Copy
</ClipboardButton>

View File

@@ -1,9 +1,8 @@
import React, { PureComponent } from 'react';
import { AppEvents, SelectableValue } from '@grafana/data';
import { SelectableValue } from '@grafana/data';
import { getBackendSrv, reportInteraction } from '@grafana/runtime';
import { Button, ClipboardButton, Field, Icon, Input, LinkButton, Modal, Select, Spinner } from '@grafana/ui';
import { appEvents } from 'app/core/core';
import { Button, ClipboardButton, Field, Input, LinkButton, Modal, Select, Spinner } from '@grafana/ui';
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
@@ -198,10 +197,6 @@ export class ShareSnapshot extends PureComponent<Props, State> {
});
};
onSnapshotUrlCopy = () => {
appEvents.emit(AppEvents.alertSuccess, ['Content copied to clipboard']);
};
renderStep1() {
const { onDismiss } = this.props;
const { snapshotName, selectedExpireOption, timeoutSeconds, isLoading, sharingButtonText, externalEnabled } =
@@ -262,17 +257,18 @@ export class ShareSnapshot extends PureComponent<Props, State> {
return (
<>
<div className="gf-form" style={{ marginTop: '40px' }}>
<div className="gf-form-row">
<a href={snapshotUrl} className="large share-modal-link" target="_blank" rel="noreferrer">
<Icon name="external-link-alt" /> {snapshotUrl}
</a>
<br />
<ClipboardButton variant="secondary" getText={this.getSnapshotUrl} onClipboardCopy={this.onSnapshotUrlCopy}>
Copy Link
</ClipboardButton>
</div>
</div>
<Field label="Snapshot URL">
<Input
id="snapshot-url-input"
value={snapshotUrl}
readOnly
addonAfter={
<ClipboardButton icon="copy" variant="primary" getText={this.getSnapshotUrl}>
Copy
</ClipboardButton>
}
/>
</Field>
<div className="pull-right" style={{ padding: '5px' }}>
Did you make a mistake?{' '}

View File

@@ -3,10 +3,6 @@ import AutoSizer from 'react-virtualized-auto-sizer';
import { ClipboardButton, CodeEditor, Modal } from '@grafana/ui';
import { notifyApp } from '../../../../core/actions';
import { createSuccessNotification } from '../../../../core/copy/appNotification';
import { dispatch } from '../../../../store/store';
export interface ViewJsonModalProps {
json: string;
onDismiss: () => void;
@@ -14,16 +10,13 @@ export interface ViewJsonModalProps {
export function ViewJsonModal({ json, onDismiss }: ViewJsonModalProps): JSX.Element {
const getClipboardText = useCallback(() => json, [json]);
const onClipboardCopy = () => {
dispatch(notifyApp(createSuccessNotification('Content copied to clipboard')));
};
return (
<Modal title="JSON" onDismiss={onDismiss} onClickBackdrop={onDismiss} isOpen>
<AutoSizer disableHeight>
{({ width }) => <CodeEditor value={json} language="json" showMiniMap={false} height="500px" width={width} />}
</AutoSizer>
<Modal.ButtonRow>
<ClipboardButton getText={getClipboardText} onClipboardCopy={onClipboardCopy}>
<ClipboardButton icon="copy" getText={getClipboardText}>
Copy to Clipboard
</ClipboardButton>
</Modal.ButtonRow>