diff --git a/app/assets/javascripts/repository/components/table/index.vue b/app/assets/javascripts/repository/components/table/index.vue
index 7119861c7b3bbc04a3f71e8796883cce47c004b3..ad3d8f9329d8ff15e0bbd9880abde6e5c328e4af 100644
--- a/app/assets/javascripts/repository/components/table/index.vue
+++ b/app/assets/javascripts/repository/components/table/index.vue
@@ -4,11 +4,13 @@ import { sprintf, __ } from '../../../locale';
import getRefMixin from '../../mixins/get_ref';
import getFiles from '../../queries/getFiles.graphql';
import TableHeader from './header.vue';
+import TableRow from './row.vue';
export default {
components: {
GlLoadingIcon,
TableHeader,
+ TableRow,
},
mixins: [getRefMixin],
apollo: {
@@ -57,7 +59,15 @@ export default {
}}
-
+
+
+
diff --git a/app/assets/javascripts/repository/components/table/row.vue b/app/assets/javascripts/repository/components/table/row.vue
new file mode 100644
index 0000000000000000000000000000000000000000..0ad0fdbd605fb3291f86820101050e569cc55dd1
--- /dev/null
+++ b/app/assets/javascripts/repository/components/table/row.vue
@@ -0,0 +1,60 @@
+
+
+
+
+ |
+
+ {{ path }}
+
+ @ {{ id }}
+
+ |
+ |
+ |
+
+
diff --git a/app/assets/javascripts/repository/graphql.js b/app/assets/javascripts/repository/graphql.js
index 0aedc73fc1224e5b6bb2674be0ae8bbb445c6c82..c85db5c01e5d389f089552725c070d1a2ef6fd08 100644
--- a/app/assets/javascripts/repository/graphql.js
+++ b/app/assets/javascripts/repository/graphql.js
@@ -7,7 +7,36 @@ Vue.use(VueApollo);
const defaultClient = createDefaultClient({
Query: {
files() {
- return [];
+ return [
+ {
+ __typename: 'file',
+ id: 1,
+ name: 'app',
+ flatPath: 'app',
+ type: 'folder',
+ },
+ {
+ __typename: 'file',
+ id: 2,
+ name: 'gitlab-svg',
+ flatPath: 'gitlab-svg',
+ type: 'commit',
+ },
+ {
+ __typename: 'file',
+ id: 3,
+ name: 'index.js',
+ flatPath: 'index.js',
+ type: 'blob',
+ },
+ {
+ __typename: 'file',
+ id: 4,
+ name: 'test.pdf',
+ flatPath: 'fixtures/test.pdf',
+ type: 'blob',
+ },
+ ];
},
},
});
diff --git a/app/assets/javascripts/repository/pages/tree.vue b/app/assets/javascripts/repository/pages/tree.vue
index 413102b2cd36645b011f0c37ee9587be552a84b5..3b898d1aa9199131f2291b96b97e924dc5151c9a 100644
--- a/app/assets/javascripts/repository/pages/tree.vue
+++ b/app/assets/javascripts/repository/pages/tree.vue
@@ -2,7 +2,7 @@
import FileTable from '../components/table/index.vue';
export default {
- component: {
+ components: {
FileTable,
},
props: {
diff --git a/app/assets/javascripts/repository/queries/getFiles.graphql b/app/assets/javascripts/repository/queries/getFiles.graphql
index 5ceaf67ea82f45a701d0d81ab76547c2bf296d9c..fb446780ed1ef20baa8386c830c0c9a59af7ff28 100644
--- a/app/assets/javascripts/repository/queries/getFiles.graphql
+++ b/app/assets/javascripts/repository/queries/getFiles.graphql
@@ -1,8 +1,7 @@
query getFiles($path: String!, $ref: String!) {
files(path: $path, ref: $ref) @client {
id
- name
- fullPath
+ flatPath
type
}
}
diff --git a/app/assets/javascripts/repository/utils/icon.js b/app/assets/javascripts/repository/utils/icon.js
new file mode 100644
index 0000000000000000000000000000000000000000..3e93ff0ec39e477d48e46aa680bd0a6c0815bf9e
--- /dev/null
+++ b/app/assets/javascripts/repository/utils/icon.js
@@ -0,0 +1,99 @@
+const entryTypeIcons = {
+ folder: 'folder',
+ commit: 'archive',
+};
+
+const fileTypeIcons = [
+ { extensions: ['pdf'], name: 'file-pdf-o' },
+ {
+ extensions: [
+ 'jpg',
+ 'jpeg',
+ 'jif',
+ 'jfif',
+ 'jp2',
+ 'jpx',
+ 'j2k',
+ 'j2c',
+ 'png',
+ 'gif',
+ 'tif',
+ 'tiff',
+ 'svg',
+ 'ico',
+ 'bmp',
+ ],
+ name: 'file-image-o',
+ },
+ {
+ extensions: ['zip', 'zipx', 'tar', 'gz', 'bz', 'bzip', 'xz', 'rar', '7z'],
+ name: 'file-archive-o',
+ },
+ { extensions: ['mp3', 'wma', 'ogg', 'oga', 'wav', 'flac', 'aac'], name: 'file-audio-o' },
+ {
+ extensions: [
+ 'mp4',
+ 'm4p',
+ 'm4v',
+ 'mpg',
+ 'mp2',
+ 'mpeg',
+ 'mpe',
+ 'mpv',
+ 'm2v',
+ 'avi',
+ 'mkv',
+ 'flv',
+ 'ogv',
+ 'mov',
+ '3gp',
+ '3g2',
+ ],
+ name: 'file-video-o',
+ },
+ { extensions: ['doc', 'dot', 'docx', 'docm', 'dotx', 'dotm', 'docb'], name: 'file-word-o' },
+ {
+ extensions: [
+ 'xls',
+ 'xlt',
+ 'xlm',
+ 'xlsx',
+ 'xlsm',
+ 'xltx',
+ 'xltm',
+ 'xlsb',
+ 'xla',
+ 'xlam',
+ 'xll',
+ 'xlw',
+ ],
+ name: 'file-excel-o',
+ },
+ {
+ extensions: [
+ 'ppt',
+ 'pot',
+ 'pps',
+ 'pptx',
+ 'pptm',
+ 'potx',
+ 'potm',
+ 'ppam',
+ 'ppsx',
+ 'ppsm',
+ 'sldx',
+ 'sldm',
+ ],
+ name: 'file-powerpoint-o',
+ },
+];
+
+// eslint-disable-next-line import/prefer-default-export
+export const getIconName = (type, path) => {
+ if (entryTypeIcons[type]) return entryTypeIcons[type];
+
+ const extension = path.split('.').pop();
+ const file = fileTypeIcons.find(t => t.extensions.some(ext => ext === extension));
+
+ return file ? file.name : 'file-text-o';
+};
diff --git a/spec/frontend/repository/components/table/__snapshots__/row_spec.js.snap b/spec/frontend/repository/components/table/__snapshots__/row_spec.js.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f0b72343b6e6fcea1fd4306233a60e1e24ed33e5
--- /dev/null
+++ b/spec/frontend/repository/components/table/__snapshots__/row_spec.js.snap
@@ -0,0 +1,33 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Repository table row component renders table row 1`] = `
+
+ |
+
+
+
+ test
+
+
+
+ |
+
+ |
+
+ |
+
+`;
diff --git a/spec/frontend/repository/components/table/row_spec.js b/spec/frontend/repository/components/table/row_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..216128dce2583242b7aab8dd40aa5e1539d893f8
--- /dev/null
+++ b/spec/frontend/repository/components/table/row_spec.js
@@ -0,0 +1,85 @@
+import { shallowMount, RouterLinkStub } from '@vue/test-utils';
+import TableRow from '~/repository/components/table/row.vue';
+
+let vm;
+let $router;
+
+function factory(propsData = {}) {
+ $router = {
+ push: jest.fn(),
+ };
+
+ vm = shallowMount(TableRow, {
+ propsData,
+ mocks: {
+ $router,
+ },
+ stubs: {
+ RouterLink: RouterLinkStub,
+ },
+ });
+
+ vm.setData({ ref: 'master' });
+}
+
+describe('Repository table row component', () => {
+ afterEach(() => {
+ vm.destroy();
+ });
+
+ it('renders table row', () => {
+ factory({
+ id: 1,
+ path: 'test',
+ type: 'file',
+ });
+
+ expect(vm.element).toMatchSnapshot();
+ });
+
+ it.each`
+ type | component | componentName
+ ${'folder'} | ${RouterLinkStub} | ${'RouterLink'}
+ ${'file'} | ${'a'} | ${'hyperlink'}
+ ${'commit'} | ${'a'} | ${'hyperlink'}
+ `('renders a $componentName for type $type', ({ type, component }) => {
+ factory({
+ id: 1,
+ path: 'test',
+ type,
+ });
+
+ expect(vm.find(component).exists()).toBe(true);
+ });
+
+ it.each`
+ type | pushes
+ ${'folder'} | ${true}
+ ${'file'} | ${false}
+ ${'commit'} | ${false}
+ `('pushes new router if type $type is folder', ({ type, pushes }) => {
+ factory({
+ id: 1,
+ path: 'test',
+ type,
+ });
+
+ vm.trigger('click');
+
+ if (pushes) {
+ expect($router.push).toHaveBeenCalledWith({ path: '/tree/master/test' });
+ } else {
+ expect($router.push).not.toHaveBeenCalled();
+ }
+ });
+
+ it('renders commit ID for submodule', () => {
+ factory({
+ id: 1,
+ path: 'test',
+ type: 'commit',
+ });
+
+ expect(vm.find('.commit-sha').text()).toContain('1');
+ });
+});
diff --git a/spec/frontend/repository/utils/icon_spec.js b/spec/frontend/repository/utils/icon_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..52787327befce5202089801dde9d63fd728d8271
--- /dev/null
+++ b/spec/frontend/repository/utils/icon_spec.js
@@ -0,0 +1,23 @@
+import { getIconName } from '~/repository/utils/icon';
+
+describe('getIconName', () => {
+ // Tests the returning font awesome icon name
+ // We only test one for each file type to save testing a lot of different
+ // file types
+ it.each`
+ type | path | icon
+ ${'folder'} | ${''} | ${'folder'}
+ ${'commit'} | ${''} | ${'archive'}
+ ${'file'} | ${'test.pdf'} | ${'file-pdf-o'}
+ ${'file'} | ${'test.jpg'} | ${'file-image-o'}
+ ${'file'} | ${'test.zip'} | ${'file-archive-o'}
+ ${'file'} | ${'test.mp3'} | ${'file-audio-o'}
+ ${'file'} | ${'test.flv'} | ${'file-video-o'}
+ ${'file'} | ${'test.dotx'} | ${'file-word-o'}
+ ${'file'} | ${'test.xlsb'} | ${'file-excel-o'}
+ ${'file'} | ${'test.ppam'} | ${'file-powerpoint-o'}
+ ${'file'} | ${'test.js'} | ${'file-text-o'}
+ `('returns $icon for $type with path $path', ({ type, path, icon }) => {
+ expect(getIconName(type, path)).toEqual(icon);
+ });
+});