Commit 74fb4a1a authored by Phil Hughes's avatar Phil Hughes

Show and hide correct elements on file tree navigation

This correctly hides or shows elements based on the path in the
Vue file listing refactor
parent 16eec80d
...@@ -16,7 +16,6 @@ export default function setupVueRepositoryList() { ...@@ -16,7 +16,6 @@ export default function setupVueRepositoryList() {
const { dataset } = el; const { dataset } = el;
const { projectPath, projectShortPath, ref, fullName } = dataset; const { projectPath, projectShortPath, ref, fullName } = dataset;
const router = createRouter(projectPath, ref); const router = createRouter(projectPath, ref);
const hideOnRootEls = document.querySelectorAll('.js-hide-on-root');
apolloProvider.clients.defaultClient.cache.writeData({ apolloProvider.clients.defaultClient.cache.writeData({
data: { data: {
...@@ -28,20 +27,7 @@ export default function setupVueRepositoryList() { ...@@ -28,20 +27,7 @@ export default function setupVueRepositoryList() {
}); });
router.afterEach(({ params: { pathMatch } }) => { router.afterEach(({ params: { pathMatch } }) => {
const isRoot = pathMatch === undefined || pathMatch === '/';
setTitle(pathMatch, ref, fullName); setTitle(pathMatch, ref, fullName);
if (!isRoot) {
document
.querySelectorAll('.js-keep-hidden-on-navigation')
.forEach(elem => elem.classList.add('hidden'));
}
document
.querySelectorAll('.js-hide-on-navigation')
.forEach(elem => elem.classList.toggle('hidden', !isRoot));
hideOnRootEls.forEach(elem => elem.classList.toggle('hidden', isRoot));
}); });
const breadcrumbEl = document.getElementById('js-repo-breadcrumb'); const breadcrumbEl = document.getElementById('js-repo-breadcrumb');
......
<script> <script>
import TreeContent from '../components/tree_content.vue'; import TreePage from './tree.vue';
import { updateElementsVisibility } from '../utils/dom';
export default { export default {
components: { components: {
TreeContent, TreePage,
},
mounted() {
this.updateProjectElements(true);
},
beforeDestroy() {
this.updateProjectElements(false);
},
methods: {
updateProjectElements(isShow) {
updateElementsVisibility('.js-show-on-project-root', isShow);
},
}, },
}; };
</script> </script>
<template> <template>
<tree-content /> <tree-page path="/" />
</template> </template>
<script> <script>
import TreeContent from '../components/tree_content.vue'; import TreeContent from '../components/tree_content.vue';
import { updateElementsVisibility } from '../utils/dom';
export default { export default {
components: { components: {
...@@ -12,6 +13,23 @@ export default { ...@@ -12,6 +13,23 @@ export default {
default: '/', default: '/',
}, },
}, },
computed: {
isRoot() {
return this.path === '/';
},
},
watch: {
isRoot: {
immediate: true,
handler: 'updateElements',
},
},
methods: {
updateElements(isRoot) {
updateElementsVisibility('.js-show-on-root', isRoot);
updateElementsVisibility('.js-hide-on-root', !isRoot);
},
},
}; };
</script> </script>
......
// eslint-disable-next-line import/prefer-default-export
export const updateElementsVisibility = (selector, isVisible) => {
document.querySelectorAll(selector).forEach(elem => elem.classList.toggle('hidden', !isVisible));
};
const DEFAULT_TITLE = '· GitLab';
// eslint-disable-next-line import/prefer-default-export // eslint-disable-next-line import/prefer-default-export
export const setTitle = (pathMatch, ref, project) => { export const setTitle = (pathMatch, ref, project) => {
if (!pathMatch) return; if (!pathMatch) {
document.title = `${project} ${DEFAULT_TITLE}`;
return;
}
const path = pathMatch.replace(/^\//, ''); const path = pathMatch.replace(/^\//, '');
const isEmpty = path === ''; const isEmpty = path === '';
/* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */ /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
document.title = `${isEmpty ? 'Files' : path} · ${ref} · ${project}`; document.title = `${isEmpty ? 'Files' : path} · ${ref} · ${project} ${DEFAULT_TITLE}`;
}; };
...@@ -4,7 +4,7 @@ module RepositoryLanguagesHelper ...@@ -4,7 +4,7 @@ module RepositoryLanguagesHelper
def repository_languages_bar(languages) def repository_languages_bar(languages)
return if languages.none? return if languages.none?
content_tag :div, class: 'progress repository-languages-bar' do content_tag :div, class: 'progress repository-languages-bar js-show-on-project-root' do
safe_join(languages.map { |lang| language_progress(lang) }) safe_join(languages.map { |lang| language_progress(lang) })
end end
end end
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
= render 'shared/commit_well', commit: commit, ref: ref, project: project = render 'shared/commit_well', commit: commit, ref: ref, project: project
- if is_project_overview - if is_project_overview
.project-buttons.append-bottom-default{ class: ("js-keep-hidden-on-navigation" if vue_file_list_enabled?) } .project-buttons.append-bottom-default{ class: ("js-show-on-project-root" if vue_file_list_enabled?) }
= render 'stat_anchor_list', anchors: @project.statistics_buttons(show_auto_devops_callout: show_auto_devops_callout) = render 'stat_anchor_list', anchors: @project.statistics_buttons(show_auto_devops_callout: show_auto_devops_callout)
- if vue_file_list_enabled? - if vue_file_list_enabled?
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
- max_project_topic_length = 15 - max_project_topic_length = 15
- emails_disabled = @project.emails_disabled? - emails_disabled = @project.emails_disabled?
.project-home-panel{ class: [("empty-project" if empty_repo), ("js-keep-hidden-on-navigation" if vue_file_list_enabled?)] } .project-home-panel{ class: [("empty-project" if empty_repo), ("js-show-on-project-root" if vue_file_list_enabled?)] }
.row.append-bottom-8 .row.append-bottom-8
.home-panel-title-row.col-md-12.col-lg-6.d-flex .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 .avatar-container.rect-avatar.s64.home-panel-avatar.append-right-default.float-none
......
- if readme.rich_viewer - if readme.rich_viewer
%article.file-holder.readme-holder{ id: 'readme', class: [("limited-width-container" unless fluid_layout), ("js-hide-on-navigation" if vue_file_list_enabled?)] } %article.file-holder.readme-holder{ id: 'readme', class: [("limited-width-container" unless fluid_layout), ("js-show-on-root" if vue_file_list_enabled?)] }
.js-file-title.file-title .js-file-title.file-title
= blob_icon readme.mode, readme.name = blob_icon readme.mode, readme.name
= link_to project_blob_path(@project, tree_join(@ref, readme.path)) do = link_to project_blob_path(@project, tree_join(@ref, readme.path)) do
......
import { shallowMount } from '@vue/test-utils';
import IndexPage from '~/repository/pages/index.vue';
import TreePage from '~/repository/pages/tree.vue';
import { updateElementsVisibility } from '~/repository/utils/dom';
jest.mock('~/repository/utils/dom');
describe('Repository index page component', () => {
let wrapper;
function factory() {
wrapper = shallowMount(IndexPage);
}
afterEach(() => {
wrapper.destroy();
updateElementsVisibility.mockClear();
});
it('calls updateElementsVisibility on mounted', () => {
factory();
expect(updateElementsVisibility).toHaveBeenCalledWith('.js-show-on-project-root', true);
});
it('calls updateElementsVisibility after destroy', () => {
factory();
wrapper.destroy();
expect(updateElementsVisibility.mock.calls.pop()).toEqual(['.js-show-on-project-root', false]);
});
it('renders TreePage', () => {
factory();
const child = wrapper.find(TreePage);
expect(child.exists()).toBe(true);
expect(child.props()).toEqual({ path: '/' });
});
});
import { shallowMount } from '@vue/test-utils';
import TreePage from '~/repository/pages/tree.vue';
import { updateElementsVisibility } from '~/repository/utils/dom';
jest.mock('~/repository/utils/dom');
describe('Repository tree page component', () => {
let wrapper;
function factory(path) {
wrapper = shallowMount(TreePage, { propsData: { path } });
}
afterEach(() => {
wrapper.destroy();
updateElementsVisibility.mockClear();
});
describe('when root path', () => {
beforeEach(() => {
factory('/');
});
it('shows root elements', () => {
expect(updateElementsVisibility.mock.calls).toEqual([
['.js-show-on-root', true],
['.js-hide-on-root', false],
]);
});
describe('when changed', () => {
beforeEach(() => {
updateElementsVisibility.mockClear();
wrapper.setProps({ path: '/test' });
});
it('hides root elements', () => {
expect(updateElementsVisibility.mock.calls).toEqual([
['.js-show-on-root', false],
['.js-hide-on-root', true],
]);
});
});
});
describe('when non-root path', () => {
beforeEach(() => {
factory('/test');
});
it('hides root elements', () => {
expect(updateElementsVisibility.mock.calls).toEqual([
['.js-show-on-root', false],
['.js-hide-on-root', true],
]);
});
});
});
import { setHTMLFixture } from '../../helpers/fixtures';
import { updateElementsVisibility } from '~/repository/utils/dom';
describe('updateElementsVisibility', () => {
it('adds hidden class', () => {
setHTMLFixture('<div class="js-test"></div>');
updateElementsVisibility('.js-test', false);
expect(document.querySelector('.js-test').classList).toContain('hidden');
});
it('removes hidden class', () => {
setHTMLFixture('<div class="hidden js-test"></div>');
updateElementsVisibility('.js-test', true);
expect(document.querySelector('.js-test').classList).not.toContain('hidden');
});
});
...@@ -8,8 +8,8 @@ describe('setTitle', () => { ...@@ -8,8 +8,8 @@ describe('setTitle', () => {
${'app/assets'} | ${'app/assets'} ${'app/assets'} | ${'app/assets'}
${'app/assets/javascripts'} | ${'app/assets/javascripts'} ${'app/assets/javascripts'} | ${'app/assets/javascripts'}
`('sets document title as $title for $path', ({ path, title }) => { `('sets document title as $title for $path', ({ path, title }) => {
setTitle(path, 'master', 'GitLab'); setTitle(path, 'master', 'GitLab Org / GitLab');
expect(document.title).toEqual(`${title} · master · GitLab`); expect(document.title).toEqual(`${title} · master · GitLab Org / GitLab · GitLab`);
}); });
}); });
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