diff options
Diffstat (limited to 'app/assets/javascripts/repository/components/table/index.vue')
-rw-r--r-- | app/assets/javascripts/repository/components/table/index.vue | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/app/assets/javascripts/repository/components/table/index.vue b/app/assets/javascripts/repository/components/table/index.vue new file mode 100644 index 00000000000..f4df98ac2ff --- /dev/null +++ b/app/assets/javascripts/repository/components/table/index.vue @@ -0,0 +1,144 @@ +<script> +import { GlLoadingIcon } from '@gitlab/ui'; +import createFlash from '~/flash'; +import { sprintf, __ } from '../../../locale'; +import getRefMixin from '../../mixins/get_ref'; +import getFiles from '../../queries/getFiles.graphql'; +import getProjectPath from '../../queries/getProjectPath.graphql'; +import TableHeader from './header.vue'; +import TableRow from './row.vue'; +import ParentRow from './parent_row.vue'; + +const PAGE_SIZE = 100; + +export default { + components: { + GlLoadingIcon, + TableHeader, + TableRow, + ParentRow, + }, + mixins: [getRefMixin], + apollo: { + projectPath: { + query: getProjectPath, + }, + }, + props: { + path: { + type: String, + required: true, + }, + }, + data() { + return { + projectPath: '', + nextPageCursor: '', + entries: { + trees: [], + submodules: [], + blobs: [], + }, + isLoadingFiles: false, + }; + }, + computed: { + tableCaption() { + return sprintf( + __('Files, directories, and submodules in the path %{path} for commit reference %{ref}'), + { path: this.path, ref: this.ref }, + ); + }, + showParentRow() { + return !this.isLoadingFiles && ['', '/'].indexOf(this.path) === -1; + }, + }, + watch: { + $route: function routeChange() { + this.entries.trees = []; + this.entries.submodules = []; + this.entries.blobs = []; + this.nextPageCursor = ''; + this.fetchFiles(); + }, + }, + mounted() { + // We need to wait for `ref` and `projectPath` to be set + this.$nextTick(() => this.fetchFiles()); + }, + methods: { + fetchFiles() { + this.isLoadingFiles = true; + + return this.$apollo + .query({ + query: getFiles, + variables: { + projectPath: this.projectPath, + ref: this.ref, + path: this.path, + nextPageCursor: this.nextPageCursor, + pageSize: PAGE_SIZE, + }, + }) + .then(({ data }) => { + if (!data) return; + + const pageInfo = this.hasNextPage(data.project.repository.tree); + + this.isLoadingFiles = false; + this.entries = Object.keys(this.entries).reduce( + (acc, key) => ({ + ...acc, + [key]: this.normalizeData(key, data.project.repository.tree[key].edges), + }), + {}, + ); + + if (pageInfo && pageInfo.hasNextPage) { + this.nextPageCursor = pageInfo.endCursor; + this.fetchFiles(); + } + }) + .catch(() => createFlash(__('An error occurding while fetching folder content.'))); + }, + normalizeData(key, data) { + return this.entries[key].concat(data.map(({ node }) => node)); + }, + hasNextPage(data) { + return [] + .concat(data.trees.pageInfo, data.submodules.pageInfo, data.blobs.pageInfo) + .find(({ hasNextPage }) => hasNextPage); + }, + }, +}; +</script> + +<template> + <div class="tree-content-holder"> + <div class="table-holder bordered-box"> + <table class="table tree-table qa-file-tree" aria-live="polite"> + <caption class="sr-only"> + {{ + tableCaption + }} + </caption> + <table-header v-once /> + <tbody> + <parent-row v-show="showParentRow" :commit-ref="ref" :path="path" /> + <template v-for="val in entries"> + <table-row + v-for="entry in val" + :id="entry.id" + :key="`${entry.flatPath}-${entry.id}`" + :current-path="path" + :path="entry.flatPath" + :type="entry.type" + /> + </template> + </tbody> + </table> + <gl-loading-icon v-show="isLoadingFiles" class="my-3" size="md" /> + </div> + </div> +</template> |