diff options
author | Grégoire Aubert <gregoire.aubert@sonarsource.com> | 2018-01-10 17:28:51 +0100 |
---|---|---|
committer | Grégoire Aubert <gregoire.aubert@sonarsource.com> | 2018-01-25 15:16:50 +0100 |
commit | b3a593c103415e903db6974cc293c3dce462e20f (patch) | |
tree | f14b4cd8f1b70c34120135c3112a39e3a38529f3 /server/sonar-web/src/main | |
parent | addc88f96fb4b873d66ea32df433e98be741d7c7 (diff) | |
download | sonarqube-b3a593c103415e903db6974cc293c3dce462e20f.tar.gz sonarqube-b3a593c103415e903db6974cc293c3dce462e20f.zip |
Create a Clipboard button
Diffstat (limited to 'server/sonar-web/src/main')
6 files changed, 184 insertions, 134 deletions
diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/Command.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/Command.js index efa4ee1c2e6..23d728a407e 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/Command.js +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/Command.js @@ -19,9 +19,8 @@ */ // @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'; /*:: @@ -31,73 +30,21 @@ type Props = { }; */ -/*:: -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> ); } diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/Command-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/Command-test.js.snap index 63e31484c8d..2bd0aafd5b8 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/Command-test.js.snap +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/Command-test.js.snap @@ -12,12 +12,19 @@ bar" 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> `; diff --git a/server/sonar-web/src/main/js/apps/users/components/TokensFormNewToken.tsx b/server/sonar-web/src/main/js/apps/users/components/TokensFormNewToken.tsx index e3bb9df6b32..f7b744e9c1f 100644 --- a/server/sonar-web/src/main/js/apps/users/components/TokensFormNewToken.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/TokensFormNewToken.tsx @@ -18,84 +18,21 @@ * 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> + ); } diff --git a/server/sonar-web/src/main/js/components/controls/ClipboardButton.tsx b/server/sonar-web/src/main/js/components/controls/ClipboardButton.tsx new file mode 100644 index 00000000000..dc9b146d13e --- /dev/null +++ b/server/sonar-web/src/main/js/components/controls/ClipboardButton.tsx @@ -0,0 +1,98 @@ +/* + * 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; + } +} diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/ClipboardButton-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/ClipboardButton-test.tsx new file mode 100644 index 00000000000..a33520ea19e --- /dev/null +++ b/server/sonar-web/src/main/js/components/controls/__tests__/ClipboardButton-test.tsx @@ -0,0 +1,35 @@ +/* + * 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); +}); diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ClipboardButton-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ClipboardButton-test.tsx.snap new file mode 100644 index 00000000000..61870f73365 --- /dev/null +++ b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ClipboardButton-test.tsx.snap @@ -0,0 +1,26 @@ +// 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> +`; |