Commit 0489d9c0 authored by Phil Hughes's avatar Phil Hughes

Merge branch '222685-improve-rendering-in-file-browser' into 'master'

Improve rendering of very large files in the Repo File Browser

Closes #222685

See merge request gitlab-org/gitlab!38733
parents ddf1a89b 7aac87b5
......@@ -34,7 +34,10 @@ const setupAxiosStartupCalls = axios => {
});
// eslint-disable-next-line promise/no-nesting
return res.json().then(data => ({
return res
.clone()
.json()
.then(data => ({
data,
status: res.status,
statusText: res.statusText,
......
<script>
import { GlButton } from '@gitlab/ui';
import createFlash from '~/flash';
import { __ } from '../../locale';
import FileTable from './table/index.vue';
......@@ -8,12 +9,15 @@ import projectPathQuery from '../queries/project_path.query.graphql';
import FilePreview from './preview/index.vue';
import { readmeFile } from '../utils/readme';
const LIMIT = 1000;
const PAGE_SIZE = 100;
export const INITIAL_FETCH_COUNT = LIMIT / PAGE_SIZE;
export default {
components: {
FileTable,
FilePreview,
GlButton,
},
mixins: [getRefMixin],
apollo: {
......@@ -43,12 +47,19 @@ export default {
blobs: [],
},
isLoadingFiles: false,
isOverLimit: false,
clickedShowMore: false,
pageSize: PAGE_SIZE,
fetchCounter: 0,
};
},
computed: {
readme() {
return readmeFile(this.entries.blobs);
},
hasShowMore() {
return !this.clickedShowMore && this.fetchCounter === INITIAL_FETCH_COUNT;
},
},
watch: {
......@@ -76,7 +87,7 @@ export default {
ref: this.ref,
path: this.path || '/',
nextPageCursor: this.nextPageCursor,
pageSize: PAGE_SIZE,
pageSize: this.pageSize,
},
})
.then(({ data }) => {
......@@ -96,7 +107,11 @@ export default {
if (pageInfo?.hasNextPage) {
this.nextPageCursor = pageInfo.endCursor;
this.fetchCounter += 1;
if (this.fetchCounter < INITIAL_FETCH_COUNT || this.clickedShowMore) {
this.fetchFiles();
this.clickedShowMore = false;
}
}
})
.catch(error => {
......@@ -112,6 +127,10 @@ export default {
.concat(data.trees.pageInfo, data.submodules.pageInfo, data.blobs.pageInfo)
.find(({ hasNextPage }) => hasNextPage);
},
showMore() {
this.clickedShowMore = true;
this.fetchFiles();
},
},
};
</script>
......@@ -124,6 +143,19 @@ export default {
:is-loading="isLoadingFiles"
:loading-path="loadingPath"
/>
<div
v-if="hasShowMore"
class="gl-border-1 gl-border-gray-100 gl-rounded-base gl-border-t-none gl-border-b-solid gl-border-l-solid gl-border-r-solid gl-rounded-top-right-none gl-rounded-top-left-none gl-mt-n1"
>
<gl-button
variant="link"
class="gl-display-flex gl-w-full gl-py-4!"
:loading="isLoadingFiles"
@click="showMore"
>
{{ s__('ProjectFileTree|Show more') }}
</gl-button>
</div>
<file-preview v-if="readme" :blob="readme" />
</div>
</template>
---
title: Improve rendering of very large files in the Repo File Browser
merge_request: 38733
author:
type: fixed
......@@ -18793,6 +18793,9 @@ msgstr ""
msgid "ProjectFileTree|Name"
msgstr ""
msgid "ProjectFileTree|Show more"
msgstr ""
msgid "ProjectLastActivity|Never"
msgstr ""
......
import { shallowMount } from '@vue/test-utils';
import TreeContent from '~/repository/components/tree_content.vue';
import { GlButton } from '@gitlab/ui';
import TreeContent, { INITIAL_FETCH_COUNT } from '~/repository/components/tree_content.vue';
import FilePreview from '~/repository/components/preview/index.vue';
let vm;
......@@ -25,14 +26,24 @@ describe('Repository table component', () => {
vm.destroy();
});
it('renders file preview', () => {
it('renders file preview', async () => {
factory('/');
vm.setData({ entries: { blobs: [{ name: 'README.md' }] } });
return vm.vm.$nextTick().then(() => {
await vm.vm.$nextTick();
expect(vm.find(FilePreview).exists()).toBe(true);
});
it('trigger fetchFiles when mounted', async () => {
factory('/');
jest.spyOn(vm.vm, 'fetchFiles').mockImplementation(() => {});
await vm.vm.$nextTick();
expect(vm.vm.fetchFiles).toHaveBeenCalled();
});
describe('normalizeData', () => {
......@@ -70,4 +81,59 @@ describe('Repository table component', () => {
expect(output).toEqual({ hasNextPage: true, nextCursor: 'test' });
});
});
describe('Show more button', () => {
const showMoreButton = () => vm.find(GlButton);
describe('when is present', () => {
beforeEach(async () => {
factory('/');
vm.setData({ fetchCounter: 10, clickedShowMore: false });
await vm.vm.$nextTick();
});
it('is not rendered once it is clicked', async () => {
showMoreButton().vm.$emit('click');
await vm.vm.$nextTick();
expect(showMoreButton().exists()).toBe(false);
});
it('is rendered', async () => {
expect(showMoreButton().exists()).toBe(true);
});
it('changes clickedShowMore when show more button is clicked', async () => {
showMoreButton().vm.$emit('click');
expect(vm.vm.clickedShowMore).toBe(true);
});
it('triggers fetchFiles when show more button is clicked', async () => {
jest.spyOn(vm.vm, 'fetchFiles');
showMoreButton().vm.$emit('click');
expect(vm.vm.fetchFiles).toBeCalled();
});
});
it('is not rendered if less than 1000 files', async () => {
factory('/');
vm.setData({ fetchCounter: 5, clickedShowMore: false });
await vm.vm.$nextTick();
expect(showMoreButton().exists()).toBe(false);
});
it('has limit of 1000 files on initial load', () => {
factory('/');
expect(INITIAL_FETCH_COUNT * vm.vm.pageSize).toBe(1000);
});
});
});
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