Commit 32b4426b authored by Bryce Johnson's avatar Bryce Johnson

Add changes on top of CE changes.

parent 02b350f7
......@@ -18,16 +18,24 @@
type: Object,
required: true,
},
triggered: {
type: Array,
required: true,
},
triggeredBy: {
type: Array,
required: true,
},
},
computed: {
graph() {
return this.pipeline.details && this.pipeline.details.stages;
},
hasTriggered() {
return !!this.pipeline.triggered.length;
return !!this.triggered.length;
},
hasTriggeredBy() {
return !!this.pipeline.triggered_by.length;
return !!this.triggeredBy.length;
},
linkedPipelinesClass() {
return this.hasTriggered || this.hasTriggeredBy ? 'has-linked-pipelines' : '';
......@@ -85,7 +93,7 @@
<linked-pipelines-column
v-if="hasTriggeredBy"
:linked-pipelines="pipeline.triggered_by"
:linked-pipelines="triggeredBy"
column-title="Upstream"
graph-position="left"
/>
......@@ -108,7 +116,7 @@
<linked-pipelines-column
v-if="hasTriggered"
:linked-pipelines="pipeline.triggered"
:linked-pipelines="triggered"
column-title="Downstream"
graph-position="right"
/>
......
<script>
import ciStatus from '../../../vue_shared/components/ci_icon.vue';
export default {
props: {
pipelineId: {
type: Number,
required: true,
},
pipelinePath: {
type: String,
required: true,
},
pipelineStatus: {
type: Object,
required: true,
},
projectName: {
type: String,
required: true,
},
},
components: {
ciStatus,
},
};
</script>
<template>
<li class="linked-pipeline build">
<div class="curve"></div>
<div>
<a :href="pipelinePath" class="linked-pipeline-content">
<span class="linked-pipeline-status ci-status-text">
<ci-status :status="pipelineStatus"/>
</span>
<span class="linked-pipeline-project-name"> {{ projectName }}</span>
<span class="linked-pipeline-id"> &#8226; #{{ pipelineId }}</span>
</a>
</div>
</li>
</template>
<script>
import linkedPipeline from './linked_pipeline.vue';
export default {
props: {
columnTitle: {
type: String,
required: true,
},
linkedPipelines: {
type: Array,
required: true,
},
graphPosition: {
type: String,
required: false,
},
},
components: {
linkedPipeline,
},
computed: {
columnId() {
return `graph-position-${this.graphPosition}`;
},
},
methods: {
flatConnectorClass(index) {
return (index === 0 && this.graphPosition === 'right') ? 'flat-connector-before' : '';
},
},
};
</script>
<template>
<div
class="linked-pipelines-column"
:id="columnId"
>
<div class="stage-name linked-pipelines-column-title"> {{ columnTitle }} </div>
<div class="cross-project-triangle"></div>
<ul>
<linked-pipeline
v-for="(pipeline, index) in linkedPipelines"
:class="flatConnectorClass(index)"
:key="pipeline.id"
:pipeline-id="pipeline.id"
:project-name="pipeline.project.name"
:pipeline-status="pipeline.details.status"
:pipeline-path="pipeline.path"
/>
</ul>
</div>
</template>
......@@ -24,6 +24,8 @@ document.addEventListener('DOMContentLoaded', () => {
props: {
isLoading: this.mediator.state.isLoading,
pipeline: this.mediator.store.state.pipeline,
triggeredBy: this.mediator.store.state.triggered_by,
triggered: this.mediator.store.state.triggered,
},
});
},
......
......@@ -12,7 +12,7 @@ export default class PipelineStore {
constructor() {
this.state = {};
this.state.pipeline = [];
this.state.pipeline = {};
this.state.triggered = [];
this.state.triggered_by = [];
}
......
......@@ -21,6 +21,7 @@
* - Jobs table
* - Jobs show view header
* - Jobs show view sidebar
* - Linked pipelines
*/
export default {
props: {
......
......@@ -250,6 +250,7 @@ $dark-diff-match-bg: rgba(255, 255, 255, 0.3);
$dark-diff-match-color: rgba(255, 255, 255, 0.1);
$file-mode-changed: #777;
$file-mode-changed: #777;
$diff-image-bg: #ddd;
$diff-image-info-color: grey;
$diff-swipe-border: #999;
$diff-view-modes-color: grey;
......@@ -581,3 +582,10 @@ $gl-gold-plan: #d4af37;
$gl-silver-plan: #91a1ab;
$gl-bronze-plan: #cd7f32;
$gl-no-plan: $gl-gray-light;
/*
Cross-project Pipelines
*/
$linked-project-column-margin: 60px;
@mixin flat-connector-before($length: 44px) {
&::before {
content: '';
position: absolute;
top: 48%;
left: -$length;
border-top: 2px solid $border-color;
width: $length;
height: 1px;
}
}
@mixin build-content($border-radius: 30px) {
display: inline-block;
padding: 8px 10px 9px;
width: 100%;
border: 1px solid $border-color;
border-radius: $border-radius;
background-color: $white-light;
&:hover {
background-color: $stage-hover-bg;
border: 1px solid $stage-hover-border;
color: $gl-text-color;
}
}
.pipelines {
.stage {
max-width: 90px;
......@@ -377,15 +404,7 @@
margin-left: 44px;
.left-connector {
&::before {
content: '';
position: absolute;
top: 48%;
left: -44px;
border-top: 2px solid $border-color;
width: 44px;
height: 1px;
}
@include flat-connector-before;
}
}
}
......@@ -398,7 +417,8 @@
list-style: none;
}
&:last-child {
// when downstream pipelines are present, the last stage isn't the last column
&:last-child:not(.has-downstream) {
.build {
// Remove right connecting horizontal line from first build in last stage
&:first-child {
......@@ -421,7 +441,8 @@
}
}
&:first-child {
// when upstream pipelines are present, the first stage isn't the first column
&:first-child:not(.has-upstream) {
.build {
// Remove left curved connectors from all builds in first stage
&:not(:first-child) {
......@@ -539,21 +560,9 @@
}
.build-content {
display: inline-block;
padding: 8px 10px 9px;
width: 100%;
border: 1px solid $border-color;
border-radius: 30px;
background-color: $white-light;
&:hover {
background-color: $stage-hover-bg;
border: 1px solid $stage-hover-border;
color: $gl-text-color;
}
@include build-content();
}
// Connect first build in each stage with right horizontal line
&:first-child {
&::after {
......@@ -984,3 +993,95 @@
width: 12px;
}
}
/**
* Cross-project pipelines (applied conditionally to pipeline graph)
*/
.has-linked-pipelines.stage-column-list {
display: inline-block;
}
.linked-pipelines-column {
@extend .stage-column;
position: relative;
& > ul {
padding: 0;
}
// IDs used to override specificity in stage-column
&#graph-position-left {
margin-right: $linked-project-column-margin;
.cross-project-triangle {
right: -64px;
}
}
&#graph-position-right {
margin-left: $linked-project-column-margin;
.cross-project-triangle {
left: -64px;
}
}
.linked-pipeline.build {
font-style: italic;
height: 40px;
// apply custom dimensions to connector before and after for triangle arrow
&.flat-connector-before {
@include flat-connector-before($linked-project-column-margin);
}
&::after {
right: -$linked-project-column-margin;
width: $linked-project-column-margin;
}
.linked-pipeline-content {
@include build-content(0);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
.stage-column.has-upstream {
margin-left: $linked-project-column-margin;
.left-connector {
@include flat-connector-before($linked-project-column-margin);
}
}
.stage-column.has-downstream {
margin-right: $linked-project-column-margin;
.build {
&:first-child {
&::after {
right: -$linked-project-column-margin;
width: $linked-project-column-margin;
}
}
}
}
.cross-project-triangle {
position: absolute;
top: 49px;
width: 0;
height: 0;
border-bottom: 7px solid transparent;
border-top: 7px solid transparent;
border-left: 7px solid $gray-darkest;
font-size: 0;
line-height: 0;
z-index: 10;
}
import Vue from 'vue';
import LinkedPipelineComponent from '~/pipelines/components/graph/linked_pipeline.vue';
import mockData from './linked_pipelines_mock_data';
const LinkedPipeline = Vue.extend(LinkedPipelineComponent);
const mockPipeline = mockData.triggered[0];
describe('Linked pipeline', () => {
beforeEach(() => {
this.propsData = {
pipelineId: mockPipeline.id,
pipelinePath: mockPipeline.path,
pipelineStatus: mockPipeline.details.status,
projectName: mockPipeline.project.name,
};
this.linkedPipeline = new LinkedPipeline({
propsData: this.propsData,
}).$mount();
});
it('should return a defined Vue component', () => {
expect(this.linkedPipeline).toBeDefined();
});
it('should render a list item as the containing element', () => {
expect(this.linkedPipeline.$el.tagName).toBe('LI');
});
it('should render a link', () => {
const linkElement = this.linkedPipeline.$el.querySelector('.linked-pipeline-content');
expect(linkElement).not.toBeNull();
});
it('should link to the correct path', () => {
const linkElement = this.linkedPipeline.$el.querySelector('.linked-pipeline-content');
expect(linkElement.getAttribute('href')).toBe(this.propsData.pipelinePath);
});
it('should render the project name', () => {
const projectNameElement = this.linkedPipeline.$el.querySelector('.linked-pipeline-project-name');
expect(projectNameElement.innerText).toContain(this.propsData.projectName);
});
it('should render an svg within the status container', () => {
const pipelineStatusElement = this.linkedPipeline.$el.querySelector('.linked-pipeline-status');
expect(pipelineStatusElement.querySelector('svg')).not.toBeNull();
});
it('should render the pipeline status icon svg', () => {
const pipelineStatusElement = this.linkedPipeline.$el.querySelector('.linked-pipeline-status');
expect(pipelineStatusElement.innerHTML).toContain('<svg');
});
it('should render the correct pipeline status icon style selector', () => {
const pipelineStatusElement = this.linkedPipeline.$el.querySelector('.linked-pipeline-status');
expect(pipelineStatusElement.firstChild.classList.contains('ci-status-icon-running')).toBe(true);
});
it('should have a ci-status child component', () => {
const ciStatusComponent = this.linkedPipeline.$children[0];
expect(ciStatusComponent).toBeDefined();
expect(ciStatusComponent.$el.classList.contains('ci-status-icon')).toBe(true);
});
it('should render the pipeline id', () => {
const pipelineIdElement = this.linkedPipeline.$el.querySelector('.linked-pipeline-id');
expect(pipelineIdElement.innerText).toContain(`#${this.propsData.pipelineId}`);
});
});
import Vue from 'vue';
import LinkedPipelinesColumn from '~/pipelines/components/graph/linked_pipelines_column.vue';
import mockData from './linked_pipelines_mock_data';
const LinkedPipelinesColumnComponent = Vue.extend(LinkedPipelinesColumn);
describe('Linked Pipelines Column', () => {
beforeEach(() => {
this.propsData = {
columnTitle: 'Upstream',
linkedPipelines: mockData.triggered,
graphPosition: 'right',
};
this.linkedPipelinesColumn = new LinkedPipelinesColumnComponent({
propsData: this.propsData,
}).$mount();
});
it('instantiates a defined Vue component', () => {
expect(this.linkedPipelinesColumn).toBeDefined();
});
it('renders the pipeline orientation', () => {
const titleElement = this.linkedPipelinesColumn.$el.querySelector('.linked-pipelines-column-title');
expect(titleElement.innerText).toContain(this.propsData.columnTitle);
});
it('has the correct number of linked pipeline child components', () => {
expect(this.linkedPipelinesColumn.$children.length).toBe(this.propsData.linkedPipelines.length);
});
it('renders the correct number of linked pipelines', () => {
const linkedPipelineElements = this.linkedPipelinesColumn.$el.querySelectorAll('.linked-pipeline');
expect(linkedPipelineElements.length).toBe(this.propsData.linkedPipelines.length);
});
describe('flatConnectorClass', () => {
beforeEach(() => {
this.flatConnectorClass = this.linkedPipelinesColumn.flatConnectorClass;
});
it('should return flat-connector-before for the first job on the right side of the graph', () => {
expect(this.flatConnectorClass(0)).toBe('flat-connector-before');
});
it('should return an empty string for subsequent jobs', () => {
expect(this.flatConnectorClass(1)).toBeFalsy();
expect(this.flatConnectorClass(99)).toBeFalsy();
});
});
});
/* eslint-disable quote-props, quotes, comma-dangle */
export default {
"triggerer": [
{
"id": 129,
"active": true,
"path": "/gitlab-org/gitlab-ce/pipelines/129",
"project": {
"name": "GitLabCE"
},
"details": {
"status": {
"icon": "icon_status_running",
"text": "running",
"label": "running",
"group": "running",
"has_details": true,
"details_path": "/gitlab-org/gitlab-ce/pipelines/129",
"favicon": "/assets/ci_favicons/dev/favicon_status_running-c3ad2fc53ea6079c174e5b6c1351ff349e99ec3af5a5622fb77b0fe53ea279c1.ico"
}
},
"flags": {
"latest": false,
"triggered": false,
"stuck": false,
"yaml_errors": false,
"retryable": true,
"cancelable": true
},
"ref": {
"name": "7-5-stable",
"path": "/gitlab-org/gitlab-ce/commits/7-5-stable",
"tag": false,
"branch": true
},
"commit": {
"id": "23433d4d8b20d7e45c103d0b6048faad38a130ab",
"short_id": "23433d4d",
"title": "Version 7.5.0.rc1",
"created_at": "2014-11-17T15:44:14.000+01:00",
"parent_ids": [
"30ac909f30f58d319b42ed1537664483894b18cd"
],
"message": "Version 7.5.0.rc1\n",
"author_name": "Jacob Vosmaer",
"author_email": "contact@jacobvosmaer.nl",
"authored_date": "2014-11-17T15:44:14.000+01:00",
"committer_name": "Jacob Vosmaer",
"committer_email": "contact@jacobvosmaer.nl",
"committed_date": "2014-11-17T15:44:14.000+01:00",
"author_gravatar_url": "http://www.gravatar.com/avatar/e66d11c0eedf8c07b3b18fca46599807?s=80&d=identicon",
"commit_url": "http://localhost:3000/gitlab-org/gitlab-ce/commit/23433d4d8b20d7e45c103d0b6048faad38a130ab",
"commit_path": "/gitlab-org/gitlab-ce/commit/23433d4d8b20d7e45c103d0b6048faad38a130ab"
},
"retry_path": "/gitlab-org/gitlab-ce/pipelines/129/retry",
"cancel_path": "/gitlab-org/gitlab-ce/pipelines/129/cancel",
"created_at": "2017-05-24T14:46:20.090Z",
"updated_at": "2017-05-24T14:46:29.906Z"
}
],
"triggered": [
{
"id": 132,
"active": true,
"path": "/gitlab-org/gitlab-ce/pipelines/132",
"project": {
"name": "GitLabCE"
},
"details": {
"status": {
"icon": "icon_status_running",
"text": "running",
"label": "running",
"group": "running",
"has_details": true,
"details_path": "/gitlab-org/gitlab-ce/pipelines/132",
"favicon": "/assets/ci_favicons/dev/favicon_status_running-c3ad2fc53ea6079c174e5b6c1351ff349e99ec3af5a5622fb77b0fe53ea279c1.ico"
}
},
"flags": {
"latest": false,
"triggered": false,
"stuck": false,
"yaml_errors": false,
"retryable": true,
"cancelable": true
},
"ref": {
"name": "crowd",
"path": "/gitlab-org/gitlab-ce/commits/crowd",
"tag": false,
"branch": true
},
"commit": {
"id": "b9d58c4cecd06be74c3cc32ccfb522b31544ab2e",
"short_id": "b9d58c4c",
"title": "getting user keys publically through http without any authentication, the github…",
"created_at": "2013-10-03T12:50:33.000+05:30",
"parent_ids": [
"e219cf7246c6a0495e4507deaffeba11e79f13b8"
],
"message": "getting user keys publically through http without any authentication, the github way. E.g: http://github.com/devaroop.keys\n\nchangelog updated to include ssh key retrieval feature update\n",
"author_name": "devaroop",
"author_email": "devaroop123@yahoo.co.in",
"authored_date": "2013-10-02T20:39:29.000+05:30",
"committer_name": "devaroop",
"committer_email": "devaroop123@yahoo.co.in",
"committed_date": "2013-10-03T12:50:33.000+05:30",
"author_gravatar_url": "http://www.gravatar.com/avatar/35df4b155ec66a3127d53459941cf8a2?s=80&d=identicon",
"commit_url": "http://localhost:3000/gitlab-org/gitlab-ce/commit/b9d58c4cecd06be74c3cc32ccfb522b31544ab2e",
"commit_path": "/gitlab-org/gitlab-ce/commit/b9d58c4cecd06be74c3cc32ccfb522b31544ab2e"
},
"retry_path": "/gitlab-org/gitlab-ce/pipelines/132/retry",
"cancel_path": "/gitlab-org/gitlab-ce/pipelines/132/cancel",
"created_at": "2017-05-24T14:46:24.644Z",
"updated_at": "2017-05-24T14:48:55.226Z"
},
{
"id": 133,
"active": true,
"path": "/gitlab-org/gitlab-ce/pipelines/133",
"project": {
"name": "GitLabCE"
},
"details": {
"status": {
"icon": "icon_status_running",
"text": "running",
"label": "running",
"group": "running",
"has_details": true,
"details_path": "/gitlab-org/gitlab-ce/pipelines/133",
"favicon": "/assets/ci_favicons/dev/favicon_status_running-c3ad2fc53ea6079c174e5b6c1351ff349e99ec3af5a5622fb77b0fe53ea279c1.ico"
}
},
"flags": {
"latest": false,
"triggered": false,
"stuck": false,
"yaml_errors": false,
"retryable": true,
"cancelable": true
},
"ref": {
"name": "crowd",
"path": "/gitlab-org/gitlab-ce/commits/crowd",
"tag": false,
"branch": true
},
"commit": {
"id": "b6bd4856a33df3d144be66c4ed1f1396009bb08b",
"short_id": "b6bd4856",
"title": "getting user keys publically through http without any authentication, the github…",
"created_at": "2013-10-02T20:39:29.000+05:30",
"parent_ids": [
"e219cf7246c6a0495e4507deaffeba11e79f13b8"
],
"message": "getting user keys publically through http without any authentication, the github way. E.g: http://github.com/devaroop.keys\n",
"author_name": "devaroop",
"author_email": "devaroop123@yahoo.co.in",
"authored_date": "2013-10-02T20:39:29.000+05:30",
"committer_name": "devaroop",
"committer_email": "devaroop123@yahoo.co.in",
"committed_date": "2013-10-02T20:39:29.000+05:30",
"author_gravatar_url": "http://www.gravatar.com/avatar/35df4b155ec66a3127d53459941cf8a2?s=80&d=identicon",
"commit_url": "http://localhost:3000/gitlab-org/gitlab-ce/commit/b6bd4856a33df3d144be66c4ed1f1396009bb08b",
"commit_path": "/gitlab-org/gitlab-ce/commit/b6bd4856a33df3d144be66c4ed1f1396009bb08b"
},
"retry_path": "/gitlab-org/gitlab-ce/pipelines/133/retry",
"cancel_path": "/gitlab-org/gitlab-ce/pipelines/133/cancel",
"created_at": "2017-05-24T14:46:24.648Z",
"updated_at": "2017-05-24T14:48:59.673Z"
},
{
"id": 130,
"active": true,
"path": "/gitlab-org/gitlab-ce/pipelines/130",
"project": {
"name": "GitLabCE"
},
"details": {
"status": {
"icon": "icon_status_running",
"text": "running",
"label": "running",
"group": "running",
"has_details": true,
"details_path": "/gitlab-org/gitlab-ce/pipelines/130",
"favicon": "/assets/ci_favicons/dev/favicon_status_running-c3ad2fc53ea6079c174e5b6c1351ff349e99ec3af5a5622fb77b0fe53ea279c1.ico"
}
},
"flags": {
"latest": false,
"triggered": false,
"stuck": false,
"yaml_errors": false,
"retryable": true,
"cancelable": true
},
"ref": {
"name": "crowd",
"path": "/gitlab-org/gitlab-ce/commits/crowd",
"tag": false,
"branch": true
},
"commit": {
"id": "6d7ced4a2311eeff037c5575cca1868a6d3f586f",
"short_id": "6d7ced4a",
"title": "Whitespace fixes to patch",
"created_at": "2013-10-08T13:53:22.000-05:00",
"parent_ids": [
"1875141a963a4238bda29011d8f7105839485253"
],
"message": "Whitespace fixes to patch\n",
"author_name": "Dale Hamel",
"author_email": "dale.hamel@srvthe.net",
"authored_date": "2013-10-08T13:53:22.000-05:00",
"committer_name": "Dale Hamel",
"committer_email": "dale.hamel@invenia.ca",
"committed_date": "2013-10-08T13:53:22.000-05:00",
"author_gravatar_url": "http://www.gravatar.com/avatar/cd08930e69fa5ad1a669206e7bafe476?s=80&d=identicon",
"commit_url": "http://localhost:3000/gitlab-org/gitlab-ce/commit/6d7ced4a2311eeff037c5575cca1868a6d3f586f",
"commit_path": "/gitlab-org/gitlab-ce/commit/6d7ced4a2311eeff037c5575cca1868a6d3f586f"
},
"retry_path": "/gitlab-org/gitlab-ce/pipelines/130/retry",
"cancel_path": "/gitlab-org/gitlab-ce/pipelines/130/cancel",
"created_at": "2017-05-24T14:46:24.630Z",
"updated_at": "2017-05-24T14:49:45.091Z"
}
]
};
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