*/
// @flow
import React from 'react';
-import Clipboard from 'clipboard';
import classNames from 'classnames';
-import Tooltip from '../../../../components/controls/Tooltip';
+import ClipboardButton from '../../../../components/controls/ClipboardButton';
import { translate } from '../../../../helpers/l10n';
/*::
};
*/
-/*::
-type State = {
- tooltipShown: boolean
-};
-*/
-
const s = ' \\' + '\n ';
export default class Command extends React.PureComponent {
- /*:: clipboard: Object; */
- /*:: copyButton: HTMLButtonElement; */
- /*:: mounted: boolean; */
/*:: props: Props; */
- state /*: State */ = { tooltipShown: false };
-
- componentDidMount() {
- this.mounted = true;
- this.clipboard = new Clipboard(this.copyButton);
- this.clipboard.on('success', this.showTooltip);
- }
-
- componentDidUpdate() {
- this.clipboard.destroy();
- this.clipboard = new Clipboard(this.copyButton);
- this.clipboard.on('success', this.showTooltip);
- }
-
- componentWillUnmount() {
- this.mounted = false;
- this.clipboard.destroy();
- }
-
- showTooltip = () => {
- if (this.mounted) {
- this.setState({ tooltipShown: true });
- setTimeout(this.hideTooltip, 1000);
- }
- };
-
- hideTooltip = () => {
- if (this.mounted) {
- this.setState({ tooltipShown: false });
- }
- };
render() {
const { command, isWindows } = this.props;
const commandArray = Array.isArray(command) ? command.filter(line => line != null) : [command];
const finalCommand = isWindows ? commandArray.join(' ') : commandArray.join(s);
- const button = (
- <button data-clipboard-text={finalCommand} ref={node => (this.copyButton = node)}>
- {translate('copy')}
- </button>
- );
-
return (
<div
className={classNames('onboarding-command', { 'onboarding-command-windows': isWindows })}>
<pre>{finalCommand}</pre>
- {this.state.tooltipShown ? (
- <Tooltip defaultVisible={true} placement="top" overlay="Copied!" trigger="manual">
- {button}
- </Tooltip>
- ) : (
- button
- )}
+ <ClipboardButton copyValue={finalCommand} tooltipPlacement="top" />
</div>
);
}
foo
bar
</pre>
- <button
- data-clipboard-text="foo
+ <ClipboardButton
+ copyValue="foo
bar"
+ tooltipPlacement="top"
>
- copy
- </button>
+ <button
+ className="js-copy-to-clipboard no-select"
+ data-clipboard-text="foo
+bar"
+ >
+ copy
+ </button>
+ </ClipboardButton>
</div>
</Command>
`;
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import * as Clipboard from 'clipboard';
-import Tooltip from '../../../components/controls/Tooltip';
-import { translate, translateWithParameters } from '../../../helpers/l10n';
+import ClipboardButton from '../../../components/controls/ClipboardButton';
+import { translateWithParameters } from '../../../helpers/l10n';
interface Props {
token: { name: string; token: string };
}
-interface State {
- tooltipShown: boolean;
-}
-
-export default class TokensFormNewToken extends React.PureComponent<Props, State> {
- clipboard: Clipboard;
- copyButton: HTMLButtonElement | null;
- mounted: boolean;
- state: State = { tooltipShown: false };
-
- componentDidMount() {
- this.mounted = true;
- if (this.copyButton) {
- this.clipboard = new Clipboard(this.copyButton);
- this.clipboard.on('success', this.showTooltip);
- }
- }
-
- componentDidUpdate() {
- this.clipboard.destroy();
- if (this.copyButton) {
- this.clipboard = new Clipboard(this.copyButton);
- this.clipboard.on('success', this.showTooltip);
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- this.clipboard.destroy();
- }
-
- showTooltip = () => {
- if (this.mounted) {
- this.setState({ tooltipShown: true });
- setTimeout(() => {
- if (this.mounted) {
- this.setState({ tooltipShown: false });
- }
- }, 1000);
- }
- };
-
- render() {
- const { name, token } = this.props.token;
- const button = (
- <button
- className="js-copy-to-clipboard no-select"
- data-clipboard-text={token}
- ref={node => (this.copyButton = node)}>
- {translate('copy')}
- </button>
- );
- return (
- <div className="panel panel-white big-spacer-top">
- <p className="alert alert-warning">
- {translateWithParameters('users.tokens.new_token_created', name)}
- </p>
- {this.state.tooltipShown ? (
- <Tooltip
- defaultVisible={true}
- placement="bottom"
- overlay={translate('users.tokens.copied')}
- trigger="manual">
- {button}
- </Tooltip>
- ) : (
- button
- )}
- <code className="big-spacer-left text-success">{token}</code>
- </div>
- );
- }
+export default function TokensFormNewToken({ token }: Props) {
+ return (
+ <div className="panel panel-white big-spacer-top">
+ <p className="alert alert-warning">
+ {translateWithParameters('users.tokens.new_token_created', token.name)}
+ </p>
+ <ClipboardButton copyValue={token.token} />
+ <code className="big-spacer-left text-success">{token.token}</code>
+ </div>
+ );
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import * as classNames from 'classnames';
+import * as Clipboard from 'clipboard';
+import Tooltip from './Tooltip';
+import { translate } from '../../helpers/l10n';
+
+interface Props {
+ className?: string;
+ copyValue: string;
+ tooltipPlacement?: string;
+}
+
+interface State {
+ tooltipShown: boolean;
+}
+
+export default class ClipboardButton extends React.PureComponent<Props, State> {
+ clipboard: Clipboard;
+ copyButton: HTMLButtonElement | null;
+ mounted: boolean;
+ state: State = { tooltipShown: false };
+
+ componentDidMount() {
+ this.mounted = true;
+ if (this.copyButton) {
+ this.clipboard = new Clipboard(this.copyButton);
+ this.clipboard.on('success', this.showTooltip);
+ }
+ }
+
+ componentDidUpdate() {
+ if (this.clipboard) {
+ this.clipboard.destroy();
+ }
+ if (this.copyButton) {
+ this.clipboard = new Clipboard(this.copyButton);
+ this.clipboard.on('success', this.showTooltip);
+ }
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ this.clipboard.destroy();
+ }
+
+ showTooltip = () => {
+ if (this.mounted) {
+ this.setState({ tooltipShown: true });
+ setTimeout(() => {
+ if (this.mounted) {
+ this.setState({ tooltipShown: false });
+ }
+ }, 1000);
+ }
+ };
+
+ render() {
+ const button = (
+ <button
+ className={classNames('js-copy-to-clipboard no-select', this.props.className)}
+ data-clipboard-text={this.props.copyValue}
+ ref={node => (this.copyButton = node)}>
+ {translate('copy')}
+ </button>
+ );
+ if (this.state.tooltipShown) {
+ return (
+ <Tooltip
+ defaultVisible={true}
+ placement={this.props.tooltipPlacement || 'bottom'}
+ overlay={translate('copied_action')}
+ trigger="manual">
+ {button}
+ </Tooltip>
+ );
+ }
+ return button;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import ClipboardButton from '../ClipboardButton';
+
+jest.useFakeTimers();
+
+it('should display correctly', () => {
+ const wrapper = shallow(<ClipboardButton copyValue="foo" />);
+ expect(wrapper).toMatchSnapshot();
+ (wrapper.instance() as ClipboardButton).showTooltip();
+ wrapper.update();
+ expect(wrapper).toMatchSnapshot();
+ jest.runAllTimers();
+ wrapper.update();
+ expect(wrapper.find('Tooltip')).toHaveLength(0);
+});
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should display correctly 1`] = `
+<button
+ className="js-copy-to-clipboard no-select"
+ data-clipboard-text="foo"
+>
+ copy
+</button>
+`;
+
+exports[`should display correctly 2`] = `
+<Tooltip
+ defaultVisible={true}
+ overlay="copied_action"
+ placement="bottom"
+ trigger="manual"
+>
+ <button
+ className="js-copy-to-clipboard no-select"
+ data-clipboard-text="foo"
+ >
+ copy
+ </button>
+</Tooltip>
+`;
assigned_to=Assigned to
bulk_change=Bulk Change
bulleted_point=Bulleted point
-coding_rules=Rules
clear=Clear
clear_all_filters=Clear All Filters
+coding_rules=Rules
+copied_action=Copied!
created_by=Created by
default_error_message=The request cannot be processed. Try again later.
default_severity=Default severity