Merge branch '66454-base-components' into 'master'
Creates base components for new job log See merge request gitlab-org/gitlab-ce!32543
This commit is contained in:
commit
c65cdb4a14
7 changed files with 303 additions and 0 deletions
28
app/assets/javascripts/jobs/components/log/line.vue
Normal file
28
app/assets/javascripts/jobs/components/log/line.vue
Normal 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>
|
45
app/assets/javascripts/jobs/components/log/line_header.vue
Normal file
45
app/assets/javascripts/jobs/components/log/line_header.vue
Normal 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>
|
52
app/assets/javascripts/jobs/components/log/line_number.vue
Normal file
52
app/assets/javascripts/jobs/components/log/line_number.vue
Normal 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>
|
5
changelogs/unreleased/66454-base-components.yml
Normal file
5
changelogs/unreleased/66454-base-components.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Creates base components for the new job log
|
||||
merge_request:
|
||||
author:
|
||||
type: added
|
84
spec/javascripts/jobs/components/log/line_header_spec.js
Normal file
84
spec/javascripts/jobs/components/log/line_header_spec.js
Normal 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);
|
||||
});
|
||||
});
|
||||
});
|
40
spec/javascripts/jobs/components/log/line_number_spec.js
Normal file
40
spec/javascripts/jobs/components/log/line_number_spec.js
Normal 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`);
|
||||
});
|
||||
});
|
49
spec/javascripts/jobs/components/log/line_spec.js
Normal file
49
spec/javascripts/jobs/components/log/line_spec.js
Normal 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);
|
||||
});
|
||||
});
|
Loading…
Reference in a new issue