Skip to content
代码片段 群组 项目
提交 fcc0eae2 编辑于 作者: Jacques Erasmus's avatar Jacques Erasmus 提交者: Olena Horal-Koretska
浏览文件

Create blame info into Vue component

Creates a Vue component for blame info
上级 528bed65
No related branches found
No related tags found
无相关合并请求
......@@ -53,7 +53,7 @@ export default {
</script>
<template>
<div class="well-segment commit gl-min-h-8 gl-p-5 gl-w-full gl-display-flex">
<div class="well-segment commit gl-min-h-8 gl-p-2 gl-w-full gl-display-flex">
<user-avatar-link
v-if="commit.author"
:link-href="commit.author.webPath"
......
<script>
import { GlTooltipDirective } from '@gitlab/ui';
import SafeHtml from '~/vue_shared/directives/safe_html';
import CommitInfo from '~/repository/components/commit_info.vue';
import { calculateBlameOffset, toggleBlameClasses } from '../utils';
export default {
name: 'BlameInfo',
components: {
CommitInfo,
},
directives: {
GlTooltip: GlTooltipDirective,
SafeHtml,
},
props: {
blameData: {
type: Array,
required: true,
},
},
computed: {
blameInfo() {
return this.blameData.map((blame, index) => ({
...blame,
blameOffset: calculateBlameOffset(blame.lineno, index),
}));
},
},
mounted() {
toggleBlameClasses(this.blameData, true);
},
destroyed() {
toggleBlameClasses(this.blameData, false);
},
};
</script>
<template>
<div class="blame gl-bg-gray-10">
<div class="blame-commit gl-border-none!">
<commit-info
v-for="(blame, index) in blameInfo"
:key="index"
:class="{ 'gl-border-t': index !== 0 }"
class="gl-display-flex gl-absolute gl-px-3"
:style="{ top: blame.blameOffset }"
:commit="blame.commit"
/>
</div>
</div>
</template>
const BLAME_INFO_CLASSLIST = ['gl-border-t', 'gl-border-gray-500', 'gl-pt-3!'];
const PADDING_BOTTOM_LARGE = 'gl-pb-6!';
const PADDING_BOTTOM_SMALL = 'gl-pb-3!';
const findLineNumberElement = (lineNumber) => document.getElementById(`L${lineNumber}`);
const findLineContentElement = (lineNumber) => document.getElementById(`LC${lineNumber}`);
export const calculateBlameOffset = (lineNumber) => {
if (lineNumber === 1) return '0px';
const lineContentOffset = findLineContentElement(lineNumber)?.offsetTop;
return `${lineContentOffset}px`;
};
export const toggleBlameClasses = (blameData, isVisible) => {
/**
* Adds/removes classes to line number/content elements to match the line with the blame info
* */
const method = isVisible ? 'add' : 'remove';
blameData.forEach(({ lineno, span }) => {
const lineNumberEl = findLineNumberElement(lineno)?.parentElement;
const lineContentEl = findLineContentElement(lineno);
const lineNumberSpanEl = findLineNumberElement(lineno + span - 1)?.parentElement;
const lineContentSpanEl = findLineContentElement(lineno + span - 1);
lineNumberEl?.classList[method](...BLAME_INFO_CLASSLIST);
lineContentEl?.classList[method](...BLAME_INFO_CLASSLIST);
if (span === 1) {
lineNumberSpanEl?.classList[method](PADDING_BOTTOM_LARGE);
lineContentSpanEl?.classList[method](PADDING_BOTTOM_LARGE);
} else {
lineNumberSpanEl?.classList[method](PADDING_BOTTOM_SMALL);
lineContentSpanEl?.classList[method](PADDING_BOTTOM_SMALL);
}
});
};
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`SourceViewer utils toggleBlameClasses adds classes 1`] = `
<div
class="content"
>
<div
class="gl-border-gray-500 gl-border-t gl-pt-3!"
>
<div
id="reference-0"
>
1
</div>
<div
id="reference-1"
>
2
</div>
<div
id="reference-2"
>
3
</div>
</div>
<div>
<div
class="gl-border-gray-500 gl-border-t gl-pt-3!"
id="reference-3"
>
Content 1
</div>
<div
class="gl-border-gray-500 gl-border-t gl-pt-3!"
id="reference-4"
>
Content 2
</div>
<div
class="gl-border-gray-500 gl-border-t gl-pt-3!"
id="reference-5"
>
Content 3
</div>
</div>
</div>
`;
exports[`SourceViewer utils toggleBlameClasses removes classes 1`] = `
<div
class="content"
>
<div>
<div
id="reference-0"
>
1
</div>
<div
id="reference-1"
>
2
</div>
<div
id="reference-2"
>
3
</div>
</div>
<div>
<div
id="reference-3"
>
Content 1
</div>
<div
id="reference-4"
>
Content 2
</div>
<div
id="reference-5"
>
Content 3
</div>
</div>
</div>
`;
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { setHTMLFixture } from 'helpers/fixtures';
import CommitInfo from '~/repository/components/commit_info.vue';
import BlameInfo from '~/vue_shared/components/source_viewer/components/blame_info.vue';
import * as utils from '~/vue_shared/components/source_viewer/utils';
import { SOURCE_CODE_CONTENT_MOCK, BLAME_DATA_MOCK } from '../mock_data';
describe('BlameInfo component', () => {
let wrapper;
const createComponent = () => {
wrapper = shallowMountExtended(BlameInfo, {
propsData: { blameData: BLAME_DATA_MOCK },
});
};
beforeEach(() => {
setHTMLFixture(SOURCE_CODE_CONTENT_MOCK);
jest.spyOn(utils, 'toggleBlameClasses');
createComponent();
});
const findCommitInfoComponents = () => wrapper.findAllComponents(CommitInfo);
it('adds the necessary classes to the DOM', () => {
expect(utils.toggleBlameClasses).toHaveBeenCalledWith(BLAME_DATA_MOCK, true);
});
it('renders a CommitInfo component for each blame entry', () => {
expect(findCommitInfoComponents().length).toBe(BLAME_DATA_MOCK.length);
});
it.each(BLAME_DATA_MOCK)(
'sets the correct data and positioning for the commitInfo',
({ lineno, commit, index }) => {
const commitInfoComponent = findCommitInfoComponents().at(index);
expect(commitInfoComponent.props('commit')).toEqual(commit);
expect(commitInfoComponent.element.style.top).toBe(utils.calculateBlameOffset(lineno));
},
);
describe('commitInfo component styling', () => {
const borderTopClassName = 'gl-border-t';
it('does not add a top border for the first entry', () => {
expect(findCommitInfoComponents().at(0).element.classList).not.toContain(borderTopClassName);
});
it('add a top border for the rest of the entries', () => {
expect(findCommitInfoComponents().at(1).element.classList).toContain(borderTopClassName);
expect(findCommitInfoComponents().at(2).element.classList).toContain(borderTopClassName);
});
});
describe('when component is destroyed', () => {
beforeEach(() => wrapper.destroy());
it('resets the DOM to its original state', () => {
expect(utils.toggleBlameClasses).toHaveBeenCalledWith(BLAME_DATA_MOCK, false);
});
});
});
......@@ -22,3 +22,24 @@ export const CHUNK_2 = {
startingFrom: 70,
blamePath,
};
export const SOURCE_CODE_CONTENT_MOCK = `
<div class="content">
<div>
<div id="L1">1</div>
<div id="L2">2</div>
<div id="L3">3</div>
</div>
<div>
<div id="LC1">Content 1</div>
<div id="LC2">Content 2</div>
<div id="LC3">Content 3</div>
</div>
</div>`;
export const BLAME_DATA_MOCK = [
{ lineno: 1, commit: { author: 'Peter' }, index: 0 },
{ lineno: 2, commit: { author: 'Sarah' }, index: 1 },
{ lineno: 3, commit: { author: 'Peter' }, index: 2 },
];
import { setHTMLFixture } from 'helpers/fixtures';
import {
calculateBlameOffset,
toggleBlameClasses,
} from '~/vue_shared/components/source_viewer/utils';
import { SOURCE_CODE_CONTENT_MOCK, BLAME_DATA_MOCK } from './mock_data';
describe('SourceViewer utils', () => {
beforeEach(() => setHTMLFixture(SOURCE_CODE_CONTENT_MOCK));
const findContent = () => document.querySelector('.content');
describe('calculateBlameOffset', () => {
it('returns an offset of zero if line number === 1', () => {
expect(calculateBlameOffset(1)).toBe('0px');
});
it('calculates an offset for the blame component', () => {
const { offsetTop } = document.querySelector('#LC3');
expect(calculateBlameOffset(3)).toBe(`${offsetTop}px`);
});
});
describe('toggleBlameClasses', () => {
it('adds classes', () => {
toggleBlameClasses(BLAME_DATA_MOCK, true);
expect(findContent()).toMatchSnapshot();
});
it('removes classes', () => {
toggleBlameClasses(BLAME_DATA_MOCK, false);
expect(findContent()).toMatchSnapshot();
});
});
});
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册