Creates base components for new job log

Creates a link component, a line component and
a clickable line component to handle the
new job log format
This commit is contained in:
Filipa Lacerda 2019-09-04 14:10:29 +00:00 committed by Kushal Pandya
parent 0da3257c35
commit be449e23e3
7 changed files with 303 additions and 0 deletions

View File

@ -0,0 +1,28 @@
<script>
import LineNumber from './line_number.vue';
export default {
components: {
LineNumber,
},
props: {
line: {
type: Object,
required: true,
},
path: {
type: String,
required: true,
},
},
};
</script>
<template>
<div class="line">
<line-number :line-number="line.lineNumber" :path="path" />
<span v-for="(content, i) in line.content" :key="i" class="line-text" :class="content.style">{{
content.text
}}</span>
</div>
</template>

View File

@ -0,0 +1,45 @@
<script>
import Icon from '~/vue_shared/components/icon.vue';
import LineNumber from './line_number.vue';
export default {
components: {
Icon,
LineNumber,
},
props: {
line: {
type: Object,
required: true,
},
isClosed: {
type: Boolean,
required: true,
},
path: {
type: String,
required: true,
},
},
computed: {
iconName() {
return this.isClosed ? 'angle-right' : 'angle-down';
},
},
methods: {
handleOnClick() {
this.$emit('toggleLine');
},
},
};
</script>
<template>
<div class="line collapsible-line" role="button" @click="handleOnClick">
<icon :name="iconName" class="arrow" />
<line-number :line-number="line.lineNumber" :path="path" />
<span v-for="(content, i) in line.content" :key="i" class="line-text" :class="content.style">{{
content.text
}}</span>
</div>
</template>

View File

@ -0,0 +1,52 @@
<script>
import { GlLink } from '@gitlab/ui';
export default {
components: {
GlLink,
},
props: {
lineNumber: {
type: Number,
required: true,
},
path: {
type: String,
required: true,
},
},
computed: {
/**
* Builds the url for each line number
*
* @returns {String}
*/
buildLineNumber() {
return `${this.path}#${this.lineNumberId}`;
},
/**
* Array indexes start with 0, so we add 1
* to create the line number
*
* @returns {Number} the line number
*/
parsedLineNumber() {
return this.lineNumber + 1;
},
/**
* Creates the anchor for each link
*
* @returns {String}
*/
lineNumberId() {
return `L${this.parsedLineNumber}`;
},
},
};
</script>
<template>
<gl-link :id="lineNumberId" class="line-number" :href="buildLineNumber">{{
parsedLineNumber
}}</gl-link>
</template>

View File

@ -0,0 +1,5 @@
---
title: Creates base components for the new job log
merge_request:
author:
type: added

View File

@ -0,0 +1,84 @@
import { mount } from '@vue/test-utils';
import LineHeader from '~/jobs/components/log/line_header.vue';
import LineNumber from '~/jobs/components/log/line_number.vue';
describe('Job Log Header Line', () => {
let wrapper;
const data = {
line: {
content: [
{
text: 'Running with gitlab-runner 12.1.0 (de7731dd)',
style: 'term-fg-l-green',
},
],
lineNumber: 0,
},
isClosed: true,
path: '/jashkenas/underscore/-/jobs/335',
};
const createComponent = (props = {}) => {
wrapper = mount(LineHeader, {
sync: false,
propsData: {
...props,
},
});
};
afterEach(() => {
wrapper.destroy();
});
describe('line', () => {
beforeEach(() => {
createComponent(data);
});
it('renders the line number component', () => {
expect(wrapper.contains(LineNumber)).toBe(true);
});
it('renders a span the provided text', () => {
expect(wrapper.find('span').text()).toBe(data.line.content[0].text);
});
it('renders the provided style as a class attribute', () => {
expect(wrapper.find('span').classes()).toContain(data.line.content[0].style);
});
});
describe('when isCloses is true', () => {
beforeEach(() => {
createComponent({ ...data, isClosed: true });
});
it('sets icon name to be angle-right', () => {
expect(wrapper.vm.iconName).toEqual('angle-right');
});
});
describe('when isCloses is false', () => {
beforeEach(() => {
createComponent({ ...data, isClosed: false });
});
it('sets icon name to be angle-down', () => {
expect(wrapper.vm.iconName).toEqual('angle-down');
});
});
describe('on click', () => {
beforeEach(() => {
createComponent(data);
});
it('emits toggleLine event', () => {
wrapper.trigger('click');
expect(wrapper.emitted().toggleLine.length).toBe(1);
});
});
});

View File

@ -0,0 +1,40 @@
import { shallowMount } from '@vue/test-utils';
import LineNumber from '~/jobs/components/log/line_number.vue';
describe('Job Log Line Number', () => {
let wrapper;
const data = {
lineNumber: 0,
path: '/jashkenas/underscore/-/jobs/335',
};
const createComponent = (props = {}) => {
wrapper = shallowMount(LineNumber, {
sync: false,
propsData: {
...props,
},
});
};
beforeEach(() => {
createComponent(data);
});
afterEach(() => {
wrapper.destroy();
});
it('renders incremented lineNunber by 1', () => {
expect(wrapper.text()).toBe('1');
});
it('renders link with lineNumber as an ID', () => {
expect(wrapper.attributes().id).toBe('L1');
});
it('links to the provided path with line number as anchor', () => {
expect(wrapper.attributes().href).toBe(`${data.path}#L1`);
});
});

View File

@ -0,0 +1,49 @@
import { shallowMount } from '@vue/test-utils';
import Line from '~/jobs/components/log/line.vue';
import LineNumber from '~/jobs/components/log/line_number.vue';
describe('Job Log Line', () => {
let wrapper;
const data = {
line: {
content: [
{
text: 'Running with gitlab-runner 12.1.0 (de7731dd)',
style: 'term-fg-l-green',
},
],
lineNumber: 0,
},
path: '/jashkenas/underscore/-/jobs/335',
};
const createComponent = (props = {}) => {
wrapper = shallowMount(Line, {
sync: false,
propsData: {
...props,
},
});
};
beforeEach(() => {
createComponent(data);
});
afterEach(() => {
wrapper.destroy();
});
it('renders the line number component', () => {
expect(wrapper.contains(LineNumber)).toBe(true);
});
it('renders a span the provided text', () => {
expect(wrapper.find('span').text()).toBe(data.line.content[0].text);
});
it('renders the provided style as a class attribute', () => {
expect(wrapper.find('span').classes()).toContain(data.line.content[0].style);
});
});