Commit 1c0a9832 authored by Bob Van Landuyt's avatar Bob Van Landuyt

Merge branch 'ph/repoButtonsReactive' into 'master'

Refactor tree controls into Vue

Closes #34794

See merge request gitlab-org/gitlab!19065
parents 5328ae9b ffe1ee15
<script>
import { GlLink } from '@gitlab/ui';
export default {
components: {
GlLink,
},
props: {
currentPath: {
type: String,
required: false,
default: null,
},
links: {
type: Array,
required: true,
},
},
computed: {
normalizedLinks() {
return this.links.map(link => ({
text: link.text,
path: `${link.path}?path=${this.currentPath}`,
}));
},
},
};
</script>
<template>
<section class="border-top pt-1 mt-1">
<h5 class="m-0 dropdown-bold-header">{{ __('Download this directory') }}</h5>
<div class="dropdown-menu-content">
<div class="btn-group ml-0 w-100">
<gl-link
v-for="(link, index) in normalizedLinks"
:key="index"
:href="link.path"
:class="{ 'btn-primary': index === 0 }"
class="btn btn-xs"
>
{{ link.text }}
</gl-link>
</div>
</div>
</section>
</template>
<script>
import { GlLink } from '@gitlab/ui';
export default {
components: {
GlLink,
},
props: {
path: {
type: String,
required: true,
},
text: {
type: String,
required: true,
},
cssClass: {
type: String,
required: false,
default: null,
},
},
};
</script>
<template>
<gl-link :href="path" :class="cssClass" class="btn">{{ text }}</gl-link>
</template>
......@@ -3,9 +3,13 @@ import createRouter from './router';
import App from './components/app.vue';
import Breadcrumbs from './components/breadcrumbs.vue';
import LastCommit from './components/last_commit.vue';
import TreeActionLink from './components/tree_action_link.vue';
import DirectoryDownloadLinks from './components/directory_download_links.vue';
import apolloProvider from './graphql';
import { setTitle } from './utils/title';
import { parseBoolean } from '../lib/utils/common_utils';
import { webIDEUrl } from '../lib/utils/url_utility';
import { __ } from '../locale';
export default function setupVueRepositoryList() {
const el = document.getElementById('js-tree-list');
......@@ -91,6 +95,66 @@ export default function setupVueRepositoryList() {
},
});
const treeHistoryLinkEl = document.getElementById('js-tree-history-link');
const { historyLink } = treeHistoryLinkEl.dataset;
// eslint-disable-next-line no-new
new Vue({
el: treeHistoryLinkEl,
router,
render(h) {
return h(TreeActionLink, {
props: {
path: historyLink + (this.$route.params.pathMatch || '/'),
text: __('History'),
},
});
},
});
const webIdeLinkEl = document.getElementById('js-tree-web-ide-link');
if (webIdeLinkEl) {
// eslint-disable-next-line no-new
new Vue({
el: webIdeLinkEl,
router,
render(h) {
return h(TreeActionLink, {
props: {
path: webIDEUrl(`/${projectPath}/edit/${ref}/-${this.$route.params.pathMatch || '/'}`),
text: __('Web IDE'),
cssClass: 'qa-web-ide-button',
},
});
},
});
}
const directoryDownloadLinks = document.getElementById('js-directory-downloads');
if (directoryDownloadLinks) {
// eslint-disable-next-line no-new
new Vue({
el: directoryDownloadLinks,
router,
render(h) {
const currentPath = this.$route.params.pathMatch || '/';
if (currentPath !== '/') {
return h(DirectoryDownloadLinks, {
props: {
currentPath: currentPath.replace(/^\//, ''),
links: JSON.parse(directoryDownloadLinks.dataset.links),
},
});
}
return null;
},
});
}
// eslint-disable-next-line no-new
new Vue({
el,
......
......@@ -195,6 +195,17 @@ module TreeHelper
full_name: project.name_with_namespace
}
end
def directory_download_links(project, ref, archive_prefix)
formats = ['zip', 'tar.gz', 'tar.bz2', 'tar']
formats.map do |fmt|
{
text: fmt,
path: project_archive_path(project, id: tree_join(ref, archive_prefix), format: fmt)
}
end
end
end
TreeHelper.prepend_if_ee('::EE::TreeHelper')
......@@ -12,11 +12,14 @@
%h5.m-0.dropdown-bold-header= _('Download source code')
.dropdown-menu-content
= render 'projects/buttons/download_links', project: project, ref: ref, archive_prefix: archive_prefix, path: nil
- if directory? && Feature.enabled?(:git_archive_path, default_enabled: true)
%section.border-top.pt-1.mt-1
%h5.m-0.dropdown-bold-header= _('Download this directory')
.dropdown-menu-content
= render 'projects/buttons/download_links', project: project, ref: ref, archive_prefix: archive_prefix, path: @path
- if Feature.enabled?(:git_archive_path, default_enabled: true)
- if vue_file_list_enabled?
#js-directory-downloads{ data: { links: directory_download_links(project, ref, archive_prefix).to_json } }
- elsif directory?
%section.border-top.pt-1.mt-1
%h5.m-0.dropdown-bold-header= _('Download this directory')
.dropdown-menu-content
= render 'projects/buttons/download_links', project: project, ref: ref, archive_prefix: archive_prefix, path: @path
- if pipeline && pipeline.latest_builds_with_artifacts.any?
%section.border-top.pt-1.mt-1
%h5.m-0.dropdown-bold-header= _('Download artifacts')
......
......@@ -77,15 +77,21 @@
.tree-controls
= render_if_exists 'projects/tree/lock_link'
= link_to s_('Commits|History'), project_commits_path(@project, @id), class: 'btn'
- if vue_file_list_enabled?
#js-tree-history-link.d-inline-block{ data: { history_link: project_commits_path(@project, @ref) } }
- else
= link_to s_('Commits|History'), project_commits_path(@project, @id), class: 'btn'
= render 'projects/find_file_link'
- if can_create_mr_from_fork
= succeed " " do
- if can_collaborate || current_user&.already_forked?(@project)
= link_to ide_edit_path(@project, @ref, @path), class: 'btn btn-default qa-web-ide-button' do
= _('Web IDE')
- if vue_file_list_enabled?
#js-tree-web-ide-link.d-inline-block
- else
= link_to ide_edit_path(@project, @ref, @path), class: 'btn btn-default qa-web-ide-button' do
= _('Web IDE')
- else
= link_to '#modal-confirm-fork', class: 'btn btn-default qa-web-ide-button', data: { target: '#modal-confirm-fork', toggle: 'modal'} do
= _('Web IDE')
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Repository directory download links component renders downloads links for path app 1`] = `
<section
class="border-top pt-1 mt-1"
>
<h5
class="m-0 dropdown-bold-header"
>
Download this directory
</h5>
<div
class="dropdown-menu-content"
>
<div
class="btn-group ml-0 w-100"
>
<gllink-stub
class="btn btn-xs btn-primary"
href="http://test.com/?path=app"
>
zip
</gllink-stub>
<gllink-stub
class="btn btn-xs"
href="http://test.com/?path=app"
>
tar
</gllink-stub>
</div>
</div>
</section>
`;
exports[`Repository directory download links component renders downloads links for path app/assets 1`] = `
<section
class="border-top pt-1 mt-1"
>
<h5
class="m-0 dropdown-bold-header"
>
Download this directory
</h5>
<div
class="dropdown-menu-content"
>
<div
class="btn-group ml-0 w-100"
>
<gllink-stub
class="btn btn-xs btn-primary"
href="http://test.com/?path=app/assets"
>
zip
</gllink-stub>
<gllink-stub
class="btn btn-xs"
href="http://test.com/?path=app/assets"
>
tar
</gllink-stub>
</div>
</div>
</section>
`;
import { shallowMount } from '@vue/test-utils';
import DirectoryDownloadLinks from '~/repository/components/directory_download_links.vue';
let vm;
function factory(currentPath) {
vm = shallowMount(DirectoryDownloadLinks, {
propsData: {
currentPath,
links: [{ text: 'zip', path: 'http://test.com/' }, { text: 'tar', path: 'http://test.com/' }],
},
});
}
describe('Repository directory download links component', () => {
afterEach(() => {
vm.destroy();
});
it.each`
path
${'app'}
${'app/assets'}
`('renders downloads links for path $path', ({ path }) => {
factory(path);
expect(vm.element).toMatchSnapshot();
});
});
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