Commit 1286210d authored by Denys Mishunov's avatar Denys Mishunov Committed by Phil Hughes

Move clone button out of blob header

Since cloning is snippet-wide operation, the button should be
 moved out to the global scope of the snippet
parent a8c3cc80
...@@ -3,6 +3,7 @@ import BlobEmbeddable from '~/blob/components/blob_embeddable.vue'; ...@@ -3,6 +3,7 @@ import BlobEmbeddable from '~/blob/components/blob_embeddable.vue';
import SnippetHeader from './snippet_header.vue'; import SnippetHeader from './snippet_header.vue';
import SnippetTitle from './snippet_title.vue'; import SnippetTitle from './snippet_title.vue';
import SnippetBlob from './snippet_blob_view.vue'; import SnippetBlob from './snippet_blob_view.vue';
import CloneDropdownButton from '~/vue_shared/components/clone_dropdown.vue';
import { GlLoadingIcon } from '@gitlab/ui'; import { GlLoadingIcon } from '@gitlab/ui';
import { getSnippetMixin } from '../mixins/snippets'; import { getSnippetMixin } from '../mixins/snippets';
...@@ -15,12 +16,16 @@ export default { ...@@ -15,12 +16,16 @@ export default {
SnippetTitle, SnippetTitle,
GlLoadingIcon, GlLoadingIcon,
SnippetBlob, SnippetBlob,
CloneDropdownButton,
}, },
mixins: [getSnippetMixin], mixins: [getSnippetMixin],
computed: { computed: {
embeddable() { embeddable() {
return this.snippet.visibilityLevel === SNIPPET_VISIBILITY_PUBLIC; return this.snippet.visibilityLevel === SNIPPET_VISIBILITY_PUBLIC;
}, },
canBeCloned() {
return Boolean(this.snippet.sshUrlToRepo || this.snippet.httpUrlToRepo);
},
}, },
}; };
</script> </script>
...@@ -35,7 +40,16 @@ export default { ...@@ -35,7 +40,16 @@ export default {
<template v-else> <template v-else>
<snippet-header :snippet="snippet" /> <snippet-header :snippet="snippet" />
<snippet-title :snippet="snippet" /> <snippet-title :snippet="snippet" />
<blob-embeddable v-if="embeddable" class="gl-mb-5" :url="snippet.webUrl" /> <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" />
<clone-dropdown-button
v-if="canBeCloned"
class="gl-ml-3"
:ssh-link="snippet.sshUrlToRepo"
:http-link="snippet.httpUrlToRepo"
data-qa-selector="clone_button"
/>
</div>
<div v-for="blob in blobs" :key="blob.path"> <div v-for="blob in blobs" :key="blob.path">
<snippet-blob :snippet="snippet" :blob="blob" /> <snippet-blob :snippet="snippet" :blob="blob" />
</div> </div>
......
<script> <script>
import BlobHeader from '~/blob/components/blob_header.vue'; import BlobHeader from '~/blob/components/blob_header.vue';
import BlobContent from '~/blob/components/blob_content.vue'; import BlobContent from '~/blob/components/blob_content.vue';
import CloneDropdownButton from '~/vue_shared/components/clone_dropdown.vue';
import GetBlobContent from '../queries/snippet.blob.content.query.graphql'; import GetBlobContent from '../queries/snippet.blob.content.query.graphql';
...@@ -16,7 +15,6 @@ export default { ...@@ -16,7 +15,6 @@ export default {
components: { components: {
BlobHeader, BlobHeader,
BlobContent, BlobContent,
CloneDropdownButton,
}, },
apollo: { apollo: {
blobContent: { blobContent: {
...@@ -66,9 +64,6 @@ export default { ...@@ -66,9 +64,6 @@ export default {
const { richViewer, simpleViewer } = this.blob; const { richViewer, simpleViewer } = this.blob;
return this.activeViewerType === RICH_BLOB_VIEWER ? richViewer : simpleViewer; return this.activeViewerType === RICH_BLOB_VIEWER ? richViewer : simpleViewer;
}, },
canBeCloned() {
return this.snippet.sshUrlToRepo || this.snippet.httpUrlToRepo;
},
hasRenderError() { hasRenderError() {
return Boolean(this.viewer.renderError); return Boolean(this.viewer.renderError);
}, },
...@@ -93,17 +88,7 @@ export default { ...@@ -93,17 +88,7 @@ export default {
:active-viewer-type="viewer.type" :active-viewer-type="viewer.type"
:has-render-error="hasRenderError" :has-render-error="hasRenderError"
@viewer-changed="switchViewer" @viewer-changed="switchViewer"
> />
<template #actions>
<clone-dropdown-button
v-if="canBeCloned"
class="gl-mr-3"
:ssh-link="snippet.sshUrlToRepo"
:http-link="snippet.httpUrlToRepo"
data-qa-selector="clone_button"
/>
</template>
</blob-header>
<blob-content <blob-content
:loading="isContentLoading" :loading="isContentLoading"
:content="blobContent" :content="blobContent"
......
---
title: Move clone button out of blob header
merge_request: 37696
author:
type: changed
...@@ -38,7 +38,7 @@ module QA ...@@ -38,7 +38,7 @@ module QA
element :delete_snippet_button element :delete_snippet_button
end end
base.view 'app/assets/javascripts/snippets/components/snippet_blob_view.vue' do base.view 'app/assets/javascripts/snippets/components/show.vue' do
element :clone_button element :clone_button
end end
......
...@@ -3,17 +3,25 @@ import BlobEmbeddable from '~/blob/components/blob_embeddable.vue'; ...@@ -3,17 +3,25 @@ import BlobEmbeddable from '~/blob/components/blob_embeddable.vue';
import SnippetHeader from '~/snippets/components/snippet_header.vue'; import SnippetHeader from '~/snippets/components/snippet_header.vue';
import SnippetTitle from '~/snippets/components/snippet_title.vue'; import SnippetTitle from '~/snippets/components/snippet_title.vue';
import SnippetBlob from '~/snippets/components/snippet_blob_view.vue'; import SnippetBlob from '~/snippets/components/snippet_blob_view.vue';
import CloneDropdownButton from '~/vue_shared/components/clone_dropdown.vue';
import { GlLoadingIcon } from '@gitlab/ui'; import { GlLoadingIcon } from '@gitlab/ui';
import { Blob, BinaryBlob } from 'jest/blob/components/mock_data'; import { Blob, BinaryBlob } from 'jest/blob/components/mock_data';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { SNIPPET_VISIBILITY_PUBLIC } from '~/snippets/constants'; import {
SNIPPET_VISIBILITY_INTERNAL,
SNIPPET_VISIBILITY_PRIVATE,
SNIPPET_VISIBILITY_PUBLIC,
} from '~/snippets/constants';
describe('Snippet view app', () => { describe('Snippet view app', () => {
let wrapper; let wrapper;
const defaultProps = { const defaultProps = {
snippetGid: 'gid://gitlab/PersonalSnippet/42', snippetGid: 'gid://gitlab/PersonalSnippet/42',
}; };
const webUrl = 'http://foo.bar';
const dummyHTTPUrl = webUrl;
const dummySSHUrl = 'ssh://foo.bar';
function createComponent({ props = defaultProps, data = {}, loading = false } = {}) { function createComponent({ props = defaultProps, data = {}, loading = false } = {}) {
const $apollo = { const $apollo = {
...@@ -72,4 +80,47 @@ describe('Snippet view app', () => { ...@@ -72,4 +80,47 @@ describe('Snippet view app', () => {
expect(blobs.at(0).props('blob')).toEqual(Blob); expect(blobs.at(0).props('blob')).toEqual(Blob);
expect(blobs.at(1).props('blob')).toEqual(BinaryBlob); expect(blobs.at(1).props('blob')).toEqual(BinaryBlob);
}); });
describe('Embed dropdown rendering', () => {
it.each`
visibilityLevel | condition | isRendered
${SNIPPET_VISIBILITY_INTERNAL} | ${'not render'} | ${false}
${SNIPPET_VISIBILITY_PRIVATE} | ${'not render'} | ${false}
${'foo'} | ${'not render'} | ${false}
${SNIPPET_VISIBILITY_PUBLIC} | ${'render'} | ${true}
`('does $condition blob-embeddable by default', ({ visibilityLevel, isRendered }) => {
createComponent({
data: {
snippet: {
visibilityLevel,
webUrl,
},
},
});
expect(wrapper.contains(BlobEmbeddable)).toBe(isRendered);
});
});
describe('Clone button rendering', () => {
it.each`
httpUrlToRepo | sshUrlToRepo | shouldRender | isRendered
${null} | ${null} | ${'Should not'} | ${false}
${null} | ${dummySSHUrl} | ${'Should'} | ${true}
${dummyHTTPUrl} | ${null} | ${'Should'} | ${true}
${dummyHTTPUrl} | ${dummySSHUrl} | ${'Should'} | ${true}
`(
'$shouldRender render "Clone" button when `httpUrlToRepo` is $httpUrlToRepo and `sshUrlToRepo` is $sshUrlToRepo',
({ httpUrlToRepo, sshUrlToRepo, isRendered }) => {
createComponent({
data: {
snippet: {
sshUrlToRepo,
httpUrlToRepo,
},
},
});
expect(wrapper.contains(CloneDropdownButton)).toBe(isRendered);
},
);
});
}); });
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import SnippetBlobView from '~/snippets/components/snippet_blob_view.vue'; import SnippetBlobView from '~/snippets/components/snippet_blob_view.vue';
import BlobHeader from '~/blob/components/blob_header.vue'; import BlobHeader from '~/blob/components/blob_header.vue';
import BlobEmbeddable from '~/blob/components/blob_embeddable.vue';
import BlobContent from '~/blob/components/blob_content.vue'; import BlobContent from '~/blob/components/blob_content.vue';
import { import {
BLOB_RENDER_EVENT_LOAD, BLOB_RENDER_EVENT_LOAD,
...@@ -9,11 +8,7 @@ import { ...@@ -9,11 +8,7 @@ import {
BLOB_RENDER_ERRORS, BLOB_RENDER_ERRORS,
} from '~/blob/components/constants'; } from '~/blob/components/constants';
import { RichViewer, SimpleViewer } from '~/vue_shared/components/blob_viewers'; import { RichViewer, SimpleViewer } from '~/vue_shared/components/blob_viewers';
import { import { SNIPPET_VISIBILITY_PUBLIC } from '~/snippets/constants';
SNIPPET_VISIBILITY_PRIVATE,
SNIPPET_VISIBILITY_INTERNAL,
SNIPPET_VISIBILITY_PUBLIC,
} from '~/snippets/constants';
import { Blob as BlobMock, SimpleViewerMock, RichViewerMock } from 'jest/blob/components/mock_data'; import { Blob as BlobMock, SimpleViewerMock, RichViewerMock } from 'jest/blob/components/mock_data';
...@@ -72,18 +67,6 @@ describe('Blob Embeddable', () => { ...@@ -72,18 +67,6 @@ describe('Blob Embeddable', () => {
expect(wrapper.find(BlobContent).exists()).toBe(true); expect(wrapper.find(BlobContent).exists()).toBe(true);
}); });
it.each([SNIPPET_VISIBILITY_INTERNAL, SNIPPET_VISIBILITY_PRIVATE, 'foo'])(
'does not render blob-embeddable by default',
visibilityLevel => {
createComponent({
snippetProps: {
visibilityLevel,
},
});
expect(wrapper.find(BlobEmbeddable).exists()).toBe(false);
},
);
it('sets simple viewer correctly', () => { it('sets simple viewer correctly', () => {
createComponent(); createComponent();
expect(wrapper.find(SimpleViewer).exists()).toBe(true); expect(wrapper.find(SimpleViewer).exists()).toBe(true);
......
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