diff options
10 files changed, 159 insertions, 166 deletions
diff --git a/app/assets/javascripts/jobs/components/empty_state.vue b/app/assets/javascripts/jobs/components/empty_state.vue index 4faf08387fb..ff45a5b05f8 100644 --- a/app/assets/javascripts/jobs/components/empty_state.vue +++ b/app/assets/javascripts/jobs/components/empty_state.vue @@ -25,7 +25,7 @@ validator(value) { return ( 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, 'title')) ); @@ -63,7 +63,7 @@ class="text-center" > <a - :href="action.link" + :href="action.path" :data-method="action.method" class="js-job-empty-state-action btn btn-primary" > diff --git a/app/assets/javascripts/jobs/components/erased_block.vue b/app/assets/javascripts/jobs/components/erased_block.vue index d688eebfa95..3d6d9ba4387 100644 --- a/app/assets/javascripts/jobs/components/erased_block.vue +++ b/app/assets/javascripts/jobs/components/erased_block.vue @@ -1,39 +1,36 @@ <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 { - components: { - TimeagoTooltip, - }, - props: { - erasedByUser: { - type: Boolean, - required: true, + export default { + components: { + TimeagoTooltip, }, - username: { - type: String, - required: false, - default: null, + props: { + user: { + type: Object, + required: false, + default: () => ({}), + }, + erasedAt: { + type: String, + required: true, + }, }, - linkToUser: { - type: String, - required: false, - default: null, + computed: { + isErasedByUser() { + return !_.isEmpty(this.user); + }, }, - erasedAt: { - type: String, - required: true, - }, - }, -}; + }; </script> <template> <div class="prepend-top-default js-build-erased"> <div class="erased alert alert-warning"> - <template v-if="erasedByUser"> + <template v-if="isErasedByUser"> {{ s__("Job|Job has been erased by") }} - <a :href="linkToUser"> - {{ username }} + <a :href="user.web_url"> + {{ user.username }} </a> </template> <template v-else> diff --git a/app/assets/javascripts/jobs/components/job_log.vue b/app/assets/javascripts/jobs/components/job_log.vue index 3c4749d996b..b12e963b60c 100644 --- a/app/assets/javascripts/jobs/components/job_log.vue +++ b/app/assets/javascripts/jobs/components/job_log.vue @@ -6,7 +6,7 @@ type: String, required: true, }, - isReceivingBuildTrace: { + isComplete: { type: Boolean, required: true, }, @@ -22,7 +22,7 @@ </code> <div - v-if="isReceivingBuildTrace" + v-if="isComplete" class="js-log-animation build-loader-animation" > <div class="dot"></div> diff --git a/app/assets/javascripts/jobs/components/job_log_controllers.vue b/app/assets/javascripts/jobs/components/job_log_controllers.vue index 2cbf0f85266..3e62ababea3 100644 --- a/app/assets/javascripts/jobs/components/job_log_controllers.vue +++ b/app/assets/javascripts/jobs/components/job_log_controllers.vue @@ -1,8 +1,9 @@ <script> + import { polyfillSticky } from '~/lib/utils/sticky'; import Icon from '~/vue_shared/components/icon.vue'; import tooltip from '~/vue_shared/directives/tooltip'; import { numberToHumanSize } from '~/lib/utils/number_utils'; - import { s__, sprintf } from '~/locale'; + import { sprintf } from '~/locale'; export default { components: { @@ -12,44 +13,48 @@ tooltip, }, props: { - canEraseJob: { - type: Boolean, - required: true, + erasePath: { + type: String, + required: false, + default: null, }, size: { type: Number, required: true, }, - rawTracePath: { + rawPath: { type: String, required: false, default: null, }, - canScrollToTop: { + isScrollTopDisabled: { + type: Boolean, + required: true, + }, + isScrollBottomDisabled: { + type: Boolean, + required: true, + }, + isScrollingDown: { type: Boolean, required: true, }, - canScrollToBottom: { + isTraceSizeVisible: { type: Boolean, required: true, }, }, computed: { jobLogSize() { - return sprintf('Showing last %{startSpanTag} %{size} %{endSpanTag} of log -', { - startSpanTag: '<span class="s-truncated-info-size truncated-info-size">', - endSpanTag: '</span>', + return sprintf('Showing last %{size} of log -', { size: numberToHumanSize(this.size), }); }, }, + mounted() { + polyfillSticky(this.$el); + }, methods: { - handleEraseJobClick() { - // eslint-disable-next-line no-alert - if (window.confirm(s__('Job|Are you sure you want to erase this job?'))) { - this.$emit('eraseJob'); - } - }, handleScrollToTop() { this.$emit('scrollJobLogTop'); }, @@ -57,48 +62,52 @@ this.$emit('scrollJobLogBottom'); }, }, + }; </script> <template> <div class="top-bar"> <!-- truncate information --> <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 - v-if="rawTracePath" - :href="rawTracePath" - class="js-raw-link raw-link" - > - {{ s__("Job|Complete Raw") }} - </a> + <a + v-if="rawPath" + :href="rawPath" + class="js-raw-link raw-link" + > + {{ s__("Job|Complete Raw") }} + </a> + </template> </div> <!-- eo truncate information --> <div class="controllers float-right"> <!-- links --> <a - v-if="rawTracePath" + v-if="rawPath" v-tooltip :title="s__('Job|Show complete raw')" - :href="rawTracePath" + :href="rawPath" class="js-raw-link-controller controllers-buttons" data-container="body" > <icon name="doc-text" /> </a> - <button - v-if="canEraseJob" + <a + v-if="erasePath" v-tooltip :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" data-container="body" - @click="handleEraseJobClick" + data-method="post" > <icon name="remove" /> - </button> + </a> <!-- eo links --> <!-- scroll buttons --> @@ -109,7 +118,7 @@ data-container="body" > <button - :disabled="!canScrollToTop" + :disabled="isScrollTopDisabled" type="button" class="js-scroll-top btn-scroll btn-transparent btn-blank" @click="handleScrollToTop" @@ -125,9 +134,10 @@ data-container="body" > <button - :disabled="!canScrollToBottom" + :disabled="isScrollBottomDisabled" type="button" class="js-scroll-bottom btn-scroll btn-transparent btn-blank" + :class="{ animate: isScrollingDown }" @click="handleScrollToBottom" > <icon name="scroll_down"/> diff --git a/app/assets/javascripts/jobs/components/stuck_block.vue b/app/assets/javascripts/jobs/components/stuck_block.vue index 18883fea950..a60643b2c65 100644 --- a/app/assets/javascripts/jobs/components/stuck_block.vue +++ b/app/assets/javascripts/jobs/components/stuck_block.vue @@ -24,14 +24,14 @@ export default { <div class="bs-callout bs-callout-warning"> <p 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 doesn't have any runners online assigned to it.`) }} </p> <p 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 any active runners online with any of these tags assigned to them:`) }} @@ -45,7 +45,7 @@ export default { </p> <p 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 have any active runners that can run this job.`) }} diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 4d8f05a81cc..a9c5e45f9fa 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -3338,9 +3338,6 @@ msgstr "" msgid "Jobs" msgstr "" -msgid "Job|Are you sure you want to erase this job?" -msgstr "" - msgid "Job|Browse" msgstr "" diff --git a/spec/javascripts/jobs/components/empty_state_spec.js b/spec/javascripts/jobs/components/empty_state_spec.js index dcc2b3d8a20..872cc1e3864 100644 --- a/spec/javascripts/jobs/components/empty_state_spec.js +++ b/spec/javascripts/jobs/components/empty_state_spec.js @@ -66,7 +66,7 @@ describe('Empty State', () => { ...props, content, action: { - link: 'runner', + path: 'runner', title: 'Check runner', method: 'post', }, diff --git a/spec/javascripts/jobs/components/erased_block_spec.js b/spec/javascripts/jobs/components/erased_block_spec.js index a4ae0c7c81e..8e0433d3fb7 100644 --- a/spec/javascripts/jobs/components/erased_block_spec.js +++ b/spec/javascripts/jobs/components/erased_block_spec.js @@ -18,9 +18,10 @@ describe('Erased block', () => { describe('with job erased by user', () => { beforeEach(() => { vm = mountComponent(Component, { - erasedByUser: true, - username: 'root', - linkToUser: 'gitlab.com/root', + user: { + username: 'root', + web_url: 'gitlab.com/root', + }, erasedAt, }); }); @@ -40,7 +41,6 @@ describe('Erased block', () => { describe('with erased job', () => { beforeEach(() => { vm = mountComponent(Component, { - erasedByUser: false, erasedAt, }); }); diff --git a/spec/javascripts/jobs/components/job_log_controllers_spec.js b/spec/javascripts/jobs/components/job_log_controllers_spec.js index 416dfab8a48..099aca602c4 100644 --- a/spec/javascripts/jobs/components/job_log_controllers_spec.js +++ b/spec/javascripts/jobs/components/job_log_controllers_spec.js @@ -10,50 +10,51 @@ describe('Job log controllers', () => { vm.$destroy(); }); - describe('Truncate information', () => { + const props = { + rawPath: '/raw', + erasePath: '/erase', + size: 511952, + isScrollTopDisabled: false, + isScrollBottomDisabled: false, + isScrollingDown: true, + isTraceSizeVisible: true, + }; - beforeEach(() => { - vm = mountComponent(Component, { - rawTracePath: '/raw', - canEraseJob: true, - size: 511952, - canScrollToTop: true, - canScrollToBottom: true, + describe('Truncate information', () => { + describe('with isTraceSizeVisible', () => { + beforeEach(() => { + vm = mountComponent(Component, props); + }); + it('renders size information', () => { + expect(vm.$el.querySelector('.js-truncated-info').textContent).toContain('499.95 KiB'); }); - }); - - it('renders size information', () => { - expect(vm.$el.querySelector('.js-truncated-info').textContent).toContain('499.95 KiB'); - }); - it('renders link to raw trace', () => { - expect(vm.$el.querySelector('.js-raw-link').getAttribute('href')).toEqual('/raw'); + it('renders link to raw trace', () => { + expect(vm.$el.querySelector('.js-raw-link').getAttribute('href')).toEqual('/raw'); + }); }); - }); describe('links section', () => { describe('with raw trace path', () => { it('renders raw trace link', () => { - vm = mountComponent(Component, { - rawTracePath: '/raw', - canEraseJob: true, - size: 511952, - canScrollToTop: true, - canScrollToBottom: true, - }); + vm = mountComponent(Component, props); - 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', () => { it('does not render raw trace link', () => { vm = mountComponent(Component, { - canEraseJob: true, + erasePath: '/erase', size: 511952, - canScrollToTop: true, - canScrollToBottom: true, + isScrollTopDisabled: true, + isScrollBottomDisabled: true, + isScrollingDown: false, + isTraceSizeVisible: true, }); expect(vm.$el.querySelector('.js-raw-link-controller')).toBeNull(); @@ -62,52 +63,23 @@ describe('Job log controllers', () => { describe('when is erasable', () => { beforeEach(() => { - vm = mountComponent(Component, { - rawTracePath: '/raw', - canEraseJob: true, - size: 511952, - canScrollToTop: true, - canScrollToBottom: true, - }); + vm = mountComponent(Component, props); }); - it('renders erase job button', () => { + it('renders erase job link', () => { 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', () => { it('does not render erase button', () => { vm = mountComponent(Component, { - rawTracePath: '/raw', - canEraseJob: false, + rawPath: '/raw', size: 511952, - canScrollToTop: true, - canScrollToBottom: true, + isScrollTopDisabled: true, + isScrollBottomDisabled: true, + isScrollingDown: false, + isTraceSizeVisible: true, }); expect(vm.$el.querySelector('.js-erase-link')).toBeNull(); @@ -119,13 +91,7 @@ describe('Job log controllers', () => { describe('scroll top button', () => { describe('when user can scroll top', () => { beforeEach(() => { - vm = mountComponent(Component, { - rawTracePath: '/raw', - canEraseJob: true, - size: 511952, - canScrollToTop: true, - canScrollToBottom: true, - }); + vm = mountComponent(Component, props); }); it('renders enabled scroll top button', () => { @@ -143,16 +109,20 @@ describe('Job log controllers', () => { describe('when user can not scroll top', () => { beforeEach(() => { vm = mountComponent(Component, { - rawTracePath: '/raw', - canEraseJob: true, + rawPath: '/raw', + erasePath: '/erase', size: 511952, - canScrollToTop: false, - canScrollToBottom: true, + isScrollTopDisabled: true, + isScrollBottomDisabled: false, + isScrollingDown: false, + isTraceSizeVisible: true, }); }); 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', () => { @@ -167,13 +137,7 @@ describe('Job log controllers', () => { describe('scroll bottom button', () => { describe('when user can scroll bottom', () => { beforeEach(() => { - vm = mountComponent(Component, { - rawTracePath: '/raw', - canEraseJob: true, - size: 511952, - canScrollToTop: true, - canScrollToBottom: true, - }); + vm = mountComponent(Component, props); }); it('renders enabled scroll bottom button', () => { @@ -191,17 +155,20 @@ describe('Job log controllers', () => { describe('when user can not scroll bottom', () => { beforeEach(() => { vm = mountComponent(Component, { - rawTracePath: '/raw', - canEraseJob: true, + rawPath: '/raw', + erasePath: '/erase', size: 511952, - canScrollToTop: true, - canScrollToBottom: false, + isScrollTopDisabled: false, + isScrollBottomDisabled: true, + isScrollingDown: false, + isTraceSizeVisible: true, }); }); 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', () => { @@ -211,7 +178,29 @@ describe('Job log controllers', () => { 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'); + }); + }); }); }); }); - diff --git a/spec/javascripts/jobs/components/job_log_spec.js b/spec/javascripts/jobs/components/job_log_spec.js index 6a5b375a26c..1011512360d 100644 --- a/spec/javascripts/jobs/components/job_log_spec.js +++ b/spec/javascripts/jobs/components/job_log_spec.js @@ -15,7 +15,7 @@ describe('Job Log', () => { it('renders provided trace', () => { vm = mountComponent(Component, { trace, - isReceivingBuildTrace: true, + isComplete: true, }); expect(vm.$el.querySelector('code').textContent).toContain('Running with gitlab-runner 11.1.0 (081978aa)'); @@ -25,7 +25,7 @@ describe('Job Log', () => { it('renders animation', () => { vm = mountComponent(Component, { trace, - isReceivingBuildTrace: true, + isComplete: true, }); expect(vm.$el.querySelector('.js-log-animation')).not.toBeNull(); @@ -36,7 +36,7 @@ describe('Job Log', () => { it('does not render animation', () => { vm = mountComponent(Component, { trace, - isReceivingBuildTrace: false, + isComplete: false, }); expect(vm.$el.querySelector('.js-log-animation')).toBeNull(); |