Commit 7aac87b5 authored by Samantha Ming's avatar Samantha Ming Committed by Phil Hughes

Add stop point for repo files with more button

Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/222685
parent 08edb3c1
...@@ -34,14 +34,17 @@ const setupAxiosStartupCalls = axios => { ...@@ -34,14 +34,17 @@ const setupAxiosStartupCalls = axios => {
}); });
// eslint-disable-next-line promise/no-nesting // eslint-disable-next-line promise/no-nesting
return res.json().then(data => ({ return res
data, .clone()
status: res.status, .json()
statusText: res.statusText, .then(data => ({
headers: fetchHeaders, data,
config: req, status: res.status,
request: req, statusText: res.statusText,
})); headers: fetchHeaders,
config: req,
request: req,
}));
}); });
} }
......
<script> <script>
import { GlButton } from '@gitlab/ui';
import createFlash from '~/flash'; import createFlash from '~/flash';
import { __ } from '../../locale'; import { __ } from '../../locale';
import FileTable from './table/index.vue'; import FileTable from './table/index.vue';
...@@ -8,12 +9,15 @@ import projectPathQuery from '../queries/project_path.query.graphql'; ...@@ -8,12 +9,15 @@ import projectPathQuery from '../queries/project_path.query.graphql';
import FilePreview from './preview/index.vue'; import FilePreview from './preview/index.vue';
import { readmeFile } from '../utils/readme'; import { readmeFile } from '../utils/readme';
const LIMIT = 1000;
const PAGE_SIZE = 100; const PAGE_SIZE = 100;
export const INITIAL_FETCH_COUNT = LIMIT / PAGE_SIZE;
export default { export default {
components: { components: {
FileTable, FileTable,
FilePreview, FilePreview,
GlButton,
}, },
mixins: [getRefMixin], mixins: [getRefMixin],
apollo: { apollo: {
...@@ -43,12 +47,19 @@ export default { ...@@ -43,12 +47,19 @@ export default {
blobs: [], blobs: [],
}, },
isLoadingFiles: false, isLoadingFiles: false,
isOverLimit: false,
clickedShowMore: false,
pageSize: PAGE_SIZE,
fetchCounter: 0,
}; };
}, },
computed: { computed: {
readme() { readme() {
return readmeFile(this.entries.blobs); return readmeFile(this.entries.blobs);
}, },
hasShowMore() {
return !this.clickedShowMore && this.fetchCounter === INITIAL_FETCH_COUNT;
},
}, },
watch: { watch: {
...@@ -76,7 +87,7 @@ export default { ...@@ -76,7 +87,7 @@ export default {
ref: this.ref, ref: this.ref,
path: this.path || '/', path: this.path || '/',
nextPageCursor: this.nextPageCursor, nextPageCursor: this.nextPageCursor,
pageSize: PAGE_SIZE, pageSize: this.pageSize,
}, },
}) })
.then(({ data }) => { .then(({ data }) => {
...@@ -96,7 +107,11 @@ export default { ...@@ -96,7 +107,11 @@ export default {
if (pageInfo?.hasNextPage) { if (pageInfo?.hasNextPage) {
this.nextPageCursor = pageInfo.endCursor; this.nextPageCursor = pageInfo.endCursor;
this.fetchFiles(); this.fetchCounter += 1;
if (this.fetchCounter < INITIAL_FETCH_COUNT || this.clickedShowMore) {
this.fetchFiles();
this.clickedShowMore = false;
}
} }
}) })
.catch(error => { .catch(error => {
...@@ -112,6 +127,10 @@ export default { ...@@ -112,6 +127,10 @@ export default {
.concat(data.trees.pageInfo, data.submodules.pageInfo, data.blobs.pageInfo) .concat(data.trees.pageInfo, data.submodules.pageInfo, data.blobs.pageInfo)
.find(({ hasNextPage }) => hasNextPage); .find(({ hasNextPage }) => hasNextPage);
}, },
showMore() {
this.clickedShowMore = true;
this.fetchFiles();
},
}, },
}; };
</script> </script>
...@@ -124,6 +143,19 @@ export default { ...@@ -124,6 +143,19 @@ export default {
:is-loading="isLoadingFiles" :is-loading="isLoadingFiles"
:loading-path="loadingPath" :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" /> <file-preview v-if="readme" :blob="readme" />
</div> </div>
</template> </template>
---
title: Improve rendering of very large files in the Repo File Browser
merge_request: 38733
author:
type: fixed
...@@ -18823,6 +18823,9 @@ msgstr "" ...@@ -18823,6 +18823,9 @@ msgstr ""
msgid "ProjectFileTree|Name" msgid "ProjectFileTree|Name"
msgstr "" msgstr ""
msgid "ProjectFileTree|Show more"
msgstr ""
msgid "ProjectLastActivity|Never" msgid "ProjectLastActivity|Never"
msgstr "" msgstr ""
......
import { shallowMount } from '@vue/test-utils'; 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'; import FilePreview from '~/repository/components/preview/index.vue';
let vm; let vm;
...@@ -25,14 +26,24 @@ describe('Repository table component', () => { ...@@ -25,14 +26,24 @@ describe('Repository table component', () => {
vm.destroy(); vm.destroy();
}); });
it('renders file preview', () => { it('renders file preview', async () => {
factory('/'); factory('/');
vm.setData({ entries: { blobs: [{ name: 'README.md' }] } }); vm.setData({ entries: { blobs: [{ name: 'README.md' }] } });
return vm.vm.$nextTick().then(() => { await vm.vm.$nextTick();
expect(vm.find(FilePreview).exists()).toBe(true);
}); 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', () => { describe('normalizeData', () => {
...@@ -70,4 +81,59 @@ describe('Repository table component', () => { ...@@ -70,4 +81,59 @@ describe('Repository table component', () => {
expect(output).toEqual({ hasNextPage: true, nextCursor: 'test' }); 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