Setup Vue app for repository file listing
Part of https://gitlab.com/gitlab-org/gitlab-ce/issues/61578
This commit is contained in:
parent
2f613f28ba
commit
404314c619
24 changed files with 184 additions and 4 deletions
|
@ -46,4 +46,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
|
||||
GpgBadges.fetch();
|
||||
leaveByUrl('project');
|
||||
|
||||
if (document.getElementById('js-tree-list')) {
|
||||
import('~/repository')
|
||||
.then(m => m.default())
|
||||
.catch(e => {
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -40,4 +40,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
}
|
||||
|
||||
GpgBadges.fetch();
|
||||
|
||||
if (document.getElementById('js-tree-list')) {
|
||||
import('~/repository')
|
||||
.then(m => m.default())
|
||||
.catch(e => {
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
3
app/assets/javascripts/repository/components/app.vue
Normal file
3
app/assets/javascripts/repository/components/app.vue
Normal file
|
@ -0,0 +1,3 @@
|
|||
<template>
|
||||
<router-view />
|
||||
</template>
|
11
app/assets/javascripts/repository/graphql.js
Normal file
11
app/assets/javascripts/repository/graphql.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
import Vue from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import createDefaultClient from '~/lib/graphql';
|
||||
|
||||
Vue.use(VueApollo);
|
||||
|
||||
const defaultClient = createDefaultClient({});
|
||||
|
||||
export default new VueApollo({
|
||||
defaultClient,
|
||||
});
|
25
app/assets/javascripts/repository/index.js
Normal file
25
app/assets/javascripts/repository/index.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
import Vue from 'vue';
|
||||
import createRouter from './router';
|
||||
import App from './components/app.vue';
|
||||
import apolloProvider from './graphql';
|
||||
|
||||
export default function setupVueRepositoryList() {
|
||||
const el = document.getElementById('js-tree-list');
|
||||
const { projectPath, ref } = el.dataset;
|
||||
|
||||
apolloProvider.clients.defaultClient.cache.writeData({
|
||||
data: {
|
||||
projectPath,
|
||||
ref,
|
||||
},
|
||||
});
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
router: createRouter(projectPath, ref),
|
||||
apolloProvider,
|
||||
render(h) {
|
||||
return h(App);
|
||||
},
|
||||
});
|
||||
}
|
24
app/assets/javascripts/repository/pages/index.vue
Normal file
24
app/assets/javascripts/repository/pages/index.vue
Normal file
|
@ -0,0 +1,24 @@
|
|||
<script>
|
||||
import getRef from '../queries/getRef.graphql';
|
||||
|
||||
export default {
|
||||
apollo: {
|
||||
ref: {
|
||||
query: getRef,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ref: '',
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<router-link :to="{ path: `/tree/${ref}/app` }">
|
||||
Go to tree
|
||||
</router-link>
|
||||
</div>
|
||||
</template>
|
15
app/assets/javascripts/repository/pages/tree.vue
Normal file
15
app/assets/javascripts/repository/pages/tree.vue
Normal file
|
@ -0,0 +1,15 @@
|
|||
<script>
|
||||
export default {
|
||||
props: {
|
||||
path: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '/',
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>{{ path }}</div>
|
||||
</template>
|
3
app/assets/javascripts/repository/queries/getRef.graphql
Normal file
3
app/assets/javascripts/repository/queries/getRef.graphql
Normal file
|
@ -0,0 +1,3 @@
|
|||
query getRef {
|
||||
ref @client
|
||||
}
|
36
app/assets/javascripts/repository/router.js
Normal file
36
app/assets/javascripts/repository/router.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
import Vue from 'vue';
|
||||
import VueRouter from 'vue-router';
|
||||
import { joinPaths } from '../lib/utils/url_utility';
|
||||
import IndexPage from './pages/index.vue';
|
||||
import TreePage from './pages/tree.vue';
|
||||
|
||||
Vue.use(VueRouter);
|
||||
|
||||
export default function createRouter(base, baseRef) {
|
||||
return new VueRouter({
|
||||
mode: 'history',
|
||||
base: joinPaths(gon.relative_url_root || '', base),
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
name: 'projectRoot',
|
||||
component: IndexPage,
|
||||
},
|
||||
{
|
||||
path: `/tree/${baseRef}(/.*)?`,
|
||||
name: 'treePath',
|
||||
component: TreePage,
|
||||
props: route => ({
|
||||
path: route.params.pathMatch,
|
||||
}),
|
||||
beforeEnter(to, from, next) {
|
||||
document
|
||||
.querySelectorAll('.js-hide-on-navigation')
|
||||
.forEach(el => el.classList.add('hidden'));
|
||||
|
||||
next();
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
- project = local_assigns.fetch(:project) { @project }
|
||||
- content_url = local_assigns.fetch(:content_url) { @tree.readme ? project_blob_path(@project, tree_join(@ref, @tree.readme.path)) : project_tree_path(@project, @ref) }
|
||||
- show_auto_devops_callout = show_auto_devops_callout?(@project)
|
||||
- vue_file_list = Feature.enabled?(:vue_file_list, @project)
|
||||
|
||||
#tree-holder.tree-holder.clearfix
|
||||
.nav-block
|
||||
|
@ -13,7 +14,12 @@
|
|||
= render 'shared/commit_well', commit: commit, ref: ref, project: project
|
||||
|
||||
- if is_project_overview
|
||||
.project-buttons.append-bottom-default
|
||||
.project-buttons.append-bottom-default{ class: ("js-hide-on-navigation" if vue_file_list) }
|
||||
= render 'stat_anchor_list', anchors: @project.statistics_buttons(show_auto_devops_callout: show_auto_devops_callout)
|
||||
|
||||
= render 'projects/tree/tree_content', tree: @tree, content_url: content_url
|
||||
- if vue_file_list
|
||||
#js-tree-list{ data: { project_path: @project.full_path, ref: ref } }
|
||||
- if @tree.readme
|
||||
= render "projects/tree/readme", readme: @tree.readme
|
||||
- else
|
||||
= render 'projects/tree/tree_content', tree: @tree, content_url: content_url
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
- empty_repo = @project.empty_repo?
|
||||
- show_auto_devops_callout = show_auto_devops_callout?(@project)
|
||||
- max_project_topic_length = 15
|
||||
.project-home-panel{ class: ("empty-project" if empty_repo) }
|
||||
.project-home-panel{ class: [("empty-project" if empty_repo), ("js-hide-on-navigation" if Feature.enabled?(:vue_file_list, @project))] }
|
||||
.row.append-bottom-8
|
||||
.home-panel-title-row.col-md-12.col-lg-6.d-flex
|
||||
.avatar-container.rect-avatar.s64.home-panel-avatar.append-right-default.float-none
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
- if readme.rich_viewer
|
||||
%article.file-holder.readme-holder{ id: 'readme', class: ("limited-width-container" unless fluid_layout) }
|
||||
%article.file-holder.readme-holder{ id: 'readme', class: [("limited-width-container" unless fluid_layout), ("js-hide-on-navigation" if Feature.enabled?(:vue_file_list, @project))] }
|
||||
.js-file-title.file-title
|
||||
= blob_icon readme.mode, readme.name
|
||||
= link_to project_blob_path(@project, tree_join(@ref, readme.path)) do
|
||||
|
|
|
@ -5,6 +5,8 @@ describe 'Projects > Files > User views files page' do
|
|||
let(:user) { project.owner }
|
||||
|
||||
before do
|
||||
stub_feature_flags(vue_file_list: false)
|
||||
|
||||
sign_in user
|
||||
visit project_tree_path(project, project.repository.root_ref)
|
||||
end
|
||||
|
|
|
@ -11,6 +11,7 @@ describe "User browses files" do
|
|||
let(:user) { project.owner }
|
||||
|
||||
before do
|
||||
stub_feature_flags(vue_file_list: false)
|
||||
stub_feature_flags(csslab: false)
|
||||
sign_in(user)
|
||||
end
|
||||
|
|
|
@ -5,6 +5,8 @@ describe 'Projects > Files > User browses LFS files' do
|
|||
let(:user) { project.owner }
|
||||
|
||||
before do
|
||||
stub_feature_flags(vue_file_list: false)
|
||||
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@ describe 'Projects > Files > User creates a directory', :js do
|
|||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
stub_feature_flags(vue_file_list: false)
|
||||
|
||||
project.add_developer(user)
|
||||
sign_in(user)
|
||||
visit project_tree_path(project, 'master')
|
||||
|
|
|
@ -12,6 +12,8 @@ describe 'Projects > Files > User deletes files', :js do
|
|||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
stub_feature_flags(vue_file_list: false)
|
||||
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ describe 'Projects > Files > User edits files', :js do
|
|||
|
||||
before do
|
||||
stub_feature_flags(web_ide_default: false)
|
||||
stub_feature_flags(vue_file_list: false)
|
||||
|
||||
sign_in(user)
|
||||
end
|
||||
|
|
|
@ -14,6 +14,8 @@ describe 'Projects > Files > User replaces files', :js do
|
|||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
stub_feature_flags(vue_file_list: false)
|
||||
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@ describe 'Projects > Files > User uploads files' do
|
|||
let(:project2_tree_path_root_ref) { project_tree_path(project2, project2.repository.root_ref) }
|
||||
|
||||
before do
|
||||
stub_feature_flags(vue_file_list: false)
|
||||
|
||||
project.add_maintainer(user)
|
||||
sign_in(user)
|
||||
end
|
||||
|
|
|
@ -8,6 +8,7 @@ describe 'Projects tree', :js do
|
|||
let(:test_sha) { '7975be0116940bf2ad4321f79d02a55c5f7779aa' }
|
||||
|
||||
before do
|
||||
stub_feature_flags(vue_file_list: false)
|
||||
project.add_maintainer(user)
|
||||
sign_in(user)
|
||||
end
|
||||
|
|
|
@ -5,6 +5,7 @@ describe 'Project' do
|
|||
include MobileHelpers
|
||||
|
||||
before do
|
||||
stub_feature_flags(vue_file_list: false)
|
||||
stub_feature_flags(approval_rules: false)
|
||||
end
|
||||
|
||||
|
|
23
spec/frontend/repository/router_spec.js
Normal file
23
spec/frontend/repository/router_spec.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
import IndexPage from '~/repository/pages/index.vue';
|
||||
import TreePage from '~/repository/pages/tree.vue';
|
||||
import createRouter from '~/repository/router';
|
||||
|
||||
describe('Repository router spec', () => {
|
||||
it.each`
|
||||
path | component | componentName
|
||||
${'/'} | ${IndexPage} | ${'IndexPage'}
|
||||
${'/tree/master'} | ${TreePage} | ${'TreePage'}
|
||||
${'/tree/master/app/assets'} | ${TreePage} | ${'TreePage'}
|
||||
${'/tree/123/app/assets'} | ${null} | ${'null'}
|
||||
`('sets component as $componentName for path "$path"', ({ path, component }) => {
|
||||
const router = createRouter('', 'master');
|
||||
|
||||
const componentsForRoute = router.getMatchedComponents(path);
|
||||
|
||||
expect(componentsForRoute.length).toBe(component ? 1 : 0);
|
||||
|
||||
if (component) {
|
||||
expect(componentsForRoute).toContain(component);
|
||||
}
|
||||
});
|
||||
});
|
|
@ -7,6 +7,8 @@ describe 'projects/tree/show' do
|
|||
let(:repository) { project.repository }
|
||||
|
||||
before do
|
||||
stub_feature_flags(vue_file_list: false)
|
||||
|
||||
assign(:project, project)
|
||||
assign(:repository, repository)
|
||||
assign(:lfs_blob_ids, [])
|
||||
|
|
Loading…
Reference in a new issue