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