Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
145560a8be
commit
7b87f43b5b
|
@ -1,7 +1,13 @@
|
|||
import Clipboard from 'clipboard';
|
||||
import ClipboardJS from 'clipboard';
|
||||
import $ from 'jquery';
|
||||
import { sprintf, __ } from '~/locale';
|
||||
import { fixTitle, add, show, once } from '~/tooltips';
|
||||
|
||||
import { parseBoolean } from '~/lib/utils/common_utils';
|
||||
import { __ } from '~/locale';
|
||||
import { fixTitle, add, show, hide, once } from '~/tooltips';
|
||||
|
||||
const CLIPBOARD_SUCCESS_EVENT = 'clipboard-success';
|
||||
const CLIPBOARD_ERROR_EVENT = 'clipboard-error';
|
||||
const I18N_ERROR_MESSAGE = __('Copy failed. Please manually copy the value.');
|
||||
|
||||
function showTooltip(target, title) {
|
||||
const { title: originalTitle } = target.dataset;
|
||||
|
@ -9,20 +15,31 @@ function showTooltip(target, title) {
|
|||
once('hidden', (tooltip) => {
|
||||
if (tooltip.target === target) {
|
||||
target.setAttribute('title', originalTitle);
|
||||
target.setAttribute('aria-label', originalTitle);
|
||||
fixTitle(target);
|
||||
}
|
||||
});
|
||||
|
||||
target.setAttribute('title', title);
|
||||
target.setAttribute('aria-label', title);
|
||||
fixTitle(target);
|
||||
show(target);
|
||||
setTimeout(() => target.blur(), 1000);
|
||||
setTimeout(() => {
|
||||
hide(target);
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function genericSuccess(e) {
|
||||
// Clear the selection and blur the trigger so it loses its border
|
||||
// Clear the selection
|
||||
e.clearSelection();
|
||||
showTooltip(e.trigger, __('Copied'));
|
||||
e.trigger.focus();
|
||||
e.trigger.dispatchEvent(new Event(CLIPBOARD_SUCCESS_EVENT));
|
||||
|
||||
const { clipboardHandleTooltip = true } = e.trigger.dataset;
|
||||
if (parseBoolean(clipboardHandleTooltip)) {
|
||||
// Update tooltip
|
||||
showTooltip(e.trigger, __('Copied'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -30,17 +47,16 @@ function genericSuccess(e) {
|
|||
* See http://clipboardjs.com/#browser-support
|
||||
*/
|
||||
function genericError(e) {
|
||||
let key;
|
||||
if (/Mac/i.test(navigator.userAgent)) {
|
||||
key = '⌘'; // Command
|
||||
} else {
|
||||
key = 'Ctrl';
|
||||
e.trigger.dispatchEvent(new Event(CLIPBOARD_ERROR_EVENT));
|
||||
|
||||
const { clipboardHandleTooltip = true } = e.trigger.dataset;
|
||||
if (parseBoolean(clipboardHandleTooltip)) {
|
||||
showTooltip(e.trigger, I18N_ERROR_MESSAGE);
|
||||
}
|
||||
showTooltip(e.trigger, sprintf(__(`Press %{key}-C to copy`), { key }));
|
||||
}
|
||||
|
||||
export default function initCopyToClipboard() {
|
||||
const clipboard = new Clipboard('[data-clipboard-target], [data-clipboard-text]');
|
||||
const clipboard = new ClipboardJS('[data-clipboard-target], [data-clipboard-text]');
|
||||
clipboard.on('success', genericSuccess);
|
||||
clipboard.on('error', genericError);
|
||||
|
||||
|
@ -74,6 +90,8 @@ export default function initCopyToClipboard() {
|
|||
clipboardData.setData('text/plain', json.text);
|
||||
clipboardData.setData('text/x-gfm', json.gfm);
|
||||
});
|
||||
|
||||
return clipboard;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -89,3 +107,5 @@ export function clickCopyToClipboardButton(btnElement) {
|
|||
|
||||
btnElement.click();
|
||||
}
|
||||
|
||||
export { CLIPBOARD_SUCCESS_EVENT, CLIPBOARD_ERROR_EVENT, I18N_ERROR_MESSAGE };
|
||||
|
|
|
@ -13,9 +13,23 @@
|
|||
* />
|
||||
*/
|
||||
import { GlButton, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { uniqueId } from 'lodash';
|
||||
|
||||
import { __ } from '~/locale';
|
||||
import {
|
||||
CLIPBOARD_SUCCESS_EVENT,
|
||||
CLIPBOARD_ERROR_EVENT,
|
||||
I18N_ERROR_MESSAGE,
|
||||
} from '~/behaviors/copy_to_clipboard';
|
||||
|
||||
export default {
|
||||
name: 'ClipboardButton',
|
||||
i18n: {
|
||||
copied: __('Copied'),
|
||||
error: I18N_ERROR_MESSAGE,
|
||||
},
|
||||
CLIPBOARD_SUCCESS_EVENT,
|
||||
CLIPBOARD_ERROR_EVENT,
|
||||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
},
|
||||
|
@ -72,6 +86,13 @@ export default {
|
|||
default: 'default',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
localTitle: this.title,
|
||||
titleTimeout: null,
|
||||
id: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
clipboardText() {
|
||||
if (this.gfm !== null) {
|
||||
|
@ -79,25 +100,50 @@ export default {
|
|||
}
|
||||
return this.text;
|
||||
},
|
||||
tooltipDirectiveOptions() {
|
||||
return {
|
||||
placement: this.tooltipPlacement,
|
||||
container: this.tooltipContainer,
|
||||
boundary: this.tooltipBoundary,
|
||||
};
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.id = uniqueId('clipboard-button-');
|
||||
},
|
||||
methods: {
|
||||
updateTooltip(title) {
|
||||
this.localTitle = title;
|
||||
this.$root.$emit('bv::show::tooltip', this.id);
|
||||
|
||||
clearTimeout(this.titleTimeout);
|
||||
|
||||
this.titleTimeout = setTimeout(() => {
|
||||
this.localTitle = this.title;
|
||||
this.$root.$emit('bv::hide::tooltip', this.id);
|
||||
}, 1000);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<gl-button
|
||||
v-gl-tooltip.hover.blur.viewport="{
|
||||
placement: tooltipPlacement,
|
||||
container: tooltipContainer,
|
||||
boundary: tooltipBoundary,
|
||||
}"
|
||||
:id="id"
|
||||
ref="copyButton"
|
||||
v-gl-tooltip.hover.focus.click.viewport="tooltipDirectiveOptions"
|
||||
:class="cssClass"
|
||||
:title="title"
|
||||
:title="localTitle"
|
||||
:data-clipboard-text="clipboardText"
|
||||
data-clipboard-handle-tooltip="false"
|
||||
:category="category"
|
||||
:size="size"
|
||||
icon="copy-to-clipboard"
|
||||
:aria-label="__('Copy this value')"
|
||||
:variant="variant"
|
||||
:aria-label="localTitle"
|
||||
aria-live="polite"
|
||||
@[$options.CLIPBOARD_SUCCESS_EVENT]="updateTooltip($options.i18n.copied)"
|
||||
@[$options.CLIPBOARD_ERROR_EVENT]="updateTooltip($options.i18n.error)"
|
||||
v-on="$listeners"
|
||||
>
|
||||
<slot></slot>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { GlButton, GlTooltipDirective } from '@gitlab/ui';
|
||||
import Clipboard from 'clipboard';
|
||||
import ClipboardJS from 'clipboard';
|
||||
import { uniqueId } from 'lodash';
|
||||
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
|
||||
|
||||
|
@ -69,7 +69,7 @@ export default {
|
|||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.clipboard = new Clipboard(this.$el, {
|
||||
this.clipboard = new ClipboardJS(this.$el, {
|
||||
container:
|
||||
document.querySelector(`${this.modalDomId} div.modal-content`) ||
|
||||
document.getElementById(this.container) ||
|
||||
|
|
|
@ -50,7 +50,7 @@ module ButtonHelper
|
|||
data: data,
|
||||
type: :button,
|
||||
title: title,
|
||||
aria: { label: title },
|
||||
aria: { label: title, live: 'polite' },
|
||||
itemprop: item_prop
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
%pre
|
||||
:plain
|
||||
curl -X POST \
|
||||
--fail \
|
||||
-F token=TOKEN \
|
||||
-F ref=REF_NAME \
|
||||
#{builds_trigger_url(@project.id)}
|
||||
|
@ -54,7 +55,7 @@
|
|||
%pre
|
||||
:plain
|
||||
script:
|
||||
- "curl -X POST -F token=TOKEN -F ref=REF_NAME #{builds_trigger_url(@project.id)}"
|
||||
- "curl -X POST --fail -F token=TOKEN -F ref=REF_NAME #{builds_trigger_url(@project.id)}"
|
||||
%h5.gl-mt-3
|
||||
= _('Use webhook')
|
||||
|
||||
|
@ -73,6 +74,7 @@
|
|||
%pre
|
||||
:plain
|
||||
curl -X POST \
|
||||
--fail \
|
||||
-F token=TOKEN \
|
||||
-F "ref=REF_NAME" \
|
||||
-F "variables[RUN_NIGHTLY_BUILD]=true" \
|
||||
|
|
|
@ -969,6 +969,8 @@ To view running completed and scheduled on-demand DAST scans for a project, go t
|
|||
failed, or was canceled.
|
||||
- To view scheduled scans, select **Scheduled**. It shows on-demand scans that have a schedule
|
||||
set up. Those are _not_ included in the **All** tab.
|
||||
- To view saved on-demand scan profiles, select **Scan library**.
|
||||
Those are _not_ included in the **All** tab.
|
||||
|
||||
#### Cancel an on-demand scan
|
||||
|
||||
|
|
|
@ -9673,6 +9673,9 @@ msgstr ""
|
|||
msgid "Copy evidence SHA"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy failed. Please manually copy the value."
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy file contents"
|
||||
msgstr ""
|
||||
|
||||
|
@ -9712,9 +9715,6 @@ msgstr ""
|
|||
msgid "Copy this registration token."
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy this value"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy to clipboard"
|
||||
msgstr ""
|
||||
|
||||
|
@ -24588,6 +24588,9 @@ msgstr ""
|
|||
msgid "OnDemandScans|Save scan"
|
||||
msgstr ""
|
||||
|
||||
msgid "OnDemandScans|Scan library"
|
||||
msgstr ""
|
||||
|
||||
msgid "OnDemandScans|Scan name"
|
||||
msgstr ""
|
||||
|
||||
|
@ -24624,6 +24627,9 @@ msgstr ""
|
|||
msgid "OnDemandScans|There are no running scans."
|
||||
msgstr ""
|
||||
|
||||
msgid "OnDemandScans|There are no saved scans."
|
||||
msgstr ""
|
||||
|
||||
msgid "OnDemandScans|There are no scheduled scans."
|
||||
msgstr ""
|
||||
|
||||
|
@ -26665,9 +26671,6 @@ msgstr ""
|
|||
msgid "Preferences|Use relative times"
|
||||
msgstr ""
|
||||
|
||||
msgid "Press %{key}-C to copy"
|
||||
msgstr ""
|
||||
|
||||
msgid "Prev"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@
|
|||
"bootstrap": "4.5.3",
|
||||
"cache-loader": "^4.1.0",
|
||||
"canvas-confetti": "^1.4.0",
|
||||
"clipboard": "^1.7.1",
|
||||
"clipboard": "^2.0.8",
|
||||
"codemirror": "^5.48.4",
|
||||
"codesandbox-api": "0.0.23",
|
||||
"compression-webpack-plugin": "^5.0.2",
|
||||
|
|
|
@ -0,0 +1,187 @@
|
|||
import initCopyToClipboard, {
|
||||
CLIPBOARD_SUCCESS_EVENT,
|
||||
CLIPBOARD_ERROR_EVENT,
|
||||
I18N_ERROR_MESSAGE,
|
||||
} from '~/behaviors/copy_to_clipboard';
|
||||
import { show, hide, fixTitle, once } from '~/tooltips';
|
||||
|
||||
let onceCallback = () => {};
|
||||
jest.mock('~/tooltips', () => ({
|
||||
show: jest.fn(),
|
||||
hide: jest.fn(),
|
||||
fixTitle: jest.fn(),
|
||||
once: jest.fn((event, callback) => {
|
||||
onceCallback = callback;
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('initCopyToClipboard', () => {
|
||||
let clearSelection;
|
||||
let focusSpy;
|
||||
let dispatchEventSpy;
|
||||
let button;
|
||||
let clipboardInstance;
|
||||
|
||||
afterEach(() => {
|
||||
document.body.innerHTML = '';
|
||||
clipboardInstance = null;
|
||||
});
|
||||
|
||||
const title = 'Copy this value';
|
||||
const defaultButtonAttributes = {
|
||||
'data-clipboard-text': 'foo bar',
|
||||
title,
|
||||
'data-title': title,
|
||||
};
|
||||
const createButton = (attributes = {}) => {
|
||||
const combinedAttributes = { ...defaultButtonAttributes, ...attributes };
|
||||
button = document.createElement('button');
|
||||
Object.keys(combinedAttributes).forEach((attributeName) => {
|
||||
button.setAttribute(attributeName, combinedAttributes[attributeName]);
|
||||
});
|
||||
document.body.appendChild(button);
|
||||
};
|
||||
|
||||
const init = () => {
|
||||
clipboardInstance = initCopyToClipboard();
|
||||
};
|
||||
|
||||
const setupSpies = () => {
|
||||
clearSelection = jest.fn();
|
||||
focusSpy = jest.spyOn(button, 'focus');
|
||||
dispatchEventSpy = jest.spyOn(button, 'dispatchEvent');
|
||||
};
|
||||
|
||||
const emitSuccessEvent = () => {
|
||||
clipboardInstance.emit('success', {
|
||||
action: 'copy',
|
||||
text: 'foo bar',
|
||||
trigger: button,
|
||||
clearSelection,
|
||||
});
|
||||
};
|
||||
|
||||
const emitErrorEvent = () => {
|
||||
clipboardInstance.emit('error', {
|
||||
action: 'copy',
|
||||
text: 'foo bar',
|
||||
trigger: button,
|
||||
clearSelection,
|
||||
});
|
||||
};
|
||||
|
||||
const itHandlesTooltip = (expectedTooltip) => {
|
||||
it('handles tooltip', () => {
|
||||
expect(button.getAttribute('title')).toBe(expectedTooltip);
|
||||
expect(button.getAttribute('aria-label')).toBe(expectedTooltip);
|
||||
expect(fixTitle).toHaveBeenCalledWith(button);
|
||||
expect(show).toHaveBeenCalledWith(button);
|
||||
expect(once).toHaveBeenCalledWith('hidden', expect.any(Function));
|
||||
|
||||
expect(hide).not.toHaveBeenCalled();
|
||||
jest.runAllTimers();
|
||||
expect(hide).toHaveBeenCalled();
|
||||
|
||||
onceCallback({ target: button });
|
||||
expect(button.getAttribute('title')).toBe(title);
|
||||
expect(button.getAttribute('aria-label')).toBe(title);
|
||||
expect(fixTitle).toHaveBeenCalledWith(button);
|
||||
});
|
||||
};
|
||||
|
||||
describe('when value is successfully copied', () => {
|
||||
it(`calls clearSelection, focuses the button, and dispatches ${CLIPBOARD_SUCCESS_EVENT} event`, () => {
|
||||
createButton();
|
||||
init();
|
||||
setupSpies();
|
||||
emitSuccessEvent();
|
||||
|
||||
expect(clearSelection).toHaveBeenCalled();
|
||||
expect(focusSpy).toHaveBeenCalled();
|
||||
expect(dispatchEventSpy).toHaveBeenCalledWith(new Event(CLIPBOARD_SUCCESS_EVENT));
|
||||
});
|
||||
|
||||
describe('when `data-clipboard-handle-tooltip` is set to `false`', () => {
|
||||
beforeEach(() => {
|
||||
createButton({
|
||||
'data-clipboard-handle-tooltip': 'false',
|
||||
});
|
||||
init();
|
||||
emitSuccessEvent();
|
||||
});
|
||||
|
||||
it('does not handle success tooltip', () => {
|
||||
expect(show).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when `data-clipboard-handle-tooltip` is set to `true`', () => {
|
||||
beforeEach(() => {
|
||||
createButton({
|
||||
'data-clipboard-handle-tooltip': 'true',
|
||||
});
|
||||
init();
|
||||
emitSuccessEvent();
|
||||
});
|
||||
|
||||
itHandlesTooltip('Copied');
|
||||
});
|
||||
|
||||
describe('when `data-clipboard-handle-tooltip` is not set', () => {
|
||||
beforeEach(() => {
|
||||
createButton();
|
||||
init();
|
||||
emitSuccessEvent();
|
||||
});
|
||||
|
||||
itHandlesTooltip('Copied');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when there is an error copying the value', () => {
|
||||
it(`dispatches ${CLIPBOARD_ERROR_EVENT} event`, () => {
|
||||
createButton();
|
||||
init();
|
||||
setupSpies();
|
||||
emitErrorEvent();
|
||||
|
||||
expect(dispatchEventSpy).toHaveBeenCalledWith(new Event(CLIPBOARD_ERROR_EVENT));
|
||||
});
|
||||
|
||||
describe('when `data-clipboard-handle-tooltip` is set to `false`', () => {
|
||||
beforeEach(() => {
|
||||
createButton({
|
||||
'data-clipboard-handle-tooltip': 'false',
|
||||
});
|
||||
init();
|
||||
emitErrorEvent();
|
||||
});
|
||||
|
||||
it('does not handle error tooltip', () => {
|
||||
expect(show).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when `data-clipboard-handle-tooltip` is set to `true`', () => {
|
||||
beforeEach(() => {
|
||||
createButton({
|
||||
'data-clipboard-handle-tooltip': 'true',
|
||||
});
|
||||
init();
|
||||
emitErrorEvent();
|
||||
});
|
||||
|
||||
itHandlesTooltip(I18N_ERROR_MESSAGE);
|
||||
});
|
||||
|
||||
describe('when `data-clipboard-handle-tooltip` is not set', () => {
|
||||
beforeEach(() => {
|
||||
createButton();
|
||||
init();
|
||||
emitErrorEvent();
|
||||
});
|
||||
|
||||
itHandlesTooltip(I18N_ERROR_MESSAGE);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -15,11 +15,14 @@ exports[`FileSha renders 1`] = `
|
|||
foo
|
||||
|
||||
<gl-button-stub
|
||||
aria-label="Copy this value"
|
||||
aria-label="Copy SHA"
|
||||
aria-live="polite"
|
||||
buttontextclasses=""
|
||||
category="tertiary"
|
||||
data-clipboard-handle-tooltip="false"
|
||||
data-clipboard-text="foo"
|
||||
icon="copy-to-clipboard"
|
||||
id="clipboard-button-1"
|
||||
size="small"
|
||||
title="Copy SHA"
|
||||
variant="default"
|
||||
|
|
|
@ -4,6 +4,8 @@ import FileSha from '~/packages_and_registries/infrastructure_registry/details/c
|
|||
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
||||
import DetailsRow from '~/vue_shared/components/registry/details_row.vue';
|
||||
|
||||
jest.mock('lodash/uniqueId', () => (prefix) => (prefix ? `${prefix}1` : 1));
|
||||
|
||||
describe('FileSha', () => {
|
||||
let wrapper;
|
||||
|
||||
|
|
|
@ -15,11 +15,14 @@ exports[`FileSha renders 1`] = `
|
|||
foo
|
||||
|
||||
<gl-button-stub
|
||||
aria-label="Copy this value"
|
||||
aria-label="Copy SHA"
|
||||
aria-live="polite"
|
||||
buttontextclasses=""
|
||||
category="tertiary"
|
||||
data-clipboard-handle-tooltip="false"
|
||||
data-clipboard-text="foo"
|
||||
icon="copy-to-clipboard"
|
||||
id="clipboard-button-1"
|
||||
size="small"
|
||||
title="Copy SHA"
|
||||
variant="default"
|
||||
|
|
|
@ -4,6 +4,8 @@ import FileSha from '~/packages_and_registries/package_registry/components/detai
|
|||
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
||||
import DetailsRow from '~/vue_shared/components/registry/details_row.vue';
|
||||
|
||||
jest.mock('lodash/uniqueId', () => (prefix) => (prefix ? `${prefix}1` : 1));
|
||||
|
||||
describe('FileSha', () => {
|
||||
let wrapper;
|
||||
|
||||
|
|
|
@ -1,8 +1,16 @@
|
|||
import { GlButton } from '@gitlab/ui';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import initCopyToClipboard from '~/behaviors/copy_to_clipboard';
|
||||
import { nextTick } from 'vue';
|
||||
|
||||
import initCopyToClipboard, {
|
||||
CLIPBOARD_SUCCESS_EVENT,
|
||||
CLIPBOARD_ERROR_EVENT,
|
||||
I18N_ERROR_MESSAGE,
|
||||
} from '~/behaviors/copy_to_clipboard';
|
||||
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
||||
|
||||
jest.mock('lodash/uniqueId', () => (prefix) => (prefix ? `${prefix}1` : 1));
|
||||
|
||||
describe('clipboard button', () => {
|
||||
let wrapper;
|
||||
|
||||
|
@ -15,6 +23,42 @@ describe('clipboard button', () => {
|
|||
|
||||
const findButton = () => wrapper.find(GlButton);
|
||||
|
||||
const expectConfirmationTooltip = async ({ event, message }) => {
|
||||
const title = 'Copy this value';
|
||||
|
||||
createWrapper({
|
||||
text: 'copy me',
|
||||
title,
|
||||
});
|
||||
|
||||
wrapper.vm.$root.$emit = jest.fn();
|
||||
|
||||
const button = findButton();
|
||||
|
||||
expect(button.attributes()).toMatchObject({
|
||||
title,
|
||||
'aria-label': title,
|
||||
});
|
||||
|
||||
await button.trigger(event);
|
||||
|
||||
expect(wrapper.vm.$root.$emit).toHaveBeenCalledWith('bv::show::tooltip', 'clipboard-button-1');
|
||||
|
||||
expect(button.attributes()).toMatchObject({
|
||||
title: message,
|
||||
'aria-label': message,
|
||||
});
|
||||
|
||||
jest.runAllTimers();
|
||||
await nextTick();
|
||||
|
||||
expect(button.attributes()).toMatchObject({
|
||||
title,
|
||||
'aria-label': title,
|
||||
});
|
||||
expect(wrapper.vm.$root.$emit).toHaveBeenCalledWith('bv::hide::tooltip', 'clipboard-button-1');
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
wrapper = null;
|
||||
|
@ -99,6 +143,32 @@ describe('clipboard button', () => {
|
|||
expect(findButton().props('variant')).toBe(variant);
|
||||
});
|
||||
|
||||
describe('confirmation tooltip', () => {
|
||||
it('adds `id` and `data-clipboard-handle-tooltip` attributes to button', () => {
|
||||
createWrapper({
|
||||
text: 'copy me',
|
||||
title: 'Copy this value',
|
||||
});
|
||||
|
||||
expect(findButton().attributes()).toMatchObject({
|
||||
id: 'clipboard-button-1',
|
||||
'data-clipboard-handle-tooltip': 'false',
|
||||
'aria-live': 'polite',
|
||||
});
|
||||
});
|
||||
|
||||
it('shows success tooltip after successful copy', () => {
|
||||
expectConfirmationTooltip({
|
||||
event: CLIPBOARD_SUCCESS_EVENT,
|
||||
message: ClipboardButton.i18n.copied,
|
||||
});
|
||||
});
|
||||
|
||||
it('shows error tooltip after failed copy', () => {
|
||||
expectConfirmationTooltip({ event: CLIPBOARD_ERROR_EVENT, message: I18N_ERROR_MESSAGE });
|
||||
});
|
||||
});
|
||||
|
||||
describe('integration', () => {
|
||||
it('actually copies to clipboard', () => {
|
||||
initCopyToClipboard();
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
exports[`Package code instruction multiline to match the snapshot 1`] = `
|
||||
<div>
|
||||
<label
|
||||
for="instruction-input_3"
|
||||
for="instruction-input_1"
|
||||
>
|
||||
foo_label
|
||||
</label>
|
||||
|
@ -23,7 +23,7 @@ multiline text
|
|||
exports[`Package code instruction single line to match the default snapshot 1`] = `
|
||||
<div>
|
||||
<label
|
||||
for="instruction-input_2"
|
||||
for="instruction-input_1"
|
||||
>
|
||||
foo_label
|
||||
</label>
|
||||
|
@ -37,7 +37,7 @@ exports[`Package code instruction single line to match the default snapshot 1`]
|
|||
<input
|
||||
class="form-control gl-font-monospace"
|
||||
data-testid="instruction-input"
|
||||
id="instruction-input_2"
|
||||
id="instruction-input_1"
|
||||
readonly="readonly"
|
||||
type="text"
|
||||
/>
|
||||
|
@ -47,9 +47,12 @@ exports[`Package code instruction single line to match the default snapshot 1`]
|
|||
data-testid="instruction-button"
|
||||
>
|
||||
<button
|
||||
aria-label="Copy this value"
|
||||
aria-label="Copy npm install command"
|
||||
aria-live="polite"
|
||||
class="btn input-group-text btn-default btn-md gl-button btn-default-secondary btn-icon"
|
||||
data-clipboard-handle-tooltip="false"
|
||||
data-clipboard-text="npm i @my-package"
|
||||
id="clipboard-button-1"
|
||||
title="Copy npm install command"
|
||||
type="button"
|
||||
>
|
||||
|
|
|
@ -3,6 +3,8 @@ import Tracking from '~/tracking';
|
|||
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
||||
import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue';
|
||||
|
||||
jest.mock('lodash/uniqueId', () => (prefix) => (prefix ? `${prefix}1` : 1));
|
||||
|
||||
describe('Package code instruction', () => {
|
||||
let wrapper;
|
||||
|
||||
|
|
|
@ -167,6 +167,7 @@ RSpec.describe ButtonHelper do
|
|||
expect(element.attr('class')).to eq('btn btn-clipboard btn-transparent')
|
||||
expect(element.attr('type')).to eq('button')
|
||||
expect(element.attr('aria-label')).to eq('Copy')
|
||||
expect(element.attr('aria-live')).to eq('polite')
|
||||
expect(element.attr('data-toggle')).to eq('tooltip')
|
||||
expect(element.attr('data-placement')).to eq('bottom')
|
||||
expect(element.attr('data-container')).to eq('body')
|
||||
|
|
17
yarn.lock
17
yarn.lock
|
@ -3435,19 +3435,10 @@ cli-boxes@^2.2.0:
|
|||
resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.0.tgz#538ecae8f9c6ca508e3c3c95b453fe93cb4c168d"
|
||||
integrity sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==
|
||||
|
||||
clipboard@^1.7.1:
|
||||
version "1.7.1"
|
||||
resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-1.7.1.tgz#360d6d6946e99a7a1fef395e42ba92b5e9b5a16b"
|
||||
integrity sha1-Ng1taUbpmnof7zleQrqStem1oWs=
|
||||
dependencies:
|
||||
good-listener "^1.2.2"
|
||||
select "^1.1.2"
|
||||
tiny-emitter "^2.0.0"
|
||||
|
||||
clipboard@^2.0.0:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.6.tgz#52921296eec0fdf77ead1749421b21c968647376"
|
||||
integrity sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==
|
||||
clipboard@^2.0.0, clipboard@^2.0.8:
|
||||
version "2.0.8"
|
||||
resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.8.tgz#ffc6c103dd2967a83005f3f61976aa4655a4cdba"
|
||||
integrity sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ==
|
||||
dependencies:
|
||||
good-listener "^1.2.2"
|
||||
select "^1.1.2"
|
||||
|
|
Loading…
Reference in New Issue