Commit 98272880 authored by Paul Slaughter's avatar Paul Slaughter

Merge branch '198729-readd-diff-stats-to-tree-list' into 'master'

Re-add file stats to diff tree list

Closes #198729

See merge request gitlab-org/gitlab!24423
parents 65b8e37b 0def199d
...@@ -4,14 +4,34 @@ ...@@ -4,14 +4,34 @@
* https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23720 * https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23720
*/ */
import FileRow from '~/vue_shared/components/file_row.vue'; import FileRow from '~/vue_shared/components/file_row.vue';
import FileRowStats from './file_row_stats.vue';
export default { export default {
name: 'DiffFileRow',
components: { components: {
FileRow, FileRow,
FileRowStats,
},
props: {
file: {
type: Object,
required: true,
},
hideFileStats: {
type: Boolean,
required: true,
},
},
computed: {
showFileRowStats() {
return !this.hideFileStats && this.file.type === 'blob';
},
}, },
}; };
</script> </script>
<template> <template>
<file-row v-bind="$attrs" v-on="$listeners" /> <file-row :file="file" :hide-file-stats="hideFileStats" v-bind="$attrs" v-on="$listeners">
<file-row-stats v-if="showFileRowStats" :file="file" />
</file-row>
</template> </template>
...@@ -5,7 +5,6 @@ import { s__, sprintf } from '~/locale'; ...@@ -5,7 +5,6 @@ import { s__, sprintf } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import FileTree from '~/vue_shared/components/file_tree.vue'; import FileTree from '~/vue_shared/components/file_tree.vue';
import DiffFileRow from './diff_file_row.vue'; import DiffFileRow from './diff_file_row.vue';
import FileRowStats from './file_row_stats.vue';
export default { export default {
directives: { directives: {
...@@ -49,9 +48,6 @@ export default { ...@@ -49,9 +48,6 @@ export default {
return acc; return acc;
}, []); }, []);
}, },
fileRowExtraComponent() {
return this.hideFileStats ? null : FileRowStats;
},
}, },
methods: { methods: {
...mapActions('diffs', ['toggleTreeOpen', 'scrollToFile']), ...mapActions('diffs', ['toggleTreeOpen', 'scrollToFile']),
...@@ -98,8 +94,8 @@ export default { ...@@ -98,8 +94,8 @@ export default {
:key="file.key" :key="file.key"
:file="file" :file="file"
:level="0" :level="0"
:hide-file-stats="hideFileStats"
:hide-extra-on-tree="true" :hide-extra-on-tree="true"
:extra-component="fileRowExtraComponent"
:show-changed-icon="true" :show-changed-icon="true"
:file-row-component="$options.DiffFileRow" :file-row-component="$options.DiffFileRow"
@toggleTreeOpen="toggleTreeOpen" @toggleTreeOpen="toggleTreeOpen"
......
...@@ -4,14 +4,35 @@ ...@@ -4,14 +4,35 @@
* https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23720 * https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23720
*/ */
import FileRow from '~/vue_shared/components/file_row.vue'; import FileRow from '~/vue_shared/components/file_row.vue';
import FileRowExtra from './file_row_extra.vue';
export default { export default {
name: 'IdeFileRow',
components: { components: {
FileRow, FileRow,
FileRowExtra,
},
props: {
file: {
type: Object,
required: true,
},
},
data() {
return {
dropdownOpen: false,
};
},
methods: {
toggleDropdown(val) {
this.dropdownOpen = val;
},
}, },
}; };
</script> </script>
<template> <template>
<file-row v-bind="$attrs" v-on="$listeners" /> <file-row :file="file" v-bind="$attrs" @mouseleave="toggleDropdown(false)" v-on="$listeners">
<file-row-extra :file="file" :dropdown-open="dropdownOpen" @toggle="toggleDropdown($event)" />
</file-row>
</template> </template>
...@@ -4,7 +4,6 @@ import { GlSkeletonLoading } from '@gitlab/ui'; ...@@ -4,7 +4,6 @@ import { GlSkeletonLoading } from '@gitlab/ui';
import FileTree from '~/vue_shared/components/file_tree.vue'; import FileTree from '~/vue_shared/components/file_tree.vue';
import IdeFileRow from './ide_file_row.vue'; import IdeFileRow from './ide_file_row.vue';
import NavDropdown from './nav_dropdown.vue'; import NavDropdown from './nav_dropdown.vue';
import FileRowExtra from './file_row_extra.vue';
export default { export default {
components: { components: {
...@@ -36,7 +35,6 @@ export default { ...@@ -36,7 +35,6 @@ export default {
methods: { methods: {
...mapActions(['updateViewer', 'toggleTreeOpen']), ...mapActions(['updateViewer', 'toggleTreeOpen']),
}, },
FileRowExtra,
IdeFileRow, IdeFileRow,
}; };
</script> </script>
...@@ -60,7 +58,6 @@ export default { ...@@ -60,7 +58,6 @@ export default {
:key="file.key" :key="file.key"
:file="file" :file="file"
:level="0" :level="0"
:extra-component="$options.FileRowExtra"
:file-row-component="$options.IdeFileRow" :file-row-component="$options.IdeFileRow"
@toggleTreeOpen="toggleTreeOpen" @toggleTreeOpen="toggleTreeOpen"
/> />
......
<script> <script>
import Icon from '~/vue_shared/components/icon.vue';
import FileHeader from '~/vue_shared/components/file_row_header.vue'; import FileHeader from '~/vue_shared/components/file_row_header.vue';
import FileIcon from '~/vue_shared/components/file_icon.vue'; import FileIcon from '~/vue_shared/components/file_icon.vue';
import ChangedFileIcon from '~/vue_shared/components/changed_file_icon.vue'; import ChangedFileIcon from '~/vue_shared/components/changed_file_icon.vue';
...@@ -9,7 +8,6 @@ export default { ...@@ -9,7 +8,6 @@ export default {
components: { components: {
FileHeader, FileHeader,
FileIcon, FileIcon,
Icon,
ChangedFileIcon, ChangedFileIcon,
}, },
props: { props: {
...@@ -21,27 +19,12 @@ export default { ...@@ -21,27 +19,12 @@ export default {
type: Number, type: Number,
required: true, required: true,
}, },
extraComponent: {
type: Object,
required: false,
default: null,
},
hideExtraOnTree: {
type: Boolean,
required: false,
default: false,
},
showChangedIcon: { showChangedIcon: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false, default: false,
}, },
}, },
data() {
return {
dropdownOpen: false,
};
},
computed: { computed: {
isTree() { isTree() {
return this.file.type === 'tree'; return this.file.type === 'tree';
...@@ -120,9 +103,6 @@ export default { ...@@ -120,9 +103,6 @@ export default {
return this.$router.currentRoute.path === `/project${this.file.url}`; return this.$router.currentRoute.path === `/project${this.file.url}`;
}, },
toggleDropdown(val) {
this.dropdownOpen = val;
},
}, },
}; };
</script> </script>
...@@ -136,7 +116,7 @@ export default { ...@@ -136,7 +116,7 @@ export default {
class="file-row" class="file-row"
role="button" role="button"
@click="clickFile" @click="clickFile"
@mouseleave="toggleDropdown(false)" @mouseleave="$emit('mouseleave', $event)"
> >
<div class="file-row-name-container"> <div class="file-row-name-container">
<span ref="textOutput" :style="levelIndentation" class="file-row-name str-truncated"> <span ref="textOutput" :style="levelIndentation" class="file-row-name str-truncated">
...@@ -152,13 +132,7 @@ export default { ...@@ -152,13 +132,7 @@ export default {
<changed-file-icon v-else :file="file" :size="16" class="append-right-5" /> <changed-file-icon v-else :file="file" :size="16" class="append-right-5" />
{{ file.name }} {{ file.name }}
</span> </span>
<component <slot></slot>
:is="extraComponent"
v-if="extraComponent && !(hideExtraOnTree && file.type === 'tree')"
:file="file"
:dropdown-open="dropdownOpen"
@toggle="toggleDropdown($event)"
/>
</div> </div>
</div> </div>
</template> </template>
......
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import DiffFileRow from '~/diffs/components/diff_file_row.vue'; import DiffFileRow from '~/diffs/components/diff_file_row.vue';
import FileRow from '~/vue_shared/components/file_row.vue'; import FileRow from '~/vue_shared/components/file_row.vue';
import FileRowStats from '~/diffs/components/file_row_stats.vue';
describe('Diff File Row component', () => { describe('Diff File Row component', () => {
let wrapper; let wrapper;
...@@ -16,10 +17,42 @@ describe('Diff File Row component', () => { ...@@ -16,10 +17,42 @@ describe('Diff File Row component', () => {
}); });
it('renders file row component', () => { it('renders file row component', () => {
createComponent({ const sharedProps = {
level: 4, level: 4,
file: {}, file: {},
};
const diffFileRowProps = {
hideFileStats: false,
};
createComponent({
...sharedProps,
...diffFileRowProps,
});
expect(wrapper.find(FileRow).props()).toEqual(
expect.objectContaining({
...sharedProps,
}),
);
});
describe('FileRowStats components', () => {
it.each`
type | hideFileStats | value | desc
${'blob'} | ${false} | ${true} | ${'is shown if file type is blob'}
${'tree'} | ${false} | ${false} | ${'is hidden if file is not blob'}
${'blob'} | ${true} | ${false} | ${'is hidden if hideFileStats is true'}
`('$desc', ({ type, value, hideFileStats }) => {
createComponent({
level: 4,
file: {
type,
},
hideFileStats,
});
expect(wrapper.find(FileRowStats).exists()).toEqual(value);
}); });
expect(wrapper.find(FileRow).exists()).toEqual(true);
}); });
}); });
Element.prototype.scrollIntoView = jest.fn();
import './element_scroll_into_view';
import './get_client_rects'; import './get_client_rects';
import './inner_text'; import './inner_text';
import './window_scroll_to'; import './window_scroll_to';
import { shallowMount } from '@vue/test-utils'; import { createLocalVue, mount } from '@vue/test-utils';
import Vuex from 'vuex';
import IdeFileRow from '~/ide/components/ide_file_row.vue'; import IdeFileRow from '~/ide/components/ide_file_row.vue';
import FileRow from '~/vue_shared/components/file_row.vue'; import FileRow from '~/vue_shared/components/file_row.vue';
import FileRowExtra from '~/ide/components/file_row_extra.vue';
import { createStore } from '~/ide/stores';
const localVue = createLocalVue();
localVue.use(Vuex);
const TEST_EXTRA_PROPS = {
testattribute: 'abc',
};
const defaultComponentProps = (type = 'tree') => ({
level: 4,
file: {
type,
name: 'js',
},
});
describe('Ide File Row component', () => { describe('Ide File Row component', () => {
let wrapper; let wrapper;
const createComponent = (props = {}) => { const createComponent = (props = {}, options = {}) => {
wrapper = shallowMount(IdeFileRow, { wrapper = mount(IdeFileRow, {
propsData: { ...props }, propsData: {
...defaultComponentProps(),
...props,
},
store: createStore(),
localVue,
...options,
}); });
}; };
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
wrapper = null;
}); });
it('renders file row component', () => { const findFileRowExtra = () => wrapper.find(FileRowExtra);
createComponent({ const findFileRow = () => wrapper.find(FileRow);
level: 4, const hasDropdownOpen = () => findFileRowExtra().props('dropdownOpen');
file: {},
it('fileRow component has listeners', () => {
const toggleTreeOpen = jest.fn();
createComponent(
{},
{
listeners: {
toggleTreeOpen,
},
},
);
findFileRow().vm.$emit('toggleTreeOpen');
return wrapper.vm.$nextTick().then(() => {
expect(toggleTreeOpen).toHaveBeenCalled();
});
});
describe('default', () => {
beforeEach(() => {
createComponent(TEST_EXTRA_PROPS);
});
it('renders file row component', () => {
const fileRow = findFileRow();
expect(fileRow.props()).toEqual(expect.objectContaining(defaultComponentProps()));
expect(fileRow.attributes()).toEqual(expect.objectContaining(TEST_EXTRA_PROPS));
});
it('renders file row extra', () => {
const extra = findFileRowExtra();
expect(extra.exists()).toBe(true);
expect(extra.props()).toEqual({
file: defaultComponentProps().file,
dropdownOpen: false,
});
});
});
describe('with open dropdown', () => {
beforeEach(() => {
createComponent();
findFileRowExtra().vm.$emit('toggle', true);
return wrapper.vm.$nextTick();
});
it('shows open dropdown', () => {
expect(hasDropdownOpen()).toBe(true);
});
it('hides dropdown when mouseleave', () => {
findFileRow().vm.$emit('mouseleave');
return wrapper.vm.$nextTick().then(() => {
expect(hasDropdownOpen()).toEqual(false);
});
});
it('hides dropdown on toggle', () => {
findFileRowExtra().vm.$emit('toggle', false);
return wrapper.vm.$nextTick().then(() => {
expect(hasDropdownOpen()).toEqual(false);
});
}); });
expect(wrapper.find(FileRow).exists()).toEqual(true);
}); });
}); });
import Vue from 'vue'; import Vue from 'vue';
import { file } from 'spec/ide/helpers'; import { file } from 'spec/ide/helpers';
import FileRow from '~/vue_shared/components/file_row.vue'; import FileRow from '~/vue_shared/components/file_row.vue';
import FileRowExtra from '~/ide/components/file_row_extra.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from '../../helpers/vue_mount_component_helper';
describe('File row component', () => { describe('File row component', () => {
...@@ -17,9 +16,6 @@ describe('File row component', () => { ...@@ -17,9 +16,6 @@ describe('File row component', () => {
vm.$destroy(); vm.$destroy();
}); });
const findNewDropdown = () => vm.$el.querySelector('.ide-new-btn .dropdown');
const findNewDropdownButton = () => vm.$el.querySelector('.ide-new-btn .dropdown button');
it('renders name', () => { it('renders name', () => {
createComponent({ createComponent({
file: file('t4'), file: file('t4'),
...@@ -88,59 +84,4 @@ describe('File row component', () => { ...@@ -88,59 +84,4 @@ describe('File row component', () => {
expect(vm.$el.classList).toContain('js-file-row-header'); expect(vm.$el.classList).toContain('js-file-row-header');
}); });
describe('new dropdown', () => {
beforeEach(() => {
createComponent({
file: file('t5'),
level: 1,
extraComponent: FileRowExtra,
});
});
it('renders in extra component', () => {
expect(findNewDropdown()).not.toBe(null);
});
it('is hidden at start', () => {
expect(findNewDropdown()).not.toHaveClass('show');
});
it('is opened when button is clicked', done => {
expect(vm.dropdownOpen).toBe(false);
findNewDropdownButton().dispatchEvent(new Event('click'));
vm.$nextTick()
.then(() => {
expect(vm.dropdownOpen).toBe(true);
expect(findNewDropdown()).toHaveClass('show');
})
.then(done)
.catch(done.fail);
});
describe('when opened', () => {
beforeEach(() => {
vm.dropdownOpen = true;
});
it('stays open when button triggers mouseout', () => {
findNewDropdownButton().dispatchEvent(new Event('mouseout'));
expect(vm.dropdownOpen).toBe(true);
});
it('stays open when button triggers mouseleave', () => {
findNewDropdownButton().dispatchEvent(new Event('mouseleave'));
expect(vm.dropdownOpen).toBe(true);
});
it('closes when row triggers mouseleave', () => {
vm.$el.dispatchEvent(new Event('mouseleave'));
expect(vm.dropdownOpen).toBe(false);
});
});
});
}); });
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