Commit 81cdda3f authored by Andrew Fontaine's avatar Andrew Fontaine

Merge branch '276949-pipeline-restructure-4' into 'master'

Pipeline Graph Structural Update: Adding Accessors

See merge request gitlab-org/gitlab!48558
parents 92364199 b979f529
......@@ -20,7 +20,10 @@ export default {
computed: {
isDelayedJob() {
return this.job && this.job.scheduled;
return this.job?.scheduled || this.job?.scheduledAt;
},
scheduledTime() {
return this.job.scheduled_at || this.job.scheduledAt;
},
},
......@@ -43,7 +46,7 @@ export default {
},
updateRemainingTime() {
const remainingMilliseconds = calculateRemainingMilliseconds(this.job.scheduled_at);
const remainingMilliseconds = calculateRemainingMilliseconds(this.scheduledTime);
this.remainingTime = formatTime(remainingMilliseconds);
},
},
......
import { get } from 'lodash';
import { REST, GRAPHQL } from './constants';
export const accessors = {
const accessors = {
[REST]: {
detailsPath: 'details_path',
groupId: 'id',
hasDetails: 'has_details',
pipelineStatus: ['details', 'status'],
sourceJob: ['source_job', 'name'],
},
[GRAPHQL]: {
detailsPath: 'detailsPath',
groupId: 'name',
hasDetails: 'hasDetails',
pipelineStatus: 'status',
sourceJob: ['sourceJob', 'name'],
},
};
const accessValue = (dataMethod, prop, item) => {
return get(item, accessors[dataMethod][prop]);
};
export { accessors, accessValue };
......@@ -4,6 +4,8 @@ import ActionComponent from './action_component.vue';
import JobNameComponent from './job_name_component.vue';
import { sprintf } from '~/locale';
import delayedJobMixin from '~/jobs/mixins/delayed_job_mixin';
import { accessors } from './accessors';
import { REST } from './constants';
/**
* Renders the badge for the pipeline graph and the job's dropdown.
......@@ -41,6 +43,11 @@ export default {
GlTooltip: GlTooltipDirective,
},
mixins: [delayedJobMixin],
inject: {
dataMethod: {
default: REST,
},
},
props: {
job: {
type: Object,
......@@ -71,10 +78,15 @@ export default {
boundary() {
return this.dropdownLength === 1 ? 'viewport' : 'scrollParent';
},
detailsPath() {
return this.status[accessors[this.dataMethod].detailsPath];
},
hasDetails() {
return this.status[accessors[this.dataMethod].hasDetails];
},
status() {
return this.job && this.job.status ? this.job.status : {};
},
tooltipText() {
const textBuilder = [];
const { name: jobName } = this.job;
......@@ -134,13 +146,13 @@ export default {
data-qa-selector="job_item_container"
>
<gl-link
v-if="status.has_details"
v-if="hasDetails"
v-gl-tooltip="{ boundary, placement: 'bottom', customClass: 'gl-pointer-events-none' }"
:href="status.details_path"
:href="detailsPath"
:title="tooltipText"
:class="jobClasses"
class="js-pipeline-graph-job-link qa-job-link menu-item gl-text-gray-900 gl-active-text-decoration-none
gl-focus-text-decoration-none"
gl-focus-text-decoration-none gl-hover-text-decoration-none"
data-testid="job-with-link"
@click.stop="hideTooltips"
@mouseout="hideTooltips"
......
......@@ -2,7 +2,8 @@
import { GlTooltipDirective, GlButton, GlLink, GlLoadingIcon } from '@gitlab/ui';
import CiStatus from '~/vue_shared/components/ci_icon.vue';
import { __, sprintf } from '~/locale';
import { UPSTREAM, DOWNSTREAM } from './constants';
import { accessValue } from './accessors';
import { DOWNSTREAM, REST, UPSTREAM } from './constants';
export default {
directives: {
......@@ -14,6 +15,11 @@ export default {
GlLink,
GlLoadingIcon,
},
inject: {
dataMethod: {
default: REST,
},
},
props: {
columnTitle: {
type: String,
......@@ -46,7 +52,7 @@ export default {
return `js-linked-pipeline-${this.pipeline.id}`;
},
pipelineStatus() {
return this.pipeline.details.status;
return accessValue(this.dataMethod, 'pipelineStatus', this.pipeline);
},
projectName() {
return this.pipeline.project.name;
......@@ -77,10 +83,11 @@ export default {
isSameProject() {
return this.projectId === this.pipeline.project.id;
},
sourceJobName() {
return accessValue(this.dataMethod, 'sourceJob', this.pipeline);
},
sourceJobInfo() {
return this.isDownstream
? sprintf(__('Created by %{job}'), { job: this.pipeline.source_job.name })
: '';
return this.isDownstream ? sprintf(__('Created by %{job}'), { job: this.sourceJobName }) : '';
},
expandedIcon() {
if (this.isUpstream) {
......
......@@ -2,6 +2,7 @@ import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import PipelineGraphWrapper from './components/graph/graph_component_wrapper.vue';
import { GRAPHQL } from './components/graph/constants';
Vue.use(VueApollo);
......@@ -20,6 +21,7 @@ const createPipelinesDetailApp = (selector, pipelineProjectPath, pipelineIid) =>
provide: {
pipelineProjectPath,
pipelineIid,
dataMethod: GRAPHQL,
},
render(createElement) {
return createElement(PipelineGraphWrapper);
......
......@@ -135,7 +135,8 @@
}
.gl-active-text-decoration-none:active,
.gl-focus-text-decoration-none:focus {
.gl-focus-text-decoration-none:focus,
.gl-hover-text-decoration-none:hover {
text-decoration: none;
}
......
......@@ -44,34 +44,84 @@ describe('DelayedJobMixin', () => {
});
});
describe('if job is delayed job', () => {
let remainingTimeInMilliseconds = 42000;
describe('in REST component', () => {
describe('if job is delayed job', () => {
let remainingTimeInMilliseconds = 42000;
beforeEach(() => {
jest
.spyOn(Date, 'now')
.mockImplementation(
() => new Date(delayedJobFixture.scheduled_at).getTime() - remainingTimeInMilliseconds,
);
beforeEach(() => {
jest
.spyOn(Date, 'now')
.mockImplementation(
() => new Date(delayedJobFixture.scheduled_at).getTime() - remainingTimeInMilliseconds,
);
vm = mountComponent(dummyComponent, {
job: delayedJobFixture,
vm = mountComponent(dummyComponent, {
job: delayedJobFixture,
});
});
describe('after mounting', () => {
beforeEach(() => vm.$nextTick());
it('sets remaining time', () => {
expect(vm.$el.innerText).toBe('00:00:42');
});
it('updates remaining time', () => {
remainingTimeInMilliseconds = 41000;
jest.advanceTimersByTime(1000);
return vm.$nextTick().then(() => {
expect(vm.$el.innerText).toBe('00:00:41');
});
});
});
});
});
describe('after mounting', () => {
beforeEach(() => vm.$nextTick());
describe('in GraphQL component', () => {
const mockGraphQlJob = {
name: 'build_b',
scheduledAt: new Date(delayedJobFixture.scheduled_at),
status: {
icon: 'status_success',
tooltip: 'passed',
hasDetails: true,
detailsPath: '/root/abcd-dag/-/jobs/1515',
group: 'success',
action: null,
},
};
describe('if job is delayed job', () => {
let remainingTimeInMilliseconds = 42000;
it('sets remaining time', () => {
expect(vm.$el.innerText).toBe('00:00:42');
beforeEach(() => {
jest
.spyOn(Date, 'now')
.mockImplementation(
() => mockGraphQlJob.scheduledAt.getTime() - remainingTimeInMilliseconds,
);
vm = mountComponent(dummyComponent, {
job: mockGraphQlJob,
});
});
it('updates remaining time', () => {
remainingTimeInMilliseconds = 41000;
jest.advanceTimersByTime(1000);
describe('after mounting', () => {
beforeEach(() => vm.$nextTick());
it('sets remaining time', () => {
expect(vm.$el.innerText).toBe('00:00:42');
});
it('updates remaining time', () => {
remainingTimeInMilliseconds = 41000;
jest.advanceTimersByTime(1000);
return vm.$nextTick().then(() => {
expect(vm.$el.innerText).toBe('00:00:41');
return vm.$nextTick().then(() => {
expect(vm.$el.innerText).toBe('00:00:41');
});
});
});
});
......
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