Commit b290f2d2 authored by Paul Slaughter's avatar Paul Slaughter Committed by Enrique Alcantara

Use embed_dropdown for snippets

- Also removes old blob_embeddable since it
isn't used anymore
- Also adds a temporary gl-dropdown-text-py-0
utility class which we can remove when some
upstream components have been updated
parent 977db6a9
<script>
import { GlFormInputGroup, GlDeprecatedButton, GlIcon } from '@gitlab/ui';
import { __ } from '~/locale';
export default {
components: {
GlFormInputGroup,
GlDeprecatedButton,
GlIcon,
},
props: {
url: {
type: String,
required: true,
},
},
data() {
return {
optionValues: [
// eslint-disable-next-line no-useless-escape
{ name: __('Embed'), value: `<script src='${this.url}.js'><\/script>` },
{ name: __('Share'), value: this.url },
],
};
},
};
</script>
<template>
<gl-form-input-group
id="embeddable-text"
:predefined-options="optionValues"
readonly
select-on-click
>
<template #append>
<gl-deprecated-button new-style data-clipboard-target="#embeddable-text">
<gl-icon name="copy-to-clipboard" :title="__('Copy')" />
</gl-deprecated-button>
</template>
</gl-form-input-group>
</template>
<script>
import { escape as esc } from 'lodash';
import {
GlButton,
GlDropdown,
GlDropdownHeader,
GlDropdownText,
GlFormInputGroup,
GlTooltipDirective,
} from '@gitlab/ui';
import { __ } from '~/locale';
const MSG_EMBED = __('Embed');
const MSG_SHARE = __('Share');
const MSG_COPY = __('Copy');
export default {
components: {
GlButton,
GlDropdown,
GlDropdownHeader,
GlDropdownText,
GlFormInputGroup,
},
directives: {
GlTooltip: GlTooltipDirective,
},
props: {
url: {
type: String,
required: true,
},
},
computed: {
sections() {
return [
// eslint-disable-next-line no-useless-escape
{ name: MSG_EMBED, value: `<script src="${esc(this.url)}.js"><\/script>` },
{ name: MSG_SHARE, value: this.url },
];
},
},
MSG_EMBED,
MSG_COPY,
};
</script>
<template>
<gl-dropdown right :text="$options.MSG_EMBED" menu-class="gl-px-1! gl-pb-5!">
<template v-for="{ name, value } in sections">
<gl-dropdown-header :key="`header_${name}`" data-testid="header">{{
name
}}</gl-dropdown-header>
<gl-dropdown-text
:key="`input_${name}`"
tag="div"
class="gl-dropdown-text-py-0"
data-testid="input"
>
<gl-form-input-group :value="value" readonly select-on-click>
<template #append>
<gl-button
v-gl-tooltip.hover
:title="$options.MSG_COPY"
:data-clipboard-text="value"
icon="copy-to-clipboard"
/>
</template>
</gl-form-input-group>
</gl-dropdown-text>
</template>
</gl-dropdown>
</template>
<script>
import { GlLoadingIcon } from '@gitlab/ui';
import BlobEmbeddable from '~/blob/components/blob_embeddable.vue';
import EmbedDropdown from './embed_dropdown.vue';
import SnippetHeader from './snippet_header.vue';
import SnippetTitle from './snippet_title.vue';
import SnippetBlob from './snippet_blob_view.vue';
......@@ -13,7 +13,7 @@ import { SNIPPET_MARK_VIEW_APP_START } from '~/performance_constants';
export default {
components: {
BlobEmbeddable,
EmbedDropdown,
SnippetHeader,
SnippetTitle,
GlLoadingIcon,
......@@ -46,7 +46,7 @@ export default {
<snippet-header :snippet="snippet" />
<snippet-title :snippet="snippet" />
<div class="gl-display-flex gl-justify-content-end gl-mb-5">
<blob-embeddable v-if="embeddable" class="gl-flex-fill-1" :url="snippet.webUrl" />
<embed-dropdown v-if="embeddable" :url="snippet.webUrl" />
<clone-dropdown-button
v-if="canBeCloned"
class="gl-ml-3"
......
......@@ -1104,3 +1104,12 @@ header.header-content .dropdown-menu.frequent-items-dropdown-menu {
}
}
}
// This class won't be needed once we can directly add utility classes to the child
// https://github.com/bootstrap-vue/bootstrap-vue/issues/5669
.gl-dropdown-text-py-0 {
.b-dropdown-text {
padding-top: 0;
padding-bottom: 0;
}
}
---
title: Use dropdown for embed in snippets
merge_request: 39885
author:
type: changed
import { shallowMount } from '@vue/test-utils';
import { GlFormInputGroup } from '@gitlab/ui';
import BlobEmbeddable from '~/blob/components/blob_embeddable.vue';
describe('Blob Embeddable', () => {
let wrapper;
const url = 'https://foo.bar';
function createComponent() {
wrapper = shallowMount(BlobEmbeddable, {
propsData: {
url,
},
});
}
beforeEach(() => {
createComponent();
});
afterEach(() => {
wrapper.destroy();
});
it('renders gl-form-input-group component', () => {
expect(wrapper.find(GlFormInputGroup).exists()).toBe(true);
});
it('makes up optionValues based on the url prop', () => {
expect(wrapper.vm.optionValues).toEqual([
{ name: 'Embed', value: expect.stringContaining(`${url}.js`) },
{ name: 'Share', value: url },
]);
});
});
import { escape as esc } from 'lodash';
import { mount } from '@vue/test-utils';
import { GlFormInputGroup } from '@gitlab/ui';
import { TEST_HOST } from 'helpers/test_constants';
import EmbedDropdown from '~/snippets/components/embed_dropdown.vue';
const TEST_URL = `${TEST_HOST}/test/no">'xss`;
describe('snippets/components/embed_dropdown', () => {
let wrapper;
const createComponent = () => {
wrapper = mount(EmbedDropdown, {
propsData: {
url: TEST_URL,
},
});
};
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
const findSectionsData = () => {
const sections = [];
let current = {};
wrapper.findAll('[data-testid="header"],[data-testid="input"]').wrappers.forEach(x => {
const type = x.attributes('data-testid');
if (type === 'header') {
current = {
header: x.text(),
};
sections.push(current);
} else {
const value = x.find(GlFormInputGroup).props('value');
const copyValue = x.find('button[title="Copy"]').attributes('data-clipboard-text');
Object.assign(current, {
value,
copyValue,
});
}
});
return sections;
};
it('renders dropdown items', () => {
createComponent();
const embedValue = `<script src="${esc(TEST_URL)}.js"></script>`;
expect(findSectionsData()).toEqual([
{
header: 'Embed',
value: embedValue,
copyValue: embedValue,
},
{
header: 'Share',
value: TEST_URL,
copyValue: TEST_URL,
},
]);
});
});
......@@ -2,7 +2,7 @@ import { GlLoadingIcon } from '@gitlab/ui';
import { Blob, BinaryBlob } from 'jest/blob/components/mock_data';
import { shallowMount } from '@vue/test-utils';
import SnippetApp from '~/snippets/components/show.vue';
import BlobEmbeddable from '~/blob/components/blob_embeddable.vue';
import EmbedDropdown from '~/snippets/components/embed_dropdown.vue';
import SnippetHeader from '~/snippets/components/snippet_header.vue';
import SnippetTitle from '~/snippets/components/snippet_title.vue';
import SnippetBlob from '~/snippets/components/snippet_blob_view.vue';
......@@ -57,7 +57,7 @@ describe('Snippet view app', () => {
expect(wrapper.find(SnippetTitle).exists()).toBe(true);
});
it('renders embeddable component if visibility allows', () => {
it('renders embed dropdown component if visibility allows', () => {
createComponent({
data: {
snippet: {
......@@ -66,7 +66,7 @@ describe('Snippet view app', () => {
},
},
});
expect(wrapper.contains(BlobEmbeddable)).toBe(true);
expect(wrapper.contains(EmbedDropdown)).toBe(true);
});
it('renders correct snippet-blob components', () => {
......@@ -88,7 +88,7 @@ describe('Snippet view app', () => {
${SNIPPET_VISIBILITY_PRIVATE} | ${'not render'} | ${false}
${'foo'} | ${'not render'} | ${false}
${SNIPPET_VISIBILITY_PUBLIC} | ${'render'} | ${true}
`('does $condition blob-embeddable by default', ({ visibilityLevel, isRendered }) => {
`('does $condition embed-dropdown by default', ({ visibilityLevel, isRendered }) => {
createComponent({
data: {
snippet: {
......@@ -97,7 +97,7 @@ describe('Snippet view app', () => {
},
},
});
expect(wrapper.contains(BlobEmbeddable)).toBe(isRendered);
expect(wrapper.contains(EmbedDropdown)).toBe(isRendered);
});
});
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment