Commit 7c1cfd0b authored by Phil Hughes's avatar Phil Hughes

Merge branch '50904-api-adjustments-components' into 'master'

Updates Vue job components to match new API

See merge request gitlab-org/gitlab-ce!21930
parents b42e7740 90e0709d
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
validator(value) { validator(value) {
return ( return (
value === null || value === null ||
(Object.prototype.hasOwnProperty.call(value, 'link') && (Object.prototype.hasOwnProperty.call(value, 'path') &&
Object.prototype.hasOwnProperty.call(value, 'method') && Object.prototype.hasOwnProperty.call(value, 'method') &&
Object.prototype.hasOwnProperty.call(value, 'title')) Object.prototype.hasOwnProperty.call(value, 'title'))
); );
...@@ -63,7 +63,7 @@ ...@@ -63,7 +63,7 @@
class="text-center" class="text-center"
> >
<a <a
:href="action.link" :href="action.path"
:data-method="action.method" :data-method="action.method"
class="js-job-empty-state-action btn btn-primary" class="js-job-empty-state-action btn btn-primary"
> >
......
<script> <script>
import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; import _ from 'underscore';
import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
export default { export default {
components: { components: {
TimeagoTooltip, TimeagoTooltip,
}, },
props: { props: {
erasedByUser: { user: {
type: Boolean, type: Object,
required: true,
},
username: {
type: String,
required: false,
default: null,
},
linkToUser: {
type: String,
required: false, required: false,
default: null, default: () => ({}),
}, },
erasedAt: { erasedAt: {
type: String, type: String,
required: true, required: true,
}, },
}, },
}; computed: {
isErasedByUser() {
return !_.isEmpty(this.user);
},
},
};
</script> </script>
<template> <template>
<div class="prepend-top-default js-build-erased"> <div class="prepend-top-default js-build-erased">
<div class="erased alert alert-warning"> <div class="erased alert alert-warning">
<template v-if="erasedByUser"> <template v-if="isErasedByUser">
{{ s__("Job|Job has been erased by") }} {{ s__("Job|Job has been erased by") }}
<a :href="linkToUser"> <a :href="user.web_url">
{{ username }} {{ user.username }}
</a> </a>
</template> </template>
<template v-else> <template v-else>
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
type: String, type: String,
required: true, required: true,
}, },
isReceivingBuildTrace: { isComplete: {
type: Boolean, type: Boolean,
required: true, required: true,
}, },
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
</code> </code>
<div <div
v-if="isReceivingBuildTrace" v-if="isComplete"
class="js-log-animation build-loader-animation" class="js-log-animation build-loader-animation"
> >
<div class="dot"></div> <div class="dot"></div>
......
<script> <script>
import { polyfillSticky } from '~/lib/utils/sticky';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
import { numberToHumanSize } from '~/lib/utils/number_utils'; import { numberToHumanSize } from '~/lib/utils/number_utils';
import { s__, sprintf } from '~/locale'; import { sprintf } from '~/locale';
export default { export default {
components: { components: {
...@@ -12,44 +13,48 @@ ...@@ -12,44 +13,48 @@
tooltip, tooltip,
}, },
props: { props: {
canEraseJob: { erasePath: {
type: Boolean, type: String,
required: true, required: false,
default: null,
}, },
size: { size: {
type: Number, type: Number,
required: true, required: true,
}, },
rawTracePath: { rawPath: {
type: String, type: String,
required: false, required: false,
default: null, default: null,
}, },
canScrollToTop: { isScrollTopDisabled: {
type: Boolean, type: Boolean,
required: true, required: true,
}, },
canScrollToBottom: { isScrollBottomDisabled: {
type: Boolean,
required: true,
},
isScrollingDown: {
type: Boolean,
required: true,
},
isTraceSizeVisible: {
type: Boolean, type: Boolean,
required: true, required: true,
}, },
}, },
computed: { computed: {
jobLogSize() { jobLogSize() {
return sprintf('Showing last %{startSpanTag} %{size} %{endSpanTag} of log -', { return sprintf('Showing last %{size} of log -', {
startSpanTag: '<span class="s-truncated-info-size truncated-info-size">',
endSpanTag: '</span>',
size: numberToHumanSize(this.size), size: numberToHumanSize(this.size),
}); });
}, },
}, },
methods: { mounted() {
handleEraseJobClick() { polyfillSticky(this.$el);
// eslint-disable-next-line no-alert
if (window.confirm(s__('Job|Are you sure you want to erase this job?'))) {
this.$emit('eraseJob');
}
}, },
methods: {
handleScrollToTop() { handleScrollToTop() {
this.$emit('scrollJobLogTop'); this.$emit('scrollJobLogTop');
}, },
...@@ -57,48 +62,52 @@ ...@@ -57,48 +62,52 @@
this.$emit('scrollJobLogBottom'); this.$emit('scrollJobLogBottom');
}, },
}, },
}; };
</script> </script>
<template> <template>
<div class="top-bar"> <div class="top-bar">
<!-- truncate information --> <!-- truncate information -->
<div class="js-truncated-info truncated-info d-none d-sm-block float-left"> <div class="js-truncated-info truncated-info d-none d-sm-block float-left">
<p v-html="jobLogSize"></p> <template v-if="isTraceSizeVisible">
{{ jobLogSize }}
<a <a
v-if="rawTracePath" v-if="rawPath"
:href="rawTracePath" :href="rawPath"
class="js-raw-link raw-link" class="js-raw-link raw-link"
> >
{{ s__("Job|Complete Raw") }} {{ s__("Job|Complete Raw") }}
</a> </a>
</template>
</div> </div>
<!-- eo truncate information --> <!-- eo truncate information -->
<div class="controllers float-right"> <div class="controllers float-right">
<!-- links --> <!-- links -->
<a <a
v-if="rawTracePath" v-if="rawPath"
v-tooltip v-tooltip
:title="s__('Job|Show complete raw')" :title="s__('Job|Show complete raw')"
:href="rawTracePath" :href="rawPath"
class="js-raw-link-controller controllers-buttons" class="js-raw-link-controller controllers-buttons"
data-container="body" data-container="body"
> >
<icon name="doc-text" /> <icon name="doc-text" />
</a> </a>
<button <a
v-if="canEraseJob" v-if="erasePath"
v-tooltip v-tooltip
:title="s__('Job|Erase job log')" :title="s__('Job|Erase job log')"
type="button" :href="erasePath"
data-confirm="__('Are you sure you want to erase this build?')"
class="js-erase-link controllers-buttons" class="js-erase-link controllers-buttons"
data-container="body" data-container="body"
@click="handleEraseJobClick" data-method="post"
> >
<icon name="remove" /> <icon name="remove" />
</button> </a>
<!-- eo links --> <!-- eo links -->
<!-- scroll buttons --> <!-- scroll buttons -->
...@@ -109,7 +118,7 @@ ...@@ -109,7 +118,7 @@
data-container="body" data-container="body"
> >
<button <button
:disabled="!canScrollToTop" :disabled="isScrollTopDisabled"
type="button" type="button"
class="js-scroll-top btn-scroll btn-transparent btn-blank" class="js-scroll-top btn-scroll btn-transparent btn-blank"
@click="handleScrollToTop" @click="handleScrollToTop"
...@@ -125,9 +134,10 @@ ...@@ -125,9 +134,10 @@
data-container="body" data-container="body"
> >
<button <button
:disabled="!canScrollToBottom" :disabled="isScrollBottomDisabled"
type="button" type="button"
class="js-scroll-bottom btn-scroll btn-transparent btn-blank" class="js-scroll-bottom btn-scroll btn-transparent btn-blank"
:class="{ animate: isScrollingDown }"
@click="handleScrollToBottom" @click="handleScrollToBottom"
> >
<icon name="scroll_down"/> <icon name="scroll_down"/>
......
...@@ -24,14 +24,14 @@ export default { ...@@ -24,14 +24,14 @@ export default {
<div class="bs-callout bs-callout-warning"> <div class="bs-callout bs-callout-warning">
<p <p
v-if="hasNoRunnersForProject" v-if="hasNoRunnersForProject"
class="js-stuck-no-runners" class="js-stuck-no-runners append-bottom-0"
> >
{{ s__(`Job|This job is stuck, because the project {{ s__(`Job|This job is stuck, because the project
doesn't have any runners online assigned to it.`) }} doesn't have any runners online assigned to it.`) }}
</p> </p>
<p <p
v-else-if="tags.length" v-else-if="tags.length"
class="js-stuck-with-tags" class="js-stuck-with-tags append-bottom-0"
> >
{{ s__(`This job is stuck, because you don't have {{ s__(`This job is stuck, because you don't have
any active runners online with any of these tags assigned to them:`) }} any active runners online with any of these tags assigned to them:`) }}
...@@ -45,7 +45,7 @@ export default { ...@@ -45,7 +45,7 @@ export default {
</p> </p>
<p <p
v-else v-else
class="js-stuck-no-active-runner" class="js-stuck-no-active-runner append-bottom-0"
> >
{{ s__(`This job is stuck, because you don't {{ s__(`This job is stuck, because you don't
have any active runners that can run this job.`) }} have any active runners that can run this job.`) }}
......
...@@ -3338,9 +3338,6 @@ msgstr "" ...@@ -3338,9 +3338,6 @@ msgstr ""
msgid "Jobs" msgid "Jobs"
msgstr "" msgstr ""
msgid "Job|Are you sure you want to erase this job?"
msgstr ""
msgid "Job|Browse" msgid "Job|Browse"
msgstr "" msgstr ""
......
...@@ -66,7 +66,7 @@ describe('Empty State', () => { ...@@ -66,7 +66,7 @@ describe('Empty State', () => {
...props, ...props,
content, content,
action: { action: {
link: 'runner', path: 'runner',
title: 'Check runner', title: 'Check runner',
method: 'post', method: 'post',
}, },
......
...@@ -18,9 +18,10 @@ describe('Erased block', () => { ...@@ -18,9 +18,10 @@ describe('Erased block', () => {
describe('with job erased by user', () => { describe('with job erased by user', () => {
beforeEach(() => { beforeEach(() => {
vm = mountComponent(Component, { vm = mountComponent(Component, {
erasedByUser: true, user: {
username: 'root', username: 'root',
linkToUser: 'gitlab.com/root', web_url: 'gitlab.com/root',
},
erasedAt, erasedAt,
}); });
}); });
...@@ -40,7 +41,6 @@ describe('Erased block', () => { ...@@ -40,7 +41,6 @@ describe('Erased block', () => {
describe('with erased job', () => { describe('with erased job', () => {
beforeEach(() => { beforeEach(() => {
vm = mountComponent(Component, { vm = mountComponent(Component, {
erasedByUser: false,
erasedAt, erasedAt,
}); });
}); });
......
...@@ -10,18 +10,21 @@ describe('Job log controllers', () => { ...@@ -10,18 +10,21 @@ describe('Job log controllers', () => {
vm.$destroy(); vm.$destroy();
}); });
describe('Truncate information', () => { const props = {
rawPath: '/raw',
erasePath: '/erase',
size: 511952,
isScrollTopDisabled: false,
isScrollBottomDisabled: false,
isScrollingDown: true,
isTraceSizeVisible: true,
};
describe('Truncate information', () => {
describe('with isTraceSizeVisible', () => {
beforeEach(() => { beforeEach(() => {
vm = mountComponent(Component, { vm = mountComponent(Component, props);
rawTracePath: '/raw',
canEraseJob: true,
size: 511952,
canScrollToTop: true,
canScrollToBottom: true,
});
}); });
it('renders size information', () => { it('renders size information', () => {
expect(vm.$el.querySelector('.js-truncated-info').textContent).toContain('499.95 KiB'); expect(vm.$el.querySelector('.js-truncated-info').textContent).toContain('499.95 KiB');
}); });
...@@ -29,31 +32,29 @@ describe('Job log controllers', () => { ...@@ -29,31 +32,29 @@ describe('Job log controllers', () => {
it('renders link to raw trace', () => { it('renders link to raw trace', () => {
expect(vm.$el.querySelector('.js-raw-link').getAttribute('href')).toEqual('/raw'); expect(vm.$el.querySelector('.js-raw-link').getAttribute('href')).toEqual('/raw');
}); });
});
}); });
describe('links section', () => { describe('links section', () => {
describe('with raw trace path', () => { describe('with raw trace path', () => {
it('renders raw trace link', () => { it('renders raw trace link', () => {
vm = mountComponent(Component, { vm = mountComponent(Component, props);
rawTracePath: '/raw',
canEraseJob: true,
size: 511952,
canScrollToTop: true,
canScrollToBottom: true,
});
expect(vm.$el.querySelector('.js-raw-link-controller').getAttribute('href')).toEqual('/raw'); expect(vm.$el.querySelector('.js-raw-link-controller').getAttribute('href')).toEqual(
'/raw',
);
}); });
}); });
describe('without raw trace path', () => { describe('without raw trace path', () => {
it('does not render raw trace link', () => { it('does not render raw trace link', () => {
vm = mountComponent(Component, { vm = mountComponent(Component, {
canEraseJob: true, erasePath: '/erase',
size: 511952, size: 511952,
canScrollToTop: true, isScrollTopDisabled: true,
canScrollToBottom: true, isScrollBottomDisabled: true,
isScrollingDown: false,
isTraceSizeVisible: true,
}); });
expect(vm.$el.querySelector('.js-raw-link-controller')).toBeNull(); expect(vm.$el.querySelector('.js-raw-link-controller')).toBeNull();
...@@ -62,52 +63,23 @@ describe('Job log controllers', () => { ...@@ -62,52 +63,23 @@ describe('Job log controllers', () => {
describe('when is erasable', () => { describe('when is erasable', () => {
beforeEach(() => { beforeEach(() => {
vm = mountComponent(Component, { vm = mountComponent(Component, props);
rawTracePath: '/raw',
canEraseJob: true,
size: 511952,
canScrollToTop: true,
canScrollToBottom: true,
});
}); });
it('renders erase job button', () => { it('renders erase job link', () => {
expect(vm.$el.querySelector('.js-erase-link')).not.toBeNull(); expect(vm.$el.querySelector('.js-erase-link')).not.toBeNull();
}); });
describe('on click', () => {
describe('when user confirms action', () => {
it('emits eraseJob event', () => {
spyOn(window, 'confirm').and.returnValue(true);
spyOn(vm, '$emit');
vm.$el.querySelector('.js-erase-link').click();
expect(vm.$emit).toHaveBeenCalledWith('eraseJob');
});
});
describe('when user does not confirm action', () => {
it('does not emit eraseJob event', () => {
spyOn(window, 'confirm').and.returnValue(false);
spyOn(vm, '$emit');
vm.$el.querySelector('.js-erase-link').click();
expect(vm.$emit).not.toHaveBeenCalledWith('eraseJob');
});
});
});
}); });
describe('when it is not erasable', () => { describe('when it is not erasable', () => {
it('does not render erase button', () => { it('does not render erase button', () => {
vm = mountComponent(Component, { vm = mountComponent(Component, {
rawTracePath: '/raw', rawPath: '/raw',
canEraseJob: false,
size: 511952, size: 511952,
canScrollToTop: true, isScrollTopDisabled: true,
canScrollToBottom: true, isScrollBottomDisabled: true,
isScrollingDown: false,
isTraceSizeVisible: true,
}); });
expect(vm.$el.querySelector('.js-erase-link')).toBeNull(); expect(vm.$el.querySelector('.js-erase-link')).toBeNull();
...@@ -119,13 +91,7 @@ describe('Job log controllers', () => { ...@@ -119,13 +91,7 @@ describe('Job log controllers', () => {
describe('scroll top button', () => { describe('scroll top button', () => {
describe('when user can scroll top', () => { describe('when user can scroll top', () => {
beforeEach(() => { beforeEach(() => {
vm = mountComponent(Component, { vm = mountComponent(Component, props);
rawTracePath: '/raw',
canEraseJob: true,
size: 511952,
canScrollToTop: true,
canScrollToBottom: true,
});
}); });
it('renders enabled scroll top button', () => { it('renders enabled scroll top button', () => {
...@@ -143,16 +109,20 @@ describe('Job log controllers', () => { ...@@ -143,16 +109,20 @@ describe('Job log controllers', () => {
describe('when user can not scroll top', () => { describe('when user can not scroll top', () => {
beforeEach(() => { beforeEach(() => {
vm = mountComponent(Component, { vm = mountComponent(Component, {
rawTracePath: '/raw', rawPath: '/raw',
canEraseJob: true, erasePath: '/erase',
size: 511952, size: 511952,
canScrollToTop: false, isScrollTopDisabled: true,
canScrollToBottom: true, isScrollBottomDisabled: false,
isScrollingDown: false,
isTraceSizeVisible: true,
}); });
}); });
it('renders disabled scroll top button', () => { it('renders disabled scroll top button', () => {
expect(vm.$el.querySelector('.js-scroll-top').getAttribute('disabled')).toEqual('disabled'); expect(vm.$el.querySelector('.js-scroll-top').getAttribute('disabled')).toEqual(
'disabled',
);
}); });
it('does not emit scrollJobLogTop event on click', () => { it('does not emit scrollJobLogTop event on click', () => {
...@@ -167,13 +137,7 @@ describe('Job log controllers', () => { ...@@ -167,13 +137,7 @@ describe('Job log controllers', () => {
describe('scroll bottom button', () => { describe('scroll bottom button', () => {
describe('when user can scroll bottom', () => { describe('when user can scroll bottom', () => {
beforeEach(() => { beforeEach(() => {
vm = mountComponent(Component, { vm = mountComponent(Component, props);
rawTracePath: '/raw',
canEraseJob: true,
size: 511952,
canScrollToTop: true,
canScrollToBottom: true,
});
}); });
it('renders enabled scroll bottom button', () => { it('renders enabled scroll bottom button', () => {
...@@ -191,17 +155,20 @@ describe('Job log controllers', () => { ...@@ -191,17 +155,20 @@ describe('Job log controllers', () => {
describe('when user can not scroll bottom', () => { describe('when user can not scroll bottom', () => {
beforeEach(() => { beforeEach(() => {
vm = mountComponent(Component, { vm = mountComponent(Component, {
rawTracePath: '/raw', rawPath: '/raw',
canEraseJob: true, erasePath: '/erase',
size: 511952, size: 511952,
canScrollToTop: true, isScrollTopDisabled: false,
canScrollToBottom: false, isScrollBottomDisabled: true,
isScrollingDown: false,
isTraceSizeVisible: true,
}); });
}); });
it('renders disabled scroll bottom button', () => { it('renders disabled scroll bottom button', () => {
expect(vm.$el.querySelector('.js-scroll-bottom').getAttribute('disabled')).toEqual('disabled'); expect(vm.$el.querySelector('.js-scroll-bottom').getAttribute('disabled')).toEqual(
'disabled',
);
}); });
it('does not emit scrollJobLogBottom event on click', () => { it('does not emit scrollJobLogBottom event on click', () => {
...@@ -211,7 +178,29 @@ describe('Job log controllers', () => { ...@@ -211,7 +178,29 @@ describe('Job log controllers', () => {
expect(vm.$emit).not.toHaveBeenCalledWith('scrollJobLogBottom'); expect(vm.$emit).not.toHaveBeenCalledWith('scrollJobLogBottom');
}); });
}); });
describe('while isScrollingDown is true', () => {
it('renders animate class for the scroll down button', () => {
vm = mountComponent(Component, props);
expect(vm.$el.querySelector('.js-scroll-bottom').className).toContain('animate');
}); });
}); });
});
describe('while isScrollingDown is false', () => {
it('does not render animate class for the scroll down button', () => {
vm = mountComponent(Component, {
rawPath: '/raw',
erasePath: '/erase',
size: 511952,
isScrollTopDisabled: true,
isScrollBottomDisabled: false,
isScrollingDown: false,
isTraceSizeVisible: true,
});
expect(vm.$el.querySelector('.js-scroll-bottom').className).not.toContain('animate');
});
});
});
});
});
...@@ -15,7 +15,7 @@ describe('Job Log', () => { ...@@ -15,7 +15,7 @@ describe('Job Log', () => {
it('renders provided trace', () => { it('renders provided trace', () => {
vm = mountComponent(Component, { vm = mountComponent(Component, {
trace, trace,
isReceivingBuildTrace: true, isComplete: true,
}); });
expect(vm.$el.querySelector('code').textContent).toContain('Running with gitlab-runner 11.1.0 (081978aa)'); expect(vm.$el.querySelector('code').textContent).toContain('Running with gitlab-runner 11.1.0 (081978aa)');
...@@ -25,7 +25,7 @@ describe('Job Log', () => { ...@@ -25,7 +25,7 @@ describe('Job Log', () => {
it('renders animation', () => { it('renders animation', () => {
vm = mountComponent(Component, { vm = mountComponent(Component, {
trace, trace,
isReceivingBuildTrace: true, isComplete: true,
}); });
expect(vm.$el.querySelector('.js-log-animation')).not.toBeNull(); expect(vm.$el.querySelector('.js-log-animation')).not.toBeNull();
...@@ -36,7 +36,7 @@ describe('Job Log', () => { ...@@ -36,7 +36,7 @@ describe('Job Log', () => {
it('does not render animation', () => { it('does not render animation', () => {
vm = mountComponent(Component, { vm = mountComponent(Component, {
trace, trace,
isReceivingBuildTrace: false, isComplete: false,
}); });
expect(vm.$el.querySelector('.js-log-animation')).toBeNull(); expect(vm.$el.querySelector('.js-log-animation')).toBeNull();
......
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