Commit a7c7b257 authored by Miguel Rincon's avatar Miguel Rincon

Merge branch '215395-add-symlink-icon-to-file-rows-in-repository-browser-2' into 'master'

Show symlink icon in repository browser

See merge request gitlab-org/gitlab!36524
parents 878b7940 fb70ac68
......@@ -97,6 +97,7 @@ export default {
:path="entry.flatPath"
:type="entry.type"
:url="entry.webUrl"
:mode="entry.mode"
:submodule-tree-url="entry.treeUrl"
:lfs-oid="entry.lfsOid"
:loading-path="loadingPath"
......
......@@ -66,6 +66,11 @@ export default {
type: String,
required: true,
},
mode: {
type: String,
required: false,
default: '',
},
type: {
type: String,
required: true,
......@@ -140,6 +145,7 @@ export default {
>
<file-icon
:file-name="fullPath"
:file-mode="mode"
:folder="isFolder"
:submodule="isSubmodule"
:loading="path === loadingPath"
......
<script>
import { GlLoadingIcon, GlIcon } from '@gitlab/ui';
import getIconForFile from './file_icon/file_icon_map';
import { FILE_SYMLINK_MODE } from '../constants';
/* This is a re-usable vue component for rendering a svg sprite
icon
......@@ -24,6 +25,11 @@ export default {
type: String,
required: true,
},
fileMode: {
type: String,
required: false,
default: '',
},
folder: {
type: Boolean,
......@@ -60,8 +66,12 @@ export default {
},
},
computed: {
isSymlink() {
return this.fileMode === FILE_SYMLINK_MODE;
},
spriteHref() {
const iconName = this.submodule ? 'folder-git' : getIconForFile(this.fileName) || 'file';
return `${gon.sprite_file_icons}#${iconName}`;
},
folderIconName() {
......@@ -75,13 +85,11 @@ export default {
</script>
<template>
<span>
<svg v-if="!loading && !folder" :class="[iconSizeClass, cssClasses]">
<use v-bind="{ 'xlink:href': spriteHref }" /></svg
><gl-icon
v-if="!loading && folder"
:name="folderIconName"
:size="size"
class="folder-icon"
/><gl-loading-icon v-if="loading" :inline="true" />
<gl-loading-icon v-if="loading" :inline="true" />
<gl-icon v-else-if="isSymlink" name="symlink" :size="size" />
<svg v-else-if="!folder" :class="[iconSizeClass, cssClasses]">
<use v-bind="{ 'xlink:href': spriteHref }" />
</svg>
<gl-icon v-else :name="folderIconName" :size="size" class="folder-icon" />
</span>
</template>
......@@ -6,6 +6,8 @@ const INTERVALS = {
day: 'day',
};
export const FILE_SYMLINK_MODE = '120000';
export const timeRanges = [
{
label: __('30 minutes'),
......
---
title: Show symlink icon in repository browser
merge_request: 36524
author:
type: fixed
......@@ -8,6 +8,7 @@ exports[`Blob Header Filepath rendering matches the snapshot 1`] = `
<file-icon-stub
aria-hidden="true"
cssclasses="mr-2"
filemode=""
filename="foo/bar/dummy.md"
size="18"
/>
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Repository table row component renders a symlink table row 1`] = `
<tr
class="tree-item"
>
<td
class="tree-item-file-name cursor-default position-relative"
>
<a
class="tree-item-link str-truncated"
data-qa-selector="file_name_link"
href="https://test.com"
>
<file-icon-stub
class="mr-1 position-relative text-secondary"
cssclasses="position-relative file-icon"
filemode="120000"
filename="test"
size="16"
/>
<span
class="position-relative"
>
test
</span>
</a>
<!---->
<!---->
<!---->
</td>
<td
class="d-none d-sm-table-cell tree-commit cursor-default"
>
<gl-skeleton-loading-stub
class="h-auto"
lines="1"
/>
</td>
<td
class="tree-time-ago text-right cursor-default"
>
<gl-skeleton-loading-stub
class="ml-auto h-auto w-50"
lines="1"
/>
</td>
</tr>
`;
exports[`Repository table row component renders table row 1`] = `
<tr
class="tree-item"
......@@ -15,6 +68,7 @@ exports[`Repository table row component renders table row 1`] = `
<file-icon-stub
class="mr-1 position-relative text-secondary"
cssclasses="position-relative file-icon"
filemode=""
filename="test"
size="16"
/>
......@@ -67,6 +121,7 @@ exports[`Repository table row component renders table row for path with special
<file-icon-stub
class="mr-1 position-relative text-secondary"
cssclasses="position-relative file-icon"
filemode=""
filename="test"
size="16"
/>
......
......@@ -23,6 +23,15 @@ const MOCK_BLOBS = [
type: 'blob',
webUrl: 'http://test.com',
},
{
id: '125abc',
sha: '125abc',
flatPath: 'blob3',
name: 'blob3.md',
type: 'blob',
webUrl: 'http://test.com',
mode: '120000',
},
];
function factory({ path, isLoading = false, entries = {} }) {
......@@ -74,7 +83,9 @@ describe('Repository table component', () => {
},
});
expect(vm.find(TableRow).exists()).toBe(true);
expect(vm.findAll(TableRow).length).toBe(2);
const rows = vm.findAll(TableRow);
expect(rows.length).toEqual(3);
expect(rows.at(2).attributes().mode).toEqual('120000');
});
});
......@@ -2,6 +2,7 @@ import { shallowMount, RouterLinkStub } from '@vue/test-utils';
import { GlBadge, GlLink, GlIcon } from '@gitlab/ui';
import TableRow from '~/repository/components/table/row.vue';
import FileIcon from '~/vue_shared/components/file_icon.vue';
import { FILE_SYMLINK_MODE } from '~/vue_shared/constants';
let vm;
let $router;
......@@ -48,6 +49,21 @@ describe('Repository table row component', () => {
});
});
it('renders a symlink table row', () => {
factory({
id: '1',
sha: '123',
path: 'test',
type: 'blob',
currentPath: '/',
mode: FILE_SYMLINK_MODE,
});
return vm.vm.$nextTick().then(() => {
expect(vm.element).toMatchSnapshot();
});
});
it('renders table row for path with special character', () => {
factory({
id: '1',
......
import { shallowMount } from '@vue/test-utils';
import { GlLoadingIcon, GlIcon } from '@gitlab/ui';
import FileIcon from '~/vue_shared/components/file_icon.vue';
import { FILE_SYMLINK_MODE } from '~/vue_shared/constants';
describe('File Icon component', () => {
let wrapper;
const findIcon = () => wrapper.find('svg');
const findSvgIcon = () => wrapper.find('svg');
const findGlIcon = () => wrapper.find(GlIcon);
const getIconName = () =>
findIcon()
findSvgIcon()
.find('use')
.element.getAttribute('xlink:href')
.replace(`${gon.sprite_file_icons}#`, '');
......@@ -27,7 +29,7 @@ describe('File Icon component', () => {
});
expect(wrapper.element.tagName).toEqual('SPAN');
expect(findIcon().exists()).toBeDefined();
expect(findSvgIcon().exists()).toBeDefined();
});
it.each`
......@@ -46,8 +48,8 @@ describe('File Icon component', () => {
folder: true,
});
expect(findIcon().exists()).toBe(false);
expect(wrapper.find(GlIcon).classes()).toContain('folder-icon');
expect(findSvgIcon().exists()).toBe(false);
expect(findGlIcon().classes()).toContain('folder-icon');
});
it('should render a loading icon', () => {
......@@ -66,8 +68,19 @@ describe('File Icon component', () => {
cssClasses: 'extraclasses',
size,
});
const classes = findSvgIcon().classes();
expect(findIcon().classes()).toContain(`s${size}`);
expect(findIcon().classes()).toContain('extraclasses');
expect(classes).toContain(`s${size}`);
expect(classes).toContain('extraclasses');
});
it('should render a symlink icon', () => {
createComponent({
fileName: 'anything',
fileMode: FILE_SYMLINK_MODE,
});
expect(findSvgIcon().exists()).toBe(false);
expect(findGlIcon().attributes('name')).toBe('symlink');
});
});
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